Backport #14131 Unfortunately every connection to postgres requires that the search path is set appropriately. This PR shadows the postgres driver to ensure that as soon as a connection is open, the search_path is set appropriately. Fix #14088 Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
parent
7a0a133d7c
commit
2fd708a397
2 changed files with 85 additions and 11 deletions
|
@ -145,7 +145,16 @@ func getEngine() (*xorm.Engine, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
engine, err := xorm.NewEngine(setting.Database.Type, connStr)
|
var engine *xorm.Engine
|
||||||
|
|
||||||
|
if setting.Database.UsePostgreSQL && len(setting.Database.Schema) > 0 {
|
||||||
|
// OK whilst we sort out our schema issues - create a schema aware postgres
|
||||||
|
registerPostgresSchemaDriver()
|
||||||
|
engine, err = xorm.NewEngine("postgresschema", connStr)
|
||||||
|
} else {
|
||||||
|
engine, err = xorm.NewEngine(setting.Database.Type, connStr)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -155,16 +164,6 @@ func getEngine() (*xorm.Engine, error) {
|
||||||
engine.Dialect().SetParams(map[string]string{"DEFAULT_VARCHAR": "nvarchar"})
|
engine.Dialect().SetParams(map[string]string{"DEFAULT_VARCHAR": "nvarchar"})
|
||||||
}
|
}
|
||||||
engine.SetSchema(setting.Database.Schema)
|
engine.SetSchema(setting.Database.Schema)
|
||||||
if setting.Database.UsePostgreSQL && len(setting.Database.Schema) > 0 {
|
|
||||||
// Add the schema to the search path
|
|
||||||
if _, err := engine.Exec(`SELECT set_config(
|
|
||||||
'search_path',
|
|
||||||
? || ',' || current_setting('search_path'),
|
|
||||||
false)`,
|
|
||||||
setting.Database.Schema); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return engine, nil
|
return engine, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
75
models/sql_postgres_with_schema.go
Normal file
75
models/sql_postgres_with_schema.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
|
"xorm.io/xorm/dialects"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registerOnce sync.Once
|
||||||
|
|
||||||
|
func registerPostgresSchemaDriver() {
|
||||||
|
registerOnce.Do(func() {
|
||||||
|
sql.Register("postgresschema", &postgresSchemaDriver{})
|
||||||
|
dialects.RegisterDriver("postgresschema", 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)
|
||||||
|
if err != nil {
|
||||||
|
return conn, 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
|
||||||
|
_, err := execer.Exec(`SELECT set_config(
|
||||||
|
'search_path',
|
||||||
|
$1 || ',' || current_setting('search_path'),
|
||||||
|
false)`, []driver.Value{schemaValue}) //nolint
|
||||||
|
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)`)
|
||||||
|
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
|
||||||
|
if err != nil {
|
||||||
|
_ = conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
Reference in a new issue