diff --git a/models/db/driver_postgresschema.go b/models/db/driver_postgresschema.go index ad2b5abc04..616712fb2a 100644 --- a/models/db/driver_postgresschema.go +++ b/models/db/driver_postgresschema.go @@ -4,8 +4,10 @@ package db import ( + "context" "database/sql" "database/sql/driver" + "errors" "sync" "gitea.dev/modules/setting" @@ -14,61 +16,34 @@ import ( "xorm.io/xorm/dialects" ) -var registerOnce sync.Once +type postgresSchemaDriver struct{} -func registerPostgresSchemaDriver() { - registerOnce.Do(func() { - sql.Register(sqlDriverPostgresSchema, &postgresSchemaDriver{}) - dialects.RegisterDriver(sqlDriverPostgresSchema, dialects.QueryDriver("postgres")) - }) -} +var registerPostgresSchemaDriver = sync.OnceFunc(func() { + sql.Register(sqlDriverPostgresSchema, &postgresSchemaDriver{}) + dialects.RegisterDriver(sqlDriverPostgresSchema, dialects.QueryDriver("postgres")) +}) -type postgresSchemaDriver struct { - pq.Driver -} - -// Open opens a new connection to the database. name is a connection string. -// This function opens the postgres connection in the default manner but immediately -// runs set_config to set the search_path appropriately -func (d *postgresSchemaDriver) Open(name string) (driver.Conn, error) { - conn, err := d.Driver.Open(name) +// Open opens the postgres connection in the default manner with default schema support. +// It immediately runs "set_config" to set the search_path appropriately. +func (*postgresSchemaDriver) Open(connStr string) (driver.Conn, error) { + conn, err := pq.Driver{}.Open(connStr) if err != nil { - return conn, err + return nil, err } - schemaValue, _ := driver.String.ConvertValue(setting.Database.Schema) - // golangci lint is incorrect here - there is no benefit to using driver.ExecerContext here - // and in any case pq does not implement it - if execer, ok := conn.(driver.Execer); ok { //nolint:staticcheck // see above - _, err := execer.Exec(`SELECT set_config( + connExec, ok := conn.(driver.ExecerContext) + if !ok { + return nil, errors.New("postgres driver does not implement ExecerContext interface") + } + _, err = connExec.ExecContext(context.Background(), `SELECT set_config( 'search_path', $1 || ',' || current_setting('search_path'), - false)`, []driver.Value{schemaValue}) - if err != nil { - _ = conn.Close() - return nil, err - } - return conn, nil - } - - stmt, err := conn.Prepare(`SELECT set_config( - 'search_path', - $1 || ',' || current_setting('search_path'), - false)`) + false)`, + []driver.NamedValue{{Ordinal: 1, Value: setting.Database.Schema}}, + ) if err != nil { _ = conn.Close() return nil, err } - defer stmt.Close() - - // driver.String.ConvertValue will never return err for string - - // golangci lint is incorrect here - there is no benefit to using stmt.ExecWithContext here - _, err = stmt.Exec([]driver.Value{schemaValue}) //nolint:staticcheck // see above - if err != nil { - _ = conn.Close() - return nil, err - } - return conn, nil }