소스 검색

database: add PostgreSQL custom schema support (#6695)

Co-authored-by: Homura37 <[email protected]>
Co-authored-by: Homura <[email protected]>
Co-authored-by: Joe Chen <[email protected]>
zvrh 3 년 전
부모
커밋
a9be4de5a5

+ 1 - 0
CHANGELOG.md

@@ -9,6 +9,7 @@ All notable changes to Gogs are documented in this file.
 - An unlisted option is added when create or migrate a repository. Unlisted repositories are public but not being listed for users without direct access in the UI. [#5733](https://github.com/gogs/gogs/issues/5733)
 - New configuration option `[git.timeout] DIFF` for customizing operation timeout of `git diff`. [#6315](https://github.com/gogs/gogs/issues/6315)
 - New configuration option `[server] SSH_SERVER_MACS` for setting list of accepted MACs for connections to builtin SSH server. [#6434](https://github.com/gogs/gogs/issues/6434)
+- Support specifying custom schema for PostgreSQL. [#6695](https://github.com/gogs/gogs/pull/6695)
 - New languages support: Mongolian. [#6510](https://github.com/gogs/gogs/pull/6510)
 
 ### Changed

+ 2 - 0
conf/app.ini

@@ -144,6 +144,8 @@ HOST = 127.0.0.1:5432
 NAME = gogs
 USER = gogs
 PASSWORD =
+; For "postgres" only
+SCHEMA = public
 ; For "postgres" only, either "disable", "require" or "verify-full".
 SSL_MODE = disable
 ; For "sqlite3" only, make sure to use absolute path.

+ 3 - 0
conf/locale/locale_en-US.ini

@@ -58,6 +58,7 @@ host = Host
 user = User
 password = Password
 db_name = Database Name
+db_schema = Schema
 db_helper = Please use INNODB engine with utf8_general_ci charset for MySQL.
 ssl_mode = SSL Mode
 path = Path
@@ -1229,6 +1230,8 @@ config.db_config = Database configuration
 config.db.type = Type
 config.db.host = Host
 config.db.name = Name
+config.db.schema = Schema
+config.db.schema_helper = (for "postgres" only)
 config.db.user = User
 config.db.ssl_mode = SSL mode
 config.db.ssl_mode_helper = (for "postgres" only)

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 3 - 3
internal/assets/conf/conf_gen.go


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2 - 2
internal/assets/templates/templates_gen.go


+ 1 - 0
internal/conf/static.go

@@ -368,6 +368,7 @@ type DatabaseOpts struct {
 	Type         string
 	Host         string
 	Name         string
+	Schema       string
 	User         string
 	Password     string
 	SSLMode      string `ini:"SSL_MODE"`

+ 1 - 0
internal/conf/testdata/TestInit.golden.ini

@@ -60,6 +60,7 @@ MAX_FILES=5
 TYPE=sqlite
 HOST=127.0.0.1:5432
 NAME=gogs
+SCHEMA=public
 USER=gogs
 PASSWORD=12345678
 SSL_MODE=disable

+ 2 - 8
internal/db/db.go

@@ -6,7 +6,6 @@ package db
 
 import (
 	"fmt"
-	"net/url"
 	"path/filepath"
 	"strings"
 	"time"
@@ -74,13 +73,8 @@ func parseDSN(opts conf.DatabaseOpts) (dsn string, err error) {
 
 	case "postgres":
 		host, port := parsePostgreSQLHostPort(opts.Host)
-		if host[0] == '/' { // looks like a unix socket
-			dsn = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
-				url.QueryEscape(opts.User), url.QueryEscape(opts.Password), port, opts.Name, concate, opts.SSLMode, host)
-		} else {
-			dsn = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
-				url.QueryEscape(opts.User), url.QueryEscape(opts.Password), host, port, opts.Name, concate, opts.SSLMode)
-		}
+		dsn = fmt.Sprintf("user='%s' password='%s' host='%s' port='%s' dbname='%s' sslmode='%s' search_path='%s'",
+			opts.User, opts.Password, host, port, opts.Name, opts.SSLMode, opts.Schema)
 
 	case "mssql":
 		host, port := parseMSSQLHostPort(opts.Host)

+ 4 - 2
internal/db/db_test.go

@@ -96,11 +96,12 @@ func Test_parseDSN(t *testing.T) {
 				Type:     "postgres",
 				Host:     "/tmp/pg.sock",
 				Name:     "gogs",
+				Schema:   "test",
 				User:     "gogs@local",
 				Password: "pa$$word",
 				SSLMode:  "disable",
 			},
-			expDSN: "postgres://gogs%40local:pa%24%24word@:5432/gogs?sslmode=disable&host=/tmp/pg.sock",
+			expDSN: "user='gogs@local' password='pa$$word' host='/tmp/pg.sock' port='5432' dbname='gogs' sslmode='disable' search_path='test'",
 		},
 		{
 			name: "postgres: tcp",
@@ -108,11 +109,12 @@ func Test_parseDSN(t *testing.T) {
 				Type:     "postgres",
 				Host:     "127.0.0.1",
 				Name:     "gogs",
+				Schema:   "test",
 				User:     "gogs@local",
 				Password: "pa$$word",
 				SSLMode:  "disable",
 			},
-			expDSN: "postgres://gogs%40local:pa%24%[email protected]:5432/gogs?sslmode=disable",
+			expDSN: "user='gogs@local' password='pa$$word' host='127.0.0.1' port='5432' dbname='gogs' sslmode='disable' search_path='test'",
 		},
 
 		{

+ 10 - 8
internal/db/models.go

@@ -7,7 +7,6 @@ package db
 import (
 	"database/sql"
 	"fmt"
-	"net/url"
 	"os"
 	"path"
 	"path/filepath"
@@ -90,13 +89,8 @@ func getEngine() (*xorm.Engine, error) {
 	case "postgres":
 		conf.UsePostgreSQL = true
 		host, port := parsePostgreSQLHostPort(conf.Database.Host)
-		if host[0] == '/' { // looks like a unix socket
-			connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
-				url.QueryEscape(conf.Database.User), url.QueryEscape(conf.Database.Password), port, conf.Database.Name, Param, conf.Database.SSLMode, host)
-		} else {
-			connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
-				url.QueryEscape(conf.Database.User), url.QueryEscape(conf.Database.Password), host, port, conf.Database.Name, Param, conf.Database.SSLMode)
-		}
+		connStr = fmt.Sprintf("user='%s' password='%s' host='%s' port='%s' dbname='%s' sslmode='%s' search_path='%s'",
+			conf.Database.User, conf.Database.Password, host, port, conf.Database.Name, conf.Database.SSLMode, conf.Database.Schema)
 		driver = "pgx"
 
 	case "mssql":
@@ -123,6 +117,10 @@ func NewTestEngine() error {
 		return fmt.Errorf("connect to database: %v", err)
 	}
 
+	if conf.UsePostgreSQL {
+		x.SetSchema(conf.Database.Schema)
+	}
+
 	x.SetMapper(core.GonicMapper{})
 	return x.StoreEngine("InnoDB").Sync2(legacyTables...)
 }
@@ -134,6 +132,10 @@ func SetEngine() (*gorm.DB, error) {
 		return nil, fmt.Errorf("connect to database: %v", err)
 	}
 
+	if conf.UsePostgreSQL {
+		x.SetSchema(conf.Database.Schema)
+	}
+
 	x.SetMapper(core.GonicMapper{})
 
 	var logPath string

+ 1 - 0
internal/form/user.go

@@ -17,6 +17,7 @@ type Install struct {
 	DbUser   string
 	DbPasswd string
 	DbName   string
+	DbSchema string
 	SSLMode  string
 	DbPath   string
 

+ 3 - 0
internal/route/install.go

@@ -132,6 +132,7 @@ func Install(c *context.Context) {
 	f.DbHost = conf.Database.Host
 	f.DbUser = conf.Database.User
 	f.DbName = conf.Database.Name
+	f.DbSchema = conf.Database.Schema
 	f.DbPath = conf.Database.Path
 
 	c.Data["CurDbOption"] = "PostgreSQL"
@@ -216,6 +217,7 @@ func InstallPost(c *context.Context, f form.Install) {
 	conf.Database.User = f.DbUser
 	conf.Database.Password = f.DbPasswd
 	conf.Database.Name = f.DbName
+	conf.Database.Schema = f.DbSchema
 	conf.Database.SSLMode = f.SSLMode
 	conf.Database.Path = f.DbPath
 
@@ -311,6 +313,7 @@ func InstallPost(c *context.Context, f form.Install) {
 	cfg.Section("database").Key("TYPE").SetValue(conf.Database.Type)
 	cfg.Section("database").Key("HOST").SetValue(conf.Database.Host)
 	cfg.Section("database").Key("NAME").SetValue(conf.Database.Name)
+	cfg.Section("database").Key("SCHEMA").SetValue(conf.Database.Schema)
 	cfg.Section("database").Key("USER").SetValue(conf.Database.User)
 	cfg.Section("database").Key("PASSWORD").SetValue(conf.Database.Password)
 	cfg.Section("database").Key("SSL_MODE").SetValue(conf.Database.SSLMode)

+ 2 - 0
templates/admin/config.tmpl

@@ -174,6 +174,8 @@
 						<dd>{{.Database.Host}}</dd>
 						<dt>{{.i18n.Tr "admin.config.db.name"}}</dt>
 						<dd>{{.Database.Name}}</dd>
+						<dt>{{.i18n.Tr "admin.config.db.schema"}}</dt>
+						<dd>{{.Database.Schema}} {{.i18n.Tr "admin.config.db.schema_helper"}}</dd>
 						<dt>{{.i18n.Tr "admin.config.db.user"}}</dt>
 						<dd>{{.Database.User}}</dd>
 						<dt>{{.i18n.Tr "admin.config.db.ssl_mode"}}</dt>

+ 4 - 0
templates/install.tmpl

@@ -49,6 +49,10 @@
 					</div>
 
 					<div id="pgsql_settings" class="{{if not (eq .CurDbOption "PostgreSQL")}}hide{{end}}">
+						<div class="inline required field">
+							<label for="db_schema">{{.i18n.Tr "install.db_schema"}}</label>
+							<input id="db_schema" name="db_schema" value="{{.db_schema}}">
+						</div>
 						<div class="inline required field">
 							<label>{{.i18n.Tr "install.ssl_mode"}}</label>
 							<div class="ui selection database type dropdown">

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.