Co-authored-by: zeripath <art27@cantab.net>tags/v1.16.0-rc1
@@ -139,7 +139,7 @@ require ( | |||
mvdan.cc/xurls/v2 v2.2.0 | |||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 | |||
xorm.io/builder v0.3.9 | |||
xorm.io/xorm v1.2.2 | |||
xorm.io/xorm v1.2.4 | |||
) | |||
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 |
@@ -1761,5 +1761,5 @@ xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= | |||
xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc= | |||
xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= | |||
xorm.io/xorm v1.0.6/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4= | |||
xorm.io/xorm v1.2.2 h1:FFBOEvJ++8fYBA9cywf2sxDVmFktl1SpJzTAG1ab06Y= | |||
xorm.io/xorm v1.2.2/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0= | |||
xorm.io/xorm v1.2.4 h1:2MQV4wJt4kY6CYJsLxjCLzBen7+aqVxqDTIwfnR59g4= | |||
xorm.io/xorm v1.2.4/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0= |
@@ -1052,7 +1052,7 @@ strk.kbt.io/projects/go/libravatar | |||
# xorm.io/builder v0.3.9 | |||
## explicit | |||
xorm.io/builder | |||
# xorm.io/xorm v1.2.2 | |||
# xorm.io/xorm v1.2.4 | |||
## explicit | |||
xorm.io/xorm | |||
xorm.io/xorm/caches |
@@ -325,6 +325,9 @@ func AssignValue(dv reflect.Value, src interface{}) error { | |||
if src == nil { | |||
return nil | |||
} | |||
if v, ok := src.(*interface{}); ok { | |||
return AssignValue(dv, *v) | |||
} | |||
if dv.Type().Implements(scannerType) { | |||
return dv.Interface().(sql.Scanner).Scan(src) |
@@ -103,6 +103,39 @@ func (db *Base) URI() *URI { | |||
return db.uri | |||
} | |||
// CreateTableSQL implements Dialect | |||
func (db *Base) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) { | |||
if tableName == "" { | |||
tableName = table.Name | |||
} | |||
quoter := db.dialect.Quoter() | |||
var b strings.Builder | |||
b.WriteString("CREATE TABLE IF NOT EXISTS ") | |||
quoter.QuoteTo(&b, tableName) | |||
b.WriteString(" (") | |||
for i, colName := range table.ColumnsSeq() { | |||
col := table.GetColumn(colName) | |||
s, _ := ColumnString(db.dialect, col, col.IsPrimaryKey && len(table.PrimaryKeys) == 1) | |||
b.WriteString(s) | |||
if i != len(table.ColumnsSeq())-1 { | |||
b.WriteString(", ") | |||
} | |||
} | |||
if len(table.PrimaryKeys) > 1 { | |||
b.WriteString(", PRIMARY KEY (") | |||
b.WriteString(quoter.Join(table.PrimaryKeys, ",")) | |||
b.WriteString(")") | |||
} | |||
b.WriteString(")") | |||
return []string{b.String()}, false | |||
} | |||
// DropTableSQL returns drop table SQL | |||
func (db *Base) DropTableSQL(tableName string) (string, bool) { | |||
quote := db.dialect.Quoter().Quote |
@@ -626,34 +626,37 @@ WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? | |||
} | |||
func (db *mssql) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) { | |||
var sql string | |||
if tableName == "" { | |||
tableName = table.Name | |||
} | |||
sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE " | |||
quoter := db.dialect.Quoter() | |||
var b strings.Builder | |||
b.WriteString("IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '") | |||
quoter.QuoteTo(&b, tableName) | |||
b.WriteString("' ) CREATE TABLE ") | |||
quoter.QuoteTo(&b, tableName) | |||
b.WriteString(" (") | |||
sql += db.Quoter().Quote(tableName) + " (" | |||
pkList := table.PrimaryKeys | |||
for _, colName := range table.ColumnsSeq() { | |||
for i, colName := range table.ColumnsSeq() { | |||
col := table.GetColumn(colName) | |||
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1) | |||
sql += s | |||
sql = strings.TrimSpace(sql) | |||
sql += ", " | |||
s, _ := ColumnString(db.dialect, col, col.IsPrimaryKey && len(table.PrimaryKeys) == 1) | |||
b.WriteString(s) | |||
if i != len(table.ColumnsSeq())-1 { | |||
b.WriteString(", ") | |||
} | |||
} | |||
if len(pkList) > 1 { | |||
sql += "PRIMARY KEY ( " | |||
sql += strings.Join(pkList, ",") | |||
sql += " ), " | |||
if len(table.PrimaryKeys) > 1 { | |||
b.WriteString(", PRIMARY KEY (") | |||
b.WriteString(quoter.Join(table.PrimaryKeys, ",")) | |||
b.WriteString(")") | |||
} | |||
sql = sql[:len(sql)-2] + ")" | |||
sql += ";" | |||
return []string{sql}, true | |||
b.WriteString(")") | |||
return []string{b.String()}, true | |||
} | |||
func (db *mssql) ForUpdateSQL(query string) string { |
@@ -626,42 +626,43 @@ func (db *mysql) GetIndexes(queryer core.Queryer, ctx context.Context, tableName | |||
} | |||
func (db *mysql) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) { | |||
var sql = "CREATE TABLE IF NOT EXISTS " | |||
if tableName == "" { | |||
tableName = table.Name | |||
} | |||
quoter := db.Quoter() | |||
sql += quoter.Quote(tableName) | |||
sql += " (" | |||
if len(table.ColumnsSeq()) > 0 { | |||
pkList := table.PrimaryKeys | |||
for _, colName := range table.ColumnsSeq() { | |||
col := table.GetColumn(colName) | |||
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1) | |||
sql += s | |||
sql = strings.TrimSpace(sql) | |||
if len(col.Comment) > 0 { | |||
sql += " COMMENT '" + col.Comment + "'" | |||
} | |||
sql += ", " | |||
quoter := db.dialect.Quoter() | |||
var b strings.Builder | |||
b.WriteString("CREATE TABLE IF NOT EXISTS ") | |||
quoter.QuoteTo(&b, tableName) | |||
b.WriteString(" (") | |||
for i, colName := range table.ColumnsSeq() { | |||
col := table.GetColumn(colName) | |||
s, _ := ColumnString(db.dialect, col, col.IsPrimaryKey && len(table.PrimaryKeys) == 1) | |||
b.WriteString(s) | |||
if len(col.Comment) > 0 { | |||
b.WriteString(" COMMENT '") | |||
b.WriteString(col.Comment) | |||
b.WriteString("'") | |||
} | |||
if len(pkList) > 1 { | |||
sql += "PRIMARY KEY ( " | |||
sql += quoter.Join(pkList, ",") | |||
sql += " ), " | |||
if i != len(table.ColumnsSeq())-1 { | |||
b.WriteString(", ") | |||
} | |||
} | |||
sql = sql[:len(sql)-2] | |||
if len(table.PrimaryKeys) > 1 { | |||
b.WriteString(", PRIMARY KEY (") | |||
b.WriteString(quoter.Join(table.PrimaryKeys, ",")) | |||
b.WriteString(")") | |||
} | |||
sql += ")" | |||
b.WriteString(")") | |||
if table.StoreEngine != "" { | |||
sql += " ENGINE=" + table.StoreEngine | |||
b.WriteString(" ENGINE=") | |||
b.WriteString(table.StoreEngine) | |||
} | |||
var charset = table.Charset | |||
@@ -669,13 +670,15 @@ func (db *mysql) CreateTableSQL(table *schemas.Table, tableName string) ([]strin | |||
charset = db.URI().Charset | |||
} | |||
if len(charset) != 0 { | |||
sql += " DEFAULT CHARSET " + charset | |||
b.WriteString(" DEFAULT CHARSET ") | |||
b.WriteString(charset) | |||
} | |||
if db.rowFormat != "" { | |||
sql += " ROW_FORMAT=" + db.rowFormat | |||
b.WriteString(" ROW_FORMAT=") | |||
b.WriteString(db.rowFormat) | |||
} | |||
return []string{sql}, true | |||
return []string{b.String()}, true | |||
} | |||
func (db *mysql) Filters() []Filter { |
@@ -965,41 +965,6 @@ func (db *postgres) AutoIncrStr() string { | |||
return "" | |||
} | |||
func (db *postgres) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) { | |||
var sql string | |||
sql = "CREATE TABLE IF NOT EXISTS " | |||
if tableName == "" { | |||
tableName = table.Name | |||
} | |||
quoter := db.Quoter() | |||
sql += quoter.Quote(tableName) | |||
sql += " (" | |||
if len(table.ColumnsSeq()) > 0 { | |||
pkList := table.PrimaryKeys | |||
for _, colName := range table.ColumnsSeq() { | |||
col := table.GetColumn(colName) | |||
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1) | |||
sql += s | |||
sql = strings.TrimSpace(sql) | |||
sql += ", " | |||
} | |||
if len(pkList) > 1 { | |||
sql += "PRIMARY KEY ( " | |||
sql += quoter.Join(pkList, ",") | |||
sql += " ), " | |||
} | |||
sql = sql[:len(sql)-2] | |||
} | |||
sql += ")" | |||
return []string{sql}, true | |||
} | |||
func (db *postgres) IndexCheckSQL(tableName, idxName string) (string, []interface{}) { | |||
if len(db.getSchema()) == 0 { | |||
args := []interface{}{tableName, idxName} |
@@ -285,41 +285,6 @@ func (db *sqlite3) DropIndexSQL(tableName string, index *schemas.Index) string { | |||
return fmt.Sprintf("DROP INDEX %v", db.Quoter().Quote(idxName)) | |||
} | |||
func (db *sqlite3) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) { | |||
var sql string | |||
sql = "CREATE TABLE IF NOT EXISTS " | |||
if tableName == "" { | |||
tableName = table.Name | |||
} | |||
quoter := db.Quoter() | |||
sql += quoter.Quote(tableName) | |||
sql += " (" | |||
if len(table.ColumnsSeq()) > 0 { | |||
pkList := table.PrimaryKeys | |||
for _, colName := range table.ColumnsSeq() { | |||
col := table.GetColumn(colName) | |||
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1) | |||
sql += s | |||
sql = strings.TrimSpace(sql) | |||
sql += ", " | |||
} | |||
if len(pkList) > 1 { | |||
sql += "PRIMARY KEY ( " | |||
sql += quoter.Join(pkList, ",") | |||
sql += " ), " | |||
} | |||
sql = sql[:len(sql)-2] | |||
} | |||
sql += ")" | |||
return []string{sql}, true | |||
} | |||
func (db *sqlite3) ForUpdateSQL(query string) string { | |||
return query | |||
} |
@@ -0,0 +1,25 @@ | |||
// Copyright 2021 The Xorm Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package utils | |||
import "reflect" | |||
// New creates a value according type | |||
func New(tp reflect.Type, length, cap int) reflect.Value { | |||
switch tp.Kind() { | |||
case reflect.Slice: | |||
slice := reflect.MakeSlice(tp, length, cap) | |||
x := reflect.New(slice.Type()) | |||
x.Elem().Set(slice) | |||
return x | |||
case reflect.Map: | |||
mp := reflect.MakeMapWithSize(tp, cap) | |||
x := reflect.New(mp.Type()) | |||
x.Elem().Set(mp) | |||
return x | |||
default: | |||
return reflect.New(tp) | |||
} | |||
} |
@@ -84,12 +84,18 @@ func newRows(session *Session, bean interface{}) (*Rows, error) { | |||
// Next move cursor to next record, return false if end has reached | |||
func (rows *Rows) Next() bool { | |||
return rows.rows.Next() | |||
if rows.rows != nil { | |||
return rows.rows.Next() | |||
} | |||
return false | |||
} | |||
// Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close. | |||
func (rows *Rows) Err() error { | |||
return rows.rows.Err() | |||
if rows.rows != nil { | |||
return rows.rows.Err() | |||
} | |||
return nil | |||
} | |||
// Scan row record to bean properties |
@@ -174,6 +174,11 @@ func (session *Session) Engine() *Engine { | |||
return session.engine | |||
} | |||
// Tx returns session tx | |||
func (session *Session) Tx() *core.Tx { | |||
return session.tx | |||
} | |||
func (session *Session) getQueryer() core.Queryer { | |||
if session.tx != nil { | |||
return session.tx |
@@ -161,6 +161,16 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) | |||
} | |||
func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error { | |||
elemType := containerValue.Type().Elem() | |||
var isPointer bool | |||
if elemType.Kind() == reflect.Ptr { | |||
isPointer = true | |||
elemType = elemType.Elem() | |||
} | |||
if elemType.Kind() == reflect.Ptr { | |||
return errors.New("pointer to pointer is not supported") | |||
} | |||
rows, err := session.queryRows(sqlStr, args...) | |||
if err != nil { | |||
return err | |||
@@ -177,31 +187,8 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect | |||
return err | |||
} | |||
var newElemFunc func(fields []string) reflect.Value | |||
elemType := containerValue.Type().Elem() | |||
var isPointer bool | |||
if elemType.Kind() == reflect.Ptr { | |||
isPointer = true | |||
elemType = elemType.Elem() | |||
} | |||
if elemType.Kind() == reflect.Ptr { | |||
return errors.New("pointer to pointer is not supported") | |||
} | |||
newElemFunc = func(fields []string) reflect.Value { | |||
switch elemType.Kind() { | |||
case reflect.Slice: | |||
slice := reflect.MakeSlice(elemType, len(fields), len(fields)) | |||
x := reflect.New(slice.Type()) | |||
x.Elem().Set(slice) | |||
return x | |||
case reflect.Map: | |||
mp := reflect.MakeMap(elemType) | |||
x := reflect.New(mp.Type()) | |||
x.Elem().Set(mp) | |||
return x | |||
} | |||
return reflect.New(elemType) | |||
var newElemFunc = func(fields []string) reflect.Value { | |||
return utils.New(elemType, len(fields), len(fields)) | |||
} | |||
var containerValueSetFunc func(*reflect.Value, schemas.PK) error | |||
@@ -226,10 +213,15 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect | |||
containerValueSetFunc = func(newValue *reflect.Value, pk schemas.PK) error { | |||
keyValue := reflect.New(keyType) | |||
err := convertPKToValue(table, keyValue.Interface(), pk) | |||
if err != nil { | |||
return err | |||
cols := table.PKColumns() | |||
if len(cols) == 1 { | |||
if err := convert.AssignValue(keyValue, pk[0]); err != nil { | |||
return err | |||
} | |||
} else { | |||
keyValue.Set(reflect.ValueOf(&pk)) | |||
} | |||
if isPointer { | |||
containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr()) | |||
} else { | |||
@@ -241,8 +233,7 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect | |||
if elemType.Kind() == reflect.Struct { | |||
var newValue = newElemFunc(fields) | |||
dataStruct := utils.ReflectValue(newValue.Interface()) | |||
tb, err := session.engine.tagParser.ParseWithCache(dataStruct) | |||
tb, err := session.engine.tagParser.ParseWithCache(newValue) | |||
if err != nil { | |||
return err | |||
} | |||
@@ -266,7 +257,6 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect | |||
default: | |||
err = rows.Scan(bean) | |||
} | |||
if err != nil { | |||
return err | |||
} | |||
@@ -278,16 +268,6 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect | |||
return rows.Err() | |||
} | |||
func convertPKToValue(table *schemas.Table, dst interface{}, pk schemas.PK) error { | |||
cols := table.PKColumns() | |||
if len(cols) == 1 { | |||
return convert.Assign(dst, pk[0], nil, nil) | |||
} | |||
dst = pk | |||
return nil | |||
} | |||
func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) { | |||
if !session.canCache() || | |||
utils.IndexNoCase(sqlStr, "having") != -1 || |