package pg
import (
)
type Options struct {
Network string
Addr string
Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
OnConnect func(ctx context.Context, cn *Conn) error
User string
Password string
Database string
ApplicationName string
TLSConfig *tls.Config
DialTimeout time.Duration
ReadTimeout time.Duration
WriteTimeout time.Duration
MaxRetries int
RetryStatementTimeout bool
MinRetryBackoff time.Duration
MaxRetryBackoff time.Duration
PoolSize int
MinIdleConns int
MaxConnAge time.Duration
PoolTimeout time.Duration
IdleTimeout time.Duration
IdleCheckFrequency time.Duration
}
func ( *Options) () {
if .Network == "" {
.Network = "tcp"
}
if .Addr == "" {
switch .Network {
case "tcp":
:= env("PGHOST", "localhost")
:= env("PGPORT", "5432")
.Addr = fmt.Sprintf("%s:%s", , )
case "unix":
.Addr = "/var/run/postgresql/.s.PGSQL.5432"
}
}
if .DialTimeout == 0 {
.DialTimeout = 5 * time.Second
}
if .Dialer == nil {
.Dialer = func( context.Context, , string) (net.Conn, error) {
:= &net.Dialer{
Timeout: .DialTimeout,
KeepAlive: 5 * time.Minute,
}
return .DialContext(, , )
}
}
if .User == "" {
.User = env("PGUSER", "postgres")
}
if .Database == "" {
.Database = env("PGDATABASE", "postgres")
}
if .PoolSize == 0 {
.PoolSize = 10 * runtime.NumCPU()
}
if .PoolTimeout == 0 {
if .ReadTimeout != 0 {
.PoolTimeout = .ReadTimeout + time.Second
} else {
.PoolTimeout = 30 * time.Second
}
}
if .IdleTimeout == 0 {
.IdleTimeout = 5 * time.Minute
}
if .IdleCheckFrequency == 0 {
.IdleCheckFrequency = time.Minute
}
switch .MinRetryBackoff {
case -1:
.MinRetryBackoff = 0
case 0:
.MinRetryBackoff = 250 * time.Millisecond
}
switch .MaxRetryBackoff {
case -1:
.MaxRetryBackoff = 0
case 0:
.MaxRetryBackoff = 4 * time.Second
}
}
func (, string) string {
:= os.Getenv()
if != "" {
return
}
return
}
func ( string) (*Options, error) {
, := url.Parse()
if != nil {
return nil,
}
if .Scheme != "postgres" && .Scheme != "postgresql" {
return nil, errors.New("pg: invalid scheme: " + .Scheme)
}
:= &Options{
Addr: .Host,
}
if !strings.Contains(.Addr, ":") {
.Addr += ":5432"
}
if .User != nil {
.User = .User.Username()
if , := .User.Password(); {
.Password =
}
}
if .User == "" {
.User = "postgres"
}
if len(strings.Trim(.Path, "/")) > 0 {
.Database = .Path[1:]
} else {
return nil, errors.New("pg: database name not provided")
}
, := url.ParseQuery(.RawQuery)
if != nil {
return nil,
}
if , := ["sslmode"]; && len() > 0 {
switch [0] {
case "verify-ca", "verify-full":
.TLSConfig = &tls.Config{}
case "allow", "prefer", "require":
.TLSConfig = &tls.Config{InsecureSkipVerify: true}
case "disable":
.TLSConfig = nil
default:
return nil, fmt.Errorf("pg: sslmode '%v' is not supported", [0])
}
} else {
.TLSConfig = &tls.Config{InsecureSkipVerify: true}
}
delete(, "sslmode")
if , := ["application_name"]; && len() > 0 {
.ApplicationName = [0]
}
delete(, "application_name")
if , := ["connect_timeout"]; && len() > 0 {
, := strconv.Atoi([0])
if != nil {
return nil, fmt.Errorf("pg: cannot parse connect_timeout option as int")
}
.DialTimeout = time.Second * time.Duration()
}
delete(, "connect_timeout")
if len() > 0 {
return nil, errors.New("pg: options other than 'sslmode', 'application_name' and 'connect_timeout' are not supported")
}
return , nil
}
func ( *Options) () func(context.Context) (net.Conn, error) {
return func( context.Context) (net.Conn, error) {
return .Dialer(, .Network, .Addr)
}
}
func ( *Options) *pool.ConnPool {
return pool.NewConnPool(&pool.Options{
Dialer: .getDialer(),
OnClose: terminateConn,
PoolSize: .PoolSize,
MinIdleConns: .MinIdleConns,
MaxConnAge: .MaxConnAge,
PoolTimeout: .PoolTimeout,
IdleTimeout: .IdleTimeout,
IdleCheckFrequency: .IdleCheckFrequency,
})
}