mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 03:18:24 +00:00 
			
		
		
		
	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:
		| @@ -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 New Issue
	
	Block a user