2019-03-27 19:15:23 +08:00
package pq
import (
"context"
"database/sql/driver"
2019-04-15 16:14:31 -04:00
"errors"
"fmt"
"os"
"strings"
2019-03-27 19:15:23 +08:00
)
// Connector represents a fixed configuration for the pq driver with a given
// name. Connector satisfies the database/sql/driver Connector interface and
// can be used to create any number of DB Conn's via the database/sql OpenDB
// function.
//
// See https://golang.org/pkg/database/sql/driver/#Connector.
// See https://golang.org/pkg/database/sql/#OpenDB.
2019-04-15 16:14:31 -04:00
type Connector struct {
opts values
dialer Dialer
2019-03-27 19:15:23 +08:00
}
// Connect returns a connection to the database using the fixed configuration
// of this Connector. Context is not used.
2019-04-15 16:14:31 -04:00
func ( c * Connector ) Connect ( ctx context . Context ) ( driver . Conn , error ) {
return c . open ( ctx )
2019-03-27 19:15:23 +08:00
}
2020-09-18 15:38:46 +01:00
// Driver returns the underlying driver of this Connector.
2019-04-15 16:14:31 -04:00
func ( c * Connector ) Driver ( ) driver . Driver {
2019-03-27 19:15:23 +08:00
return & Driver { }
}
// NewConnector returns a connector for the pq driver in a fixed configuration
2019-04-15 16:14:31 -04:00
// with the given dsn. The returned connector can be used to create any number
2019-03-27 19:15:23 +08:00
// of equivalent Conn's. The returned connector is intended to be used with
// database/sql.OpenDB.
//
// See https://golang.org/pkg/database/sql/driver/#Connector.
// See https://golang.org/pkg/database/sql/#OpenDB.
2019-04-15 16:14:31 -04:00
func NewConnector ( dsn string ) ( * Connector , error ) {
var err error
o := make ( values )
// A number of defaults are applied here, in this order:
//
// * Very low precedence defaults applied in every situation
// * Environment variables
// * Explicitly passed connection information
o [ "host" ] = "localhost"
o [ "port" ] = "5432"
// N.B.: Extra float digits should be set to 3, but that breaks
// Postgres 8.4 and older, where the max is 2.
o [ "extra_float_digits" ] = "2"
for k , v := range parseEnviron ( os . Environ ( ) ) {
o [ k ] = v
}
if strings . HasPrefix ( dsn , "postgres://" ) || strings . HasPrefix ( dsn , "postgresql://" ) {
dsn , err = ParseURL ( dsn )
if err != nil {
return nil , err
}
}
if err := parseOpts ( dsn , o ) ; err != nil {
return nil , err
}
// Use the "fallback" application name if necessary
if fallback , ok := o [ "fallback_application_name" ] ; ok {
if _ , ok := o [ "application_name" ] ; ! ok {
o [ "application_name" ] = fallback
}
}
// We can't work with any client_encoding other than UTF-8 currently.
// However, we have historically allowed the user to set it to UTF-8
// explicitly, and there's no reason to break such programs, so allow that.
// Note that the "options" setting could also set client_encoding, but
// parsing its value is not worth it. Instead, we always explicitly send
// client_encoding as a separate run-time parameter, which should override
// anything set in options.
if enc , ok := o [ "client_encoding" ] ; ok && ! isUTF8 ( enc ) {
return nil , errors . New ( "client_encoding must be absent or 'UTF8'" )
}
o [ "client_encoding" ] = "UTF8"
// DateStyle needs a similar treatment.
if datestyle , ok := o [ "datestyle" ] ; ok {
if datestyle != "ISO, MDY" {
return nil , fmt . Errorf ( "setting datestyle must be absent or %v; got %v" , "ISO, MDY" , datestyle )
}
} else {
o [ "datestyle" ] = "ISO, MDY"
}
// If a user is not provided by any other means, the last
// resort is to use the current operating system provided user
// name.
if _ , ok := o [ "user" ] ; ! ok {
u , err := userCurrent ( )
if err != nil {
return nil , err
}
o [ "user" ] = u
}
2020-06-16 07:57:38 -04:00
// SSL is not necessary or supported over UNIX domain sockets
if network , _ := network ( o ) ; network == "unix" {
o [ "sslmode" ] = "disable"
}
2019-04-15 16:14:31 -04:00
return & Connector { opts : o , dialer : defaultDialer { } } , nil
2019-03-27 19:15:23 +08:00
}