code.gitea.io/gitea@v1.22.3/models/db/sql_postgres_with_schema.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package db
     5  
     6  import (
     7  	"database/sql"
     8  	"database/sql/driver"
     9  	"sync"
    10  
    11  	"code.gitea.io/gitea/modules/setting"
    12  
    13  	"github.com/lib/pq"
    14  	"xorm.io/xorm/dialects"
    15  )
    16  
    17  var registerOnce sync.Once
    18  
    19  func registerPostgresSchemaDriver() {
    20  	registerOnce.Do(func() {
    21  		sql.Register("postgresschema", &postgresSchemaDriver{})
    22  		dialects.RegisterDriver("postgresschema", dialects.QueryDriver("postgres"))
    23  	})
    24  }
    25  
    26  type postgresSchemaDriver struct {
    27  	pq.Driver
    28  }
    29  
    30  // Open opens a new connection to the database. name is a connection string.
    31  // This function opens the postgres connection in the default manner but immediately
    32  // runs set_config to set the search_path appropriately
    33  func (d *postgresSchemaDriver) Open(name string) (driver.Conn, error) {
    34  	conn, err := d.Driver.Open(name)
    35  	if err != nil {
    36  		return conn, err
    37  	}
    38  	schemaValue, _ := driver.String.ConvertValue(setting.Database.Schema)
    39  
    40  	// golangci lint is incorrect here - there is no benefit to using driver.ExecerContext here
    41  	// and in any case pq does not implement it
    42  	if execer, ok := conn.(driver.Execer); ok { //nolint
    43  		_, err := execer.Exec(`SELECT set_config(
    44  			'search_path',
    45  			$1 || ',' || current_setting('search_path'),
    46  			false)`, []driver.Value{schemaValue})
    47  		if err != nil {
    48  			_ = conn.Close()
    49  			return nil, err
    50  		}
    51  		return conn, nil
    52  	}
    53  
    54  	stmt, err := conn.Prepare(`SELECT set_config(
    55  		'search_path',
    56  		$1 || ',' || current_setting('search_path'),
    57  		false)`)
    58  	if err != nil {
    59  		_ = conn.Close()
    60  		return nil, err
    61  	}
    62  	defer stmt.Close()
    63  
    64  	// driver.String.ConvertValue will never return err for string
    65  
    66  	// golangci lint is incorrect here - there is no benefit to using stmt.ExecWithContext here
    67  	_, err = stmt.Exec([]driver.Value{schemaValue}) //nolint
    68  	if err != nil {
    69  		_ = conn.Close()
    70  		return nil, err
    71  	}
    72  
    73  	return conn, nil
    74  }