@@ -15,11 +15,13 @@ import (
1515 "github.com/jackc/puddle/v2"
1616)
1717
18- var defaultMaxConns = int32 (4 )
19- var defaultMinConns = int32 (0 )
20- var defaultMaxConnLifetime = time .Hour
21- var defaultMaxConnIdleTime = time .Minute * 30
22- var defaultHealthCheckPeriod = time .Minute
18+ var (
19+ defaultMaxConns = int32 (4 )
20+ defaultMinConns = int32 (0 )
21+ defaultMaxConnLifetime = time .Hour
22+ defaultMaxConnIdleTime = time .Minute * 30
23+ defaultHealthCheckPeriod = time .Minute
24+ )
2325
2426type connResource struct {
2527 conn * pgx.Conn
@@ -100,6 +102,11 @@ type Pool struct {
100102
101103 closeOnce sync.Once
102104 closeChan chan struct {}
105+
106+ autoLoadTypes []string
107+ reuseTypeMap bool
108+ autoLoadMutex * sync.Mutex
109+ autoLoadTypeInfos []* pgx.TypeInfo
103110}
104111
105112// Config is the configuration struct for creating a pool. It must be created by [ParseConfig] and then it can be
@@ -147,6 +154,15 @@ type Config struct {
147154 // HealthCheckPeriod is the duration between checks of the health of idle connections.
148155 HealthCheckPeriod time.Duration
149156
157+ // AutoLoadTypes is a list of user-defined types which should automatically be loaded
158+ // as each new connection is created. This will also load any related types, directly
159+ // or indirectly required to handle these types.
160+ AutoLoadTypes []string
161+
162+ // ReuseTypeMaps, if enabled, will reuse the typemap information being used by AutoLoadTypes.
163+ // This removes the need to query the database each time a new connection is created.
164+ ReuseTypeMaps bool
165+
150166 createdByParseConfig bool // Used to enforce created by ParseConfig rule.
151167}
152168
@@ -185,6 +201,8 @@ func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
185201 config : config ,
186202 beforeConnect : config .BeforeConnect ,
187203 afterConnect : config .AfterConnect ,
204+ autoLoadTypes : config .AutoLoadTypes ,
205+ reuseTypeMap : config .ReuseTypeMaps ,
188206 beforeAcquire : config .BeforeAcquire ,
189207 afterRelease : config .AfterRelease ,
190208 beforeClose : config .BeforeClose ,
@@ -196,6 +214,7 @@ func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
196214 healthCheckPeriod : config .HealthCheckPeriod ,
197215 healthCheckChan : make (chan struct {}, 1 ),
198216 closeChan : make (chan struct {}),
217+ autoLoadMutex : new (sync.Mutex ),
199218 }
200219
201220 if t , ok := config .ConnConfig .Tracer .(AcquireTracer ); ok {
@@ -237,6 +256,19 @@ func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
237256 }
238257 }
239258
259+ if len (p .autoLoadTypes ) > 0 {
260+ types , err := p .loadTypes (ctx , conn , p .autoLoadTypes )
261+ if err != nil {
262+ conn .Close (ctx )
263+ panic (err )
264+ }
265+ if err = conn .RegisterTypes (types , conn .TypeMap ()); err != nil {
266+ conn .Close (ctx )
267+
268+ panic (err )
269+ }
270+ }
271+
240272 jitterSecs := rand .Float64 () * config .MaxConnLifetimeJitter .Seconds ()
241273 maxAgeTime := time .Now ().Add (config .MaxConnLifetime ).Add (time .Duration (jitterSecs ) * time .Second )
242274
@@ -388,6 +420,27 @@ func (p *Pool) Close() {
388420 })
389421}
390422
423+ // loadTypes is used internally to autoload the custom types for a connection,
424+ // potentially reusing previously-loaded typemap information.
425+ func (p * Pool ) loadTypes (ctx context.Context , conn * pgx.Conn , typeNames []string ) ([]* pgx.TypeInfo , error ) {
426+ if p .reuseTypeMap {
427+ p .autoLoadMutex .Lock ()
428+ defer p .autoLoadMutex .Unlock ()
429+ if p .autoLoadTypeInfos != nil {
430+ return p .autoLoadTypeInfos , nil
431+ }
432+ types , err := conn .LoadTypes (ctx , typeNames )
433+ if err != nil {
434+ return nil , err
435+ }
436+ p .autoLoadTypeInfos = types
437+ return types , err
438+ }
439+ // Avoid needing to acquire the mutex and allow connections to initialise in parallel
440+ // if we have chosen to not reuse the type mapping
441+ return conn .LoadTypes (ctx , typeNames )
442+ }
443+
391444func (p * Pool ) isExpired (res * puddle.Resource [* connResource ]) bool {
392445 return time .Now ().After (res .Value ().maxAgeTime )
393446}
@@ -482,7 +535,6 @@ func (p *Pool) checkMinConns() error {
482535func (p * Pool ) createIdleResources (parentCtx context.Context , targetResources int ) error {
483536 ctx , cancel := context .WithCancel (parentCtx )
484537 defer cancel ()
485-
486538 errs := make (chan error , targetResources )
487539
488540 for i := 0 ; i < targetResources ; i ++ {
@@ -495,7 +547,6 @@ func (p *Pool) createIdleResources(parentCtx context.Context, targetResources in
495547 errs <- err
496548 }()
497549 }
498-
499550 var firstError error
500551 for i := 0 ; i < targetResources ; i ++ {
501552 err := <- errs
0 commit comments