You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.4 KiB

  1. package pq
  2. import (
  3. "context"
  4. "database/sql/driver"
  5. "errors"
  6. "fmt"
  7. "os"
  8. "strings"
  9. )
  10. // Connector represents a fixed configuration for the pq driver with a given
  11. // name. Connector satisfies the database/sql/driver Connector interface and
  12. // can be used to create any number of DB Conn's via the database/sql OpenDB
  13. // function.
  14. //
  15. // See https://golang.org/pkg/database/sql/driver/#Connector.
  16. // See https://golang.org/pkg/database/sql/#OpenDB.
  17. type Connector struct {
  18. opts values
  19. dialer Dialer
  20. }
  21. // Connect returns a connection to the database using the fixed configuration
  22. // of this Connector. Context is not used.
  23. func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) {
  24. return c.open(ctx)
  25. }
  26. // Driver returns the underlying driver of this Connector.
  27. func (c *Connector) Driver() driver.Driver {
  28. return &Driver{}
  29. }
  30. // NewConnector returns a connector for the pq driver in a fixed configuration
  31. // with the given dsn. The returned connector can be used to create any number
  32. // of equivalent Conn's. The returned connector is intended to be used with
  33. // database/sql.OpenDB.
  34. //
  35. // See https://golang.org/pkg/database/sql/driver/#Connector.
  36. // See https://golang.org/pkg/database/sql/#OpenDB.
  37. func NewConnector(dsn string) (*Connector, error) {
  38. var err error
  39. o := make(values)
  40. // A number of defaults are applied here, in this order:
  41. //
  42. // * Very low precedence defaults applied in every situation
  43. // * Environment variables
  44. // * Explicitly passed connection information
  45. o["host"] = "localhost"
  46. o["port"] = "5432"
  47. // N.B.: Extra float digits should be set to 3, but that breaks
  48. // Postgres 8.4 and older, where the max is 2.
  49. o["extra_float_digits"] = "2"
  50. for k, v := range parseEnviron(os.Environ()) {
  51. o[k] = v
  52. }
  53. if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") {
  54. dsn, err = ParseURL(dsn)
  55. if err != nil {
  56. return nil, err
  57. }
  58. }
  59. if err := parseOpts(dsn, o); err != nil {
  60. return nil, err
  61. }
  62. // Use the "fallback" application name if necessary
  63. if fallback, ok := o["fallback_application_name"]; ok {
  64. if _, ok := o["application_name"]; !ok {
  65. o["application_name"] = fallback
  66. }
  67. }
  68. // We can't work with any client_encoding other than UTF-8 currently.
  69. // However, we have historically allowed the user to set it to UTF-8
  70. // explicitly, and there's no reason to break such programs, so allow that.
  71. // Note that the "options" setting could also set client_encoding, but
  72. // parsing its value is not worth it. Instead, we always explicitly send
  73. // client_encoding as a separate run-time parameter, which should override
  74. // anything set in options.
  75. if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) {
  76. return nil, errors.New("client_encoding must be absent or 'UTF8'")
  77. }
  78. o["client_encoding"] = "UTF8"
  79. // DateStyle needs a similar treatment.
  80. if datestyle, ok := o["datestyle"]; ok {
  81. if datestyle != "ISO, MDY" {
  82. return nil, fmt.Errorf("setting datestyle must be absent or %v; got %v", "ISO, MDY", datestyle)
  83. }
  84. } else {
  85. o["datestyle"] = "ISO, MDY"
  86. }
  87. // If a user is not provided by any other means, the last
  88. // resort is to use the current operating system provided user
  89. // name.
  90. if _, ok := o["user"]; !ok {
  91. u, err := userCurrent()
  92. if err != nil {
  93. return nil, err
  94. }
  95. o["user"] = u
  96. }
  97. // SSL is not necessary or supported over UNIX domain sockets
  98. if network, _ := network(o); network == "unix" {
  99. o["sslmode"] = "disable"
  100. }
  101. return &Connector{opts: o, dialer: defaultDialer{}}, nil
  102. }