Skip to content

Commit bd20c37

Browse files
authored
Add SetSchema for engine (go-xorm#876)
* add SetSchema for engine * fix user * fix postgres with schema * fix test * fix test * fix test * fix tablename * refactor tableName * fix schema support * improve the interface of EngineInterface
1 parent 0b84179 commit bd20c37

29 files changed

+373
-592
lines changed

circle.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ database:
1717
- createdb -p 5432 -e -U postgres xorm_test1
1818
- createdb -p 5432 -e -U postgres xorm_test2
1919
- createdb -p 5432 -e -U postgres xorm_test3
20+
- psql xorm_test postgres -c "create schema xorm"
2021

2122
test:
2223
override:
@@ -30,7 +31,9 @@ test:
3031
- go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic
3132
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic
3233
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic
33-
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt > coverage.txt
34+
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic
35+
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic
36+
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt
3437
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh
3538
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh
3639
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh

dialect_postgres.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
895895
args := []interface{}{tableName}
896896
return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
897897
}
898+
898899
args := []interface{}{db.Schema, tableName}
899900
return `SELECT tablename FROM pg_tables WHERE schemaname = ? AND tablename = ?`, args
900901
}
@@ -912,6 +913,9 @@ func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
912913
quote := db.Quote
913914
idxName := index.Name
914915

916+
tableName = strings.Replace(tableName, `"`, "", -1)
917+
tableName = strings.Replace(tableName, `.`, "_", -1)
918+
915919
if !strings.HasPrefix(idxName, "UQE_") &&
916920
!strings.HasPrefix(idxName, "IDX_") {
917921
if index.Type == core.UniqueType {
@@ -920,6 +924,9 @@ func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
920924
idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
921925
}
922926
}
927+
if db.Uri.Schema != "" {
928+
idxName = db.Uri.Schema + "." + idxName
929+
}
923930
return fmt.Sprintf("DROP INDEX %v", quote(idxName))
924931
}
925932

@@ -960,7 +967,7 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
960967
var f string
961968
if len(db.Schema) != 0 {
962969
args = append(args, db.Schema)
963-
f = "AND s.table_schema = $2"
970+
f = " AND s.table_schema = $2"
964971
}
965972
s = fmt.Sprintf(s, f)
966973

@@ -1085,11 +1092,11 @@ func (db *postgres) GetTables() ([]*core.Table, error) {
10851092
func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
10861093
args := []interface{}{tableName}
10871094
s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")
1088-
db.LogSQL(s, args)
10891095
if len(db.Schema) != 0 {
10901096
args = append(args, db.Schema)
10911097
s = s + " AND schemaname=$2"
10921098
}
1099+
db.LogSQL(s, args)
10931100

10941101
rows, err := db.DB().Query(s, args...)
10951102
if err != nil {

engine.go

+20-67
Original file line numberDiff line numberDiff line change
@@ -536,46 +536,6 @@ func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.D
536536
return nil
537537
}
538538

539-
func (engine *Engine) tableName(beanOrTableName interface{}) (string, error) {
540-
v := rValue(beanOrTableName)
541-
if v.Type().Kind() == reflect.String {
542-
return beanOrTableName.(string), nil
543-
} else if v.Type().Kind() == reflect.Struct {
544-
return engine.tbName(v), nil
545-
}
546-
return "", errors.New("bean should be a struct or struct's point")
547-
}
548-
549-
func (engine *Engine) tbSchemaName(v string) string {
550-
// Add schema name as prefix of table name.
551-
// Only for postgres database.
552-
if engine.dialect.DBType() == core.POSTGRES &&
553-
engine.dialect.URI().Schema != "" &&
554-
engine.dialect.URI().Schema != postgresPublicSchema &&
555-
strings.Index(v, ".") == -1 {
556-
return engine.dialect.URI().Schema + "." + v
557-
}
558-
return v
559-
}
560-
561-
func (engine *Engine) tbName(v reflect.Value) string {
562-
if tb, ok := v.Interface().(TableName); ok {
563-
return engine.tbSchemaName(tb.TableName())
564-
565-
}
566-
567-
if v.Type().Kind() == reflect.Ptr {
568-
if tb, ok := reflect.Indirect(v).Interface().(TableName); ok {
569-
return engine.tbSchemaName(tb.TableName())
570-
}
571-
} else if v.CanAddr() {
572-
if tb, ok := v.Addr().Interface().(TableName); ok {
573-
return engine.tbSchemaName(tb.TableName())
574-
}
575-
}
576-
return engine.tbSchemaName(engine.TableMapper.Obj2Table(reflect.Indirect(v).Type().Name()))
577-
}
578-
579539
// Cascade use cascade or not
580540
func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
581541
session := engine.NewSession()
@@ -859,7 +819,7 @@ func (engine *Engine) TableInfo(bean interface{}) *Table {
859819
if err != nil {
860820
engine.logger.Error(err)
861821
}
862-
return &Table{tb, engine.tbName(v)}
822+
return &Table{tb, engine.TableName(bean)}
863823
}
864824

865825
func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
@@ -895,20 +855,8 @@ var (
895855
func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
896856
t := v.Type()
897857
table := engine.newTable()
898-
if tb, ok := v.Interface().(TableName); ok {
899-
table.Name = tb.TableName()
900-
} else {
901-
if v.CanAddr() {
902-
if tb, ok = v.Addr().Interface().(TableName); ok {
903-
table.Name = tb.TableName()
904-
}
905-
}
906-
if table.Name == "" {
907-
table.Name = engine.TableMapper.Obj2Table(t.Name())
908-
}
909-
}
910-
911858
table.Type = t
859+
table.Name = engine.tbNameForMap(v)
912860

913861
var idFieldColName string
914862
var hasCacheTag, hasNoCacheTag bool
@@ -1186,7 +1134,7 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
11861134
if t.Kind() != reflect.Struct {
11871135
return errors.New("error params")
11881136
}
1189-
tableName := engine.tbName(v)
1137+
tableName := engine.TableName(bean)
11901138
table, err := engine.autoMapType(v)
11911139
if err != nil {
11921140
return err
@@ -1210,7 +1158,7 @@ func (engine *Engine) ClearCache(beans ...interface{}) error {
12101158
if t.Kind() != reflect.Struct {
12111159
return errors.New("error params")
12121160
}
1213-
tableName := engine.tbName(v)
1161+
tableName := engine.TableName(bean)
12141162
table, err := engine.autoMapType(v)
12151163
if err != nil {
12161164
return err
@@ -1237,13 +1185,13 @@ func (engine *Engine) Sync(beans ...interface{}) error {
12371185

12381186
for _, bean := range beans {
12391187
v := rValue(bean)
1240-
tableName := engine.tbName(v)
1188+
tableNameNoSchema := engine.tbNameNoSchema(v.Interface())
12411189
table, err := engine.autoMapType(v)
12421190
if err != nil {
12431191
return err
12441192
}
12451193

1246-
isExist, err := session.Table(bean).isTableExist(tableName)
1194+
isExist, err := session.Table(bean).isTableExist(tableNameNoSchema)
12471195
if err != nil {
12481196
return err
12491197
}
@@ -1269,12 +1217,12 @@ func (engine *Engine) Sync(beans ...interface{}) error {
12691217
}
12701218
} else {
12711219
for _, col := range table.Columns() {
1272-
isExist, err := engine.dialect.IsColumnExist(tableName, col.Name)
1220+
isExist, err := engine.dialect.IsColumnExist(tableNameNoSchema, col.Name)
12731221
if err != nil {
12741222
return err
12751223
}
12761224
if !isExist {
1277-
if err := session.statement.setRefValue(v); err != nil {
1225+
if err := session.statement.setRefBean(bean); err != nil {
12781226
return err
12791227
}
12801228
err = session.addColumn(col.Name)
@@ -1285,35 +1233,35 @@ func (engine *Engine) Sync(beans ...interface{}) error {
12851233
}
12861234

12871235
for name, index := range table.Indexes {
1288-
if err := session.statement.setRefValue(v); err != nil {
1236+
if err := session.statement.setRefBean(bean); err != nil {
12891237
return err
12901238
}
12911239
if index.Type == core.UniqueType {
1292-
isExist, err := session.isIndexExist2(tableName, index.Cols, true)
1240+
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, true)
12931241
if err != nil {
12941242
return err
12951243
}
12961244
if !isExist {
1297-
if err := session.statement.setRefValue(v); err != nil {
1245+
if err := session.statement.setRefBean(bean); err != nil {
12981246
return err
12991247
}
13001248

1301-
err = session.addUnique(tableName, name)
1249+
err = session.addUnique(tableNameNoSchema, name)
13021250
if err != nil {
13031251
return err
13041252
}
13051253
}
13061254
} else if index.Type == core.IndexType {
1307-
isExist, err := session.isIndexExist2(tableName, index.Cols, false)
1255+
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, false)
13081256
if err != nil {
13091257
return err
13101258
}
13111259
if !isExist {
1312-
if err := session.statement.setRefValue(v); err != nil {
1260+
if err := session.statement.setRefBean(bean); err != nil {
13131261
return err
13141262
}
13151263

1316-
err = session.addIndex(tableName, name)
1264+
err = session.addIndex(tableNameNoSchema, name)
13171265
if err != nil {
13181266
return err
13191267
}
@@ -1649,6 +1597,11 @@ func (engine *Engine) SetTZDatabase(tz *time.Location) {
16491597
engine.DatabaseTZ = tz
16501598
}
16511599

1600+
// SetSchema sets the schema of database
1601+
func (engine *Engine) SetSchema(schema string) {
1602+
engine.dialect.URI().Schema = schema
1603+
}
1604+
16521605
// Unscoped always disable struct tag "deleted"
16531606
func (engine *Engine) Unscoped() *Session {
16541607
session := engine.NewSession()

engine_table.go

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2018 The Xorm Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xorm
6+
7+
import (
8+
"fmt"
9+
"reflect"
10+
"strings"
11+
12+
"github.com/go-xorm/core"
13+
)
14+
15+
// TableNameWithSchema will automatically add schema prefix on table name
16+
func (engine *Engine) tbNameWithSchema(v string) string {
17+
// Add schema name as prefix of table name.
18+
// Only for postgres database.
19+
if engine.dialect.DBType() == core.POSTGRES &&
20+
engine.dialect.URI().Schema != "" &&
21+
engine.dialect.URI().Schema != postgresPublicSchema &&
22+
strings.Index(v, ".") == -1 {
23+
return engine.dialect.URI().Schema + "." + v
24+
}
25+
return v
26+
}
27+
28+
// TableName returns table name with schema prefix if has
29+
func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
30+
tbName := engine.tbNameNoSchema(bean)
31+
if len(includeSchema) > 0 && includeSchema[0] {
32+
tbName = engine.tbNameWithSchema(tbName)
33+
}
34+
35+
return tbName
36+
}
37+
38+
// tbName get some table's table name
39+
func (session *Session) tbNameNoSchema(table *core.Table) string {
40+
if len(session.statement.AltTableName) > 0 {
41+
return session.statement.AltTableName
42+
}
43+
44+
return table.Name
45+
}
46+
47+
func (engine *Engine) tbNameForMap(v reflect.Value) string {
48+
t := v.Type()
49+
if tb, ok := v.Interface().(TableName); ok {
50+
return tb.TableName()
51+
}
52+
if v.CanAddr() {
53+
if tb, ok := v.Addr().Interface().(TableName); ok {
54+
return tb.TableName()
55+
}
56+
}
57+
return engine.TableMapper.Obj2Table(t.Name())
58+
}
59+
60+
func (engine *Engine) tbNameNoSchema(tablename interface{}) string {
61+
switch tablename.(type) {
62+
case []string:
63+
t := tablename.([]string)
64+
if len(t) > 1 {
65+
return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1]))
66+
} else if len(t) == 1 {
67+
return engine.Quote(t[0])
68+
}
69+
case []interface{}:
70+
t := tablename.([]interface{})
71+
l := len(t)
72+
var table string
73+
if l > 0 {
74+
f := t[0]
75+
switch f.(type) {
76+
case string:
77+
table = f.(string)
78+
case TableName:
79+
table = f.(TableName).TableName()
80+
default:
81+
v := rValue(f)
82+
t := v.Type()
83+
if t.Kind() == reflect.Struct {
84+
table = engine.tbNameForMap(v)
85+
} else {
86+
table = engine.Quote(fmt.Sprintf("%v", f))
87+
}
88+
}
89+
}
90+
if l > 1 {
91+
return fmt.Sprintf("%v AS %v", engine.Quote(table),
92+
engine.Quote(fmt.Sprintf("%v", t[1])))
93+
} else if l == 1 {
94+
return engine.Quote(table)
95+
}
96+
case TableName:
97+
return tablename.(TableName).TableName()
98+
case string:
99+
return tablename.(string)
100+
default:
101+
v := rValue(tablename)
102+
t := v.Type()
103+
if t.Kind() == reflect.Struct {
104+
return engine.tbNameForMap(v)
105+
}
106+
return engine.Quote(fmt.Sprintf("%v", tablename))
107+
}
108+
return ""
109+
}

interface.go

+2
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,15 @@ type EngineInterface interface {
8787
SetDefaultCacher(core.Cacher)
8888
SetLogLevel(core.LogLevel)
8989
SetMapper(core.IMapper)
90+
SetSchema(string)
9091
SetTZDatabase(tz *time.Location)
9192
SetTZLocation(tz *time.Location)
9293
ShowSQL(show ...bool)
9394
Sync(...interface{}) error
9495
Sync2(...interface{}) error
9596
StoreEngine(storeEngine string) *Session
9697
TableInfo(bean interface{}) *Table
98+
TableName(interface{}, ...bool) string
9799
UnMapType(reflect.Type)
98100
}
99101

0 commit comments

Comments
 (0)