This commit is contained in:
“michael2008s” 2015-09-08 19:34:05 +08:00
commit 728b819b14
14 changed files with 262 additions and 67 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2013 - 2015 Copyright (c) 2013 - 2015 The Xorm Authors
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -2,6 +2,8 @@
Xorm is a simple and powerful ORM for Go. Xorm is a simple and powerful ORM for Go.
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lunny/xorm/trend.png)](https://bitdeli.com/free "Bitdeli Badge") [![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lunny/xorm/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
# Features # Features

View File

@ -4,6 +4,8 @@
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm) [![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm)
## 特性 ## 特性

View File

@ -1 +1 @@
xorm v0.4.3.0520 xorm v0.4.3.0824

View File

@ -33,7 +33,7 @@ func test(engine *xorm.Engine) {
return return
} }
size := 500 size := 100
queue := make(chan int, size) queue := make(chan int, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
@ -83,7 +83,7 @@ func test(engine *xorm.Engine) {
} }
func main() { func main() {
runtime.GOMAXPROCS(1) runtime.GOMAXPROCS(2)
fmt.Println("-----start sqlite go routines-----") fmt.Println("-----start sqlite go routines-----")
engine, err := sqliteEngine() engine, err := sqliteEngine()
if err != nil { if err != nil {

View File

@ -509,6 +509,10 @@ func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
return sql return sql
} }
func (db *mssql) ForUpdateSql(query string) string {
return query
}
func (db *mssql) Filters() []core.Filter { func (db *mssql) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}} return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
} }

View File

@ -913,7 +913,8 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
} }
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{tableName} pgSchema := "public"
args := []interface{}{tableName,pgSchema}
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix , s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey, CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
@ -924,7 +925,7 @@ FROM pg_attribute f
LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey) LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
LEFT JOIN pg_class AS g ON p.confrelid = g.oid LEFT JOIN pg_class AS g ON p.confrelid = g.oid
LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
WHERE c.relkind = 'r'::char AND c.relname = $1 AND f.attnum > 0 ORDER BY f.attnum;` WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;`
rows, err := db.DB().Query(s, args...) rows, err := db.DB().Query(s, args...)
if db.Logger != nil { if db.Logger != nil {

View File

@ -23,6 +23,10 @@ type BeforeSetProcessor interface {
BeforeSet(string, Cell) BeforeSet(string, Cell)
} }
type AfterSetProcessor interface {
AfterSet(string, Cell)
}
// !nashtsai! TODO enable BeforeValidateProcessor when xorm start to support validations // !nashtsai! TODO enable BeforeValidateProcessor when xorm start to support validations
//// Executed before an object is validated //// Executed before an object is validated
//type BeforeValidateProcessor interface { //type BeforeValidateProcessor interface {

View File

@ -45,7 +45,7 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable) sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable)
} }
rows.session.Engine.logSQL(sqlStr, args) rows.session.saveLastSQL(sqlStr, args)
var err error var err error
rows.stmt, err = rows.session.DB().Prepare(sqlStr) rows.stmt, err = rows.session.DB().Prepare(sqlStr)
if err != nil { if err != nil {

View File

@ -46,6 +46,10 @@ type Session struct {
stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr)) stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
cascadeDeep int cascadeDeep int
// !evalphobia! stored the last executed query on this session
lastSQL string
lastSQLArgs []interface{}
} }
// Method Init reset the session as the init status. // Method Init reset the session as the init status.
@ -63,6 +67,9 @@ func (session *Session) Init() {
session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0) session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
session.beforeClosures = make([]func(interface{}), 0) session.beforeClosures = make([]func(interface{}), 0)
session.afterClosures = make([]func(interface{}), 0) session.afterClosures = make([]func(interface{}), 0)
session.lastSQL = ""
session.lastSQLArgs = []interface{}{}
} }
// Method Close release the connection from pool // Method Close release the connection from pool
@ -224,6 +231,12 @@ func (session *Session) Distinct(columns ...string) *Session {
return session return session
} }
// Set Read/Write locking for UPDATE
func (session *Session) ForUpdate() *Session {
session.Statement.IsForUpdate = true
return session
}
// Only not use the paramters as select or update columns // Only not use the paramters as select or update columns
func (session *Session) Omit(columns ...string) *Session { func (session *Session) Omit(columns ...string) *Session {
session.Statement.Omit(columns...) session.Statement.Omit(columns...)
@ -331,8 +344,7 @@ func (session *Session) Begin() error {
session.IsAutoCommit = false session.IsAutoCommit = false
session.IsCommitedOrRollbacked = false session.IsCommitedOrRollbacked = false
session.Tx = tx session.Tx = tx
session.saveLastSQL("BEGIN TRANSACTION")
session.Engine.logSQL("BEGIN TRANSACTION")
} }
return nil return nil
} }
@ -340,7 +352,7 @@ func (session *Session) Begin() error {
// When using transaction, you can rollback if any error // When using transaction, you can rollback if any error
func (session *Session) Rollback() error { func (session *Session) Rollback() error {
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
session.Engine.logSQL(session.Engine.dialect.RollBackStr()) session.saveLastSQL(session.Engine.dialect.RollBackStr())
session.IsCommitedOrRollbacked = true session.IsCommitedOrRollbacked = true
return session.Tx.Rollback() return session.Tx.Rollback()
} }
@ -350,7 +362,7 @@ func (session *Session) Rollback() error {
// When using transaction, Commit will commit all operations. // When using transaction, Commit will commit all operations.
func (session *Session) Commit() error { func (session *Session) Commit() error {
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
session.Engine.logSQL("COMMIT") session.saveLastSQL("COMMIT")
session.IsCommitedOrRollbacked = true session.IsCommitedOrRollbacked = true
var err error var err error
if err = session.Tx.Commit(); err == nil { if err = session.Tx.Commit(); err == nil {
@ -471,7 +483,7 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
} }
session.Engine.logSQL(sqlStr, args...) session.saveLastSQL(sqlStr, args...)
return session.Engine.LogSQLExecutionTime(sqlStr, args, func() (sql.Result, error) { return session.Engine.LogSQLExecutionTime(sqlStr, args, func() (sql.Result, error) {
if session.IsAutoCommit { if session.IsAutoCommit {
@ -614,11 +626,15 @@ func (session *Session) DropTable(beanOrTableName interface{}) error {
return nil return nil
} }
func (statement *Statement) JoinColumns(cols []*core.Column) string { func (statement *Statement) JoinColumns(cols []*core.Column, includeTableName bool) string {
var colnames = make([]string, len(cols)) var colnames = make([]string, len(cols))
for i, col := range cols { for i, col := range cols {
if includeTableName {
colnames[i] = statement.Engine.Quote(statement.TableName()) + colnames[i] = statement.Engine.Quote(statement.TableName()) +
"." + statement.Engine.Quote(col.Name) "." + statement.Engine.Quote(col.Name)
} else {
colnames[i] = statement.Engine.Quote(col.Name)
}
} }
return strings.Join(colnames, ", ") return strings.Join(colnames, ", ")
} }
@ -630,11 +646,14 @@ func (statement *Statement) convertIdSql(sqlStr string) string {
return "" return ""
} }
colstrs := statement.JoinColumns(cols) colstrs := statement.JoinColumns(cols, false)
sqls := splitNNoCase(sqlStr, "from", 2) sqls := splitNNoCase(sqlStr, " from ", 2)
if len(sqls) != 2 { if len(sqls) != 2 {
return "" return ""
} }
if statement.Engine.dialect.DBType() == "ql" {
return fmt.Sprintf("SELECT id() FROM %v", sqls[1])
}
return fmt.Sprintf("SELECT %s FROM %v", colstrs, sqls[1]) return fmt.Sprintf("SELECT %s FROM %v", colstrs, sqls[1])
} }
return "" return ""
@ -1463,7 +1482,7 @@ func (session *Session) isTableEmpty(tableName string) (bool, error) {
var total int64 var total int64
sql := fmt.Sprintf("select count(*) from %s", session.Engine.Quote(tableName)) sql := fmt.Sprintf("select count(*) from %s", session.Engine.Quote(tableName))
err := session.DB().QueryRow(sql).Scan(&total) err := session.DB().QueryRow(sql).Scan(&total)
session.Engine.logSQL(sql) session.saveLastSQL(sql)
if err != nil { if err != nil {
return true, err return true, err
} }
@ -1632,6 +1651,14 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
} }
} }
defer func() {
if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet {
for ii, key := range fields {
b.AfterSet(key, Cell(scanResults[ii].(*interface{})))
}
}
}()
var tempMap = make(map[string]int) var tempMap = make(map[string]int)
for ii, key := range fields { for ii, key := range fields {
var idx int var idx int
@ -1681,7 +1708,6 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
hasAssigned := false hasAssigned := false
switch fieldType.Kind() { switch fieldType.Kind() {
case reflect.Complex64, reflect.Complex128: case reflect.Complex64, reflect.Complex128:
if rawValueType.Kind() == reflect.String { if rawValueType.Kind() == reflect.String {
hasAssigned = true hasAssigned = true
@ -1692,6 +1718,15 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
return err return err
} }
fieldValue.Set(x.Elem()) fieldValue.Set(x.Elem())
} else if rawValueType.Kind() == reflect.Slice {
hasAssigned = true
x := reflect.New(fieldType)
err := json.Unmarshal(vv.Bytes(), x.Interface())
if err != nil {
session.Engine.LogError(err)
return err
}
fieldValue.Set(x.Elem())
} }
case reflect.Slice, reflect.Array: case reflect.Slice, reflect.Array:
switch rawValueType.Kind() { switch rawValueType.Kind() {
@ -1736,6 +1771,7 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
fieldValue.SetUint(uint64(vv.Int())) fieldValue.SetUint(uint64(vv.Int()))
} }
case reflect.Struct: case reflect.Struct:
col := table.GetColumn(key)
if fieldType.ConvertibleTo(core.TimeType) { if fieldType.ConvertibleTo(core.TimeType) {
if rawValueType == core.TimeType { if rawValueType == core.TimeType {
hasAssigned = true hasAssigned = true
@ -1743,7 +1779,7 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
t := vv.Convert(core.TimeType).Interface().(time.Time) t := vv.Convert(core.TimeType).Interface().(time.Time)
z, _ := t.Zone() z, _ := t.Zone()
if len(z) == 0 || t.Year() == 0 { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location if len(z) == 0 || t.Year() == 0 { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
session.Engine.LogDebug("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location()) session.Engine.LogDebugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
t.Minute(), t.Second(), t.Nanosecond(), time.Local) t.Minute(), t.Second(), t.Nanosecond(), time.Local)
} }
@ -1765,15 +1801,35 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
// !<winxxp>! 增加支持sql.Scanner接口的结构如sql.NullString // !<winxxp>! 增加支持sql.Scanner接口的结构如sql.NullString
hasAssigned = true hasAssigned = true
if err := nulVal.Scan(vv.Interface()); err != nil { if err := nulVal.Scan(vv.Interface()); err != nil {
fmt.Println("sql.Sanner error:", err.Error()) //fmt.Println("sql.Sanner error:", err.Error())
session.Engine.LogError("sql.Sanner error:", err.Error()) session.Engine.LogError("sql.Sanner error:", err.Error())
hasAssigned = false hasAssigned = false
} }
} else if col.SQLType.IsJson() {
if rawValueType.Kind() == reflect.String {
hasAssigned = true
x := reflect.New(fieldType)
err := json.Unmarshal([]byte(vv.String()), x.Interface())
if err != nil {
session.Engine.LogError(err)
return err
}
fieldValue.Set(x.Elem())
} else if rawValueType.Kind() == reflect.Slice {
hasAssigned = true
x := reflect.New(fieldType)
err := json.Unmarshal(vv.Bytes(), x.Interface())
if err != nil {
session.Engine.LogError(err)
return err
}
fieldValue.Set(x.Elem())
}
} else if session.Statement.UseCascade { } else if session.Statement.UseCascade {
table := session.Engine.autoMapType(*fieldValue) table := session.Engine.autoMapType(*fieldValue)
if table != nil { if table != nil {
if len(table.PrimaryKeys) > 1 { if len(table.PrimaryKeys) != 1 {
panic("unsupported composited primary key cascade") panic("unsupported non or composited primary key cascade")
} }
var pk = make(core.PK, len(table.PrimaryKeys)) var pk = make(core.PK, len(table.PrimaryKeys))
@ -1964,7 +2020,7 @@ func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{})
*sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable) *sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable)
} }
session.Engine.logSQL(*sqlStr, paramStr...) session.saveLastSQL(*sqlStr, paramStr...)
} }
func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
@ -2954,21 +3010,39 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
return tf, nil return tf, nil
} }
if fieldTable, ok := session.Engine.Tables[fieldValue.Type()]; ok { if !col.SQLType.IsJson() {
if len(fieldTable.PrimaryKeys) == 1 {
pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
return pkField.Interface(), nil
} else {
return 0, fmt.Errorf("no primary key for col %v", col.Name)
}
} else {
// !<winxxp>! 增加支持driver.Valuer接口的结构如sql.NullString // !<winxxp>! 增加支持driver.Valuer接口的结构如sql.NullString
if v, ok := fieldValue.Interface().(driver.Valuer); ok { if v, ok := fieldValue.Interface().(driver.Valuer); ok {
return v.Value() return v.Value()
} }
return 0, fmt.Errorf("Unsupported type %v", fieldValue.Type()) fieldTable := session.Engine.autoMapType(fieldValue)
//if fieldTable, ok := session.Engine.Tables[fieldValue.Type()]; ok {
if len(fieldTable.PrimaryKeys) == 1 {
pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
return pkField.Interface(), nil
} }
return 0, fmt.Errorf("no primary key for col %v", col.Name)
//}
}
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
session.Engine.LogError(err)
return 0, err
}
return string(bytes), nil
} else if col.SQLType.IsBlob() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
session.Engine.LogError(err)
return 0, err
}
return bytes, nil
}
return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
case reflect.Complex64, reflect.Complex128: case reflect.Complex64, reflect.Complex128:
bytes, err := json.Marshal(fieldValue.Interface()) bytes, err := json.Marshal(fieldValue.Interface())
if err != nil { if err != nil {
@ -3002,9 +3076,8 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val
} }
} }
return bytes, nil return bytes, nil
} else {
return nil, ErrUnSupportedType
} }
return nil, ErrUnSupportedType
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return int64(fieldValue.Uint()), nil return int64(fieldValue.Uint()), nil
default: default:
@ -3094,9 +3167,10 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
// for postgres, many of them didn't implement lastInsertId, so we should // for postgres, many of them didn't implement lastInsertId, so we should
// implemented it ourself. // implemented it ourself.
if session.Engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 {
//assert table.AutoIncrement != ""
res, err := session.query("select seq_atable.currval from dual", args...)
if session.Engine.DriverName() != core.POSTGRES || table.AutoIncrement == "" {
res, err := session.exec(sqlStr, args...)
if err != nil { if err != nil {
return 0, err return 0, err
} else { } else {
@ -3116,14 +3190,14 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
} }
} }
if table.AutoIncrement == "" { if len(res) < 1 {
return res.RowsAffected() return 0, errors.New("insert no error but not returned id")
} }
var id int64 = 0 idByte := res[0][table.AutoIncrement]
id, err = res.LastInsertId() id, err := strconv.ParseInt(string(idByte), 10, 64)
if err != nil || id <= 0 { if err != nil {
return res.RowsAffected() return 1, err
} }
aiValue, err := table.AutoIncrColumn().ValueOf(bean) aiValue, err := table.AutoIncrColumn().ValueOf(bean)
@ -3131,8 +3205,8 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
session.Engine.LogError(err) session.Engine.LogError(err)
} }
if aiValue == nil || !aiValue.IsValid() /*|| aiValue.Int() != 0*/ || !aiValue.CanSet() { if aiValue == nil || !aiValue.IsValid() /*|| aiValue. != 0*/ || !aiValue.CanSet() {
return res.RowsAffected() return 1, nil
} }
var v interface{} = id var v interface{} = id
@ -3150,8 +3224,8 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
} }
aiValue.Set(reflect.ValueOf(v)) aiValue.Set(reflect.ValueOf(v))
return res.RowsAffected() return 1, nil
} else { } else if session.Engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 {
//assert table.AutoIncrement != "" //assert table.AutoIncrement != ""
sqlStr = sqlStr + " RETURNING " + session.Engine.Quote(table.AutoIncrement) sqlStr = sqlStr + " RETURNING " + session.Engine.Quote(table.AutoIncrement)
res, err := session.query(sqlStr, args...) res, err := session.query(sqlStr, args...)
@ -3210,6 +3284,62 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
aiValue.Set(reflect.ValueOf(v)) aiValue.Set(reflect.ValueOf(v))
return 1, nil return 1, nil
} else {
res, err := session.exec(sqlStr, args...)
if err != nil {
return 0, err
} else {
handleAfterInsertProcessorFunc(bean)
}
if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
session.cacheInsert(session.Statement.TableName())
}
if table.Version != "" && session.Statement.checkVersion {
verValue, err := table.VersionColumn().ValueOf(bean)
if err != nil {
session.Engine.LogError(err)
} else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
}
}
if table.AutoIncrement == "" {
return res.RowsAffected()
}
var id int64 = 0
id, err = res.LastInsertId()
if err != nil || id <= 0 {
return res.RowsAffected()
}
aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil {
session.Engine.LogError(err)
}
if aiValue == nil || !aiValue.IsValid() /*|| aiValue.Int() != 0*/ || !aiValue.CanSet() {
return res.RowsAffected()
}
var v interface{} = id
switch aiValue.Type().Kind() {
case reflect.Int32:
v = int32(id)
case reflect.Int:
v = int(id)
case reflect.Uint32:
v = uint32(id)
case reflect.Uint64:
v = uint64(id)
case reflect.Uint:
v = uint(id)
}
aiValue.Set(reflect.ValueOf(v))
return res.RowsAffected()
} }
} }
@ -3230,7 +3360,7 @@ func (statement *Statement) convertUpdateSql(sqlStr string) (string, string) {
return "", "" return "", ""
} }
colstrs := statement.JoinColumns(statement.RefTable.PKColumns()) colstrs := statement.JoinColumns(statement.RefTable.PKColumns(), true)
sqls := splitNNoCase(sqlStr, "where", 2) sqls := splitNNoCase(sqlStr, "where", 2)
if len(sqls) != 2 { if len(sqls) != 2 {
if len(sqls) == 1 { if len(sqls) == 1 {
@ -3827,6 +3957,18 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
return res.RowsAffected() return res.RowsAffected()
} }
// saveLastSQL stores executed query information
func (session *Session) saveLastSQL(sql string, args ...interface{}) {
session.lastSQL = sql
session.lastSQLArgs = args
session.Engine.logSQL(sql, args...)
}
// LastSQL returns last query information
func (session *Session) LastSQL() (string, []interface{}) {
return session.lastSQL, session.lastSQLArgs
}
func (s *Session) Sync2(beans ...interface{}) error { func (s *Session) Sync2(beans ...interface{}) error {
engine := s.Engine engine := s.Engine

View File

@ -250,6 +250,10 @@ func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
return fmt.Sprintf("DROP INDEX %v", quote(idxName)) return fmt.Sprintf("DROP INDEX %v", quote(idxName))
} }
func (db *sqlite3) ForUpdateSql(query string) string {
return query
}
/*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) { /*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{tableName} args := []interface{}{tableName}
sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))" sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"

View File

@ -66,6 +66,7 @@ type Statement struct {
UseCache bool UseCache bool
UseAutoTime bool UseAutoTime bool
IsDistinct bool IsDistinct bool
IsForUpdate bool
TableAlias string TableAlias string
allUseBool bool allUseBool bool
checkVersion bool checkVersion bool
@ -104,6 +105,7 @@ func (statement *Statement) Init() {
statement.UseCache = true statement.UseCache = true
statement.UseAutoTime = true statement.UseAutoTime = true
statement.IsDistinct = false statement.IsDistinct = false
statement.IsForUpdate = false
statement.TableAlias = "" statement.TableAlias = ""
statement.selectStr = "" statement.selectStr = ""
statement.allUseBool = false statement.allUseBool = false
@ -432,6 +434,9 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text { if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
continue continue
} }
if col.SQLType.IsJson() {
continue
}
var colName string var colName string
if addedTableName { if addedTableName {
@ -533,6 +538,25 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
if val == nil { if val == nil {
continue continue
} }
} else {
if col.SQLType.IsJson() {
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
engine.LogError(err)
continue
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
engine.LogError(err)
continue
}
val = bytes
}
} else { } else {
engine.autoMapType(fieldValue) engine.autoMapType(fieldValue)
if table, ok := engine.Tables[fieldValue.Type()]; ok { if table, ok := engine.Tables[fieldValue.Type()]; ok {
@ -553,6 +577,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
val = fieldValue.Interface() val = fieldValue.Interface()
} }
} }
}
case reflect.Array, reflect.Slice, reflect.Map: case reflect.Array, reflect.Slice, reflect.Map:
if fieldValue == reflect.Zero(fieldType) { if fieldValue == reflect.Zero(fieldType) {
continue continue
@ -794,6 +819,12 @@ func (statement *Statement) Distinct(columns ...string) *Statement {
return statement return statement
} }
// Generate "SELECT ... FOR UPDATE" statment
func (statement *Statement) ForUpdate() *Statement {
statement.IsForUpdate = true
return statement
}
// replace select // replace select
func (s *Statement) Select(str string) *Statement { func (s *Statement) Select(str string) *Statement {
s.selectStr = str s.selectStr = str
@ -810,6 +841,7 @@ func (statement *Statement) Cols(columns ...string) *Statement {
if strings.Contains(statement.ColumnStr, ".") { if strings.Contains(statement.ColumnStr, ".") {
statement.ColumnStr = strings.Replace(statement.ColumnStr, ".", statement.Engine.Quote("."), -1) statement.ColumnStr = strings.Replace(statement.ColumnStr, ".", statement.Engine.Quote("."), -1)
} }
statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.Quote("*"), "*", -1)
return statement return statement
} }
@ -1179,6 +1211,7 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
distinct = "DISTINCT " distinct = "DISTINCT "
} }
var dialect core.Dialect = statement.Engine.Dialect()
var top string var top string
var mssqlCondi string var mssqlCondi string
/*var orderBy string /*var orderBy string
@ -1190,7 +1223,7 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
if statement.WhereStr != "" { if statement.WhereStr != "" {
whereStr = fmt.Sprintf(" WHERE %v", statement.WhereStr) whereStr = fmt.Sprintf(" WHERE %v", statement.WhereStr)
if statement.ConditionStr != "" { if statement.ConditionStr != "" {
whereStr = fmt.Sprintf("%v %s %v", whereStr, statement.Engine.Dialect().AndStr(), whereStr = fmt.Sprintf("%v %s %v", whereStr, dialect.AndStr(),
statement.ConditionStr) statement.ConditionStr)
} }
} else if statement.ConditionStr != "" { } else if statement.ConditionStr != "" {
@ -1198,7 +1231,7 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
} }
var fromStr string = " FROM " + statement.Engine.Quote(statement.TableName()) var fromStr string = " FROM " + statement.Engine.Quote(statement.TableName())
if statement.TableAlias != "" { if statement.TableAlias != "" {
if statement.Engine.dialect.DBType() == core.ORACLE { if dialect.DBType() == core.ORACLE {
fromStr += " " + statement.Engine.Quote(statement.TableAlias) fromStr += " " + statement.Engine.Quote(statement.TableAlias)
} else { } else {
fromStr += " AS " + statement.Engine.Quote(statement.TableAlias) fromStr += " AS " + statement.Engine.Quote(statement.TableAlias)
@ -1208,7 +1241,7 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr) fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr)
} }
if statement.Engine.dialect.DBType() == core.MSSQL { if dialect.DBType() == core.MSSQL {
if statement.LimitN > 0 { if statement.LimitN > 0 {
top = fmt.Sprintf(" TOP %d ", statement.LimitN) top = fmt.Sprintf(" TOP %d ", statement.LimitN)
} }
@ -1258,17 +1291,20 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
if statement.OrderStr != "" { if statement.OrderStr != "" {
a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr) a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
} }
if statement.Engine.dialect.DBType() != core.MSSQL && statement.Engine.dialect.DBType() != core.ORACLE { if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE {
if statement.Start > 0 { if statement.Start > 0 {
a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start) a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start)
} else if statement.LimitN > 0 { } else if statement.LimitN > 0 {
a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN) a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN)
} }
} else if statement.Engine.dialect.DBType() == core.ORACLE { } else if dialect.DBType() == core.ORACLE {
if statement.Start != 0 || statement.LimitN != 0 { if statement.Start != 0 || statement.LimitN != 0 {
a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start) a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start)
} }
} }
if statement.IsForUpdate {
a = dialect.ForUpdateSql(a)
}
return return
} }

View File

@ -17,7 +17,7 @@ import (
) )
const ( const (
Version string = "0.4.3.0627" Version string = "0.4.3.0824"
) )
func regDrvsNDialects() bool { func regDrvsNDialects() bool {