xorm/statement.go

1244 lines
34 KiB
Go
Raw Normal View History

2015-04-28 08:25:04 +00:00
// Copyright 2015 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.
2013-05-03 07:26:51 +00:00
package xorm
import (
"database/sql/driver"
"encoding/json"
2014-08-18 13:20:18 +00:00
"errors"
2013-12-18 03:31:32 +00:00
"fmt"
"reflect"
"strings"
"time"
2014-01-07 09:33:27 +00:00
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
2013-05-03 07:26:51 +00:00
)
// Statement save all the sql info for executing SQL
2013-05-03 07:26:51 +00:00
type Statement struct {
2018-09-23 02:18:23 +00:00
RefTable *core.Table
Engine *Engine
Start int
LimitN int
idParam *core.PK
OrderStr string
JoinStr string
joinArgs []interface{}
GroupByStr string
HavingStr string
ColumnStr string
selectStr string
useAllCols bool
OmitStr string
AltTableName string
tableName string
RawSQL string
RawParams []interface{}
UseCascade bool
UseAutoJoin bool
StoreEngine string
Charset string
UseCache bool
UseAutoTime bool
noAutoCondition bool
IsDistinct bool
IsForUpdate bool
TableAlias string
allUseBool bool
checkVersion bool
unscoped bool
columnMap columnMap
omitColumnMap columnMap
mustColumnMap map[string]bool
nullableMap map[string]bool
incrColumns map[string]incrParam
decrColumns map[string]decrParam
exprColumns map[string]exprParam
cond builder.Cond
bufferSize int
context ContextCache
2013-05-03 07:26:51 +00:00
}
2017-01-09 01:52:23 +00:00
// Init reset all the statement's fields
2013-05-06 08:01:17 +00:00
func (statement *Statement) Init() {
2013-12-18 03:31:32 +00:00
statement.RefTable = nil
statement.Start = 0
statement.LimitN = 0
statement.OrderStr = ""
statement.UseCascade = true
statement.JoinStr = ""
statement.joinArgs = make([]interface{}, 0)
2013-12-18 03:31:32 +00:00
statement.GroupByStr = ""
statement.HavingStr = ""
statement.ColumnStr = ""
statement.OmitStr = ""
2018-04-11 03:52:16 +00:00
statement.columnMap = columnMap{}
statement.omitColumnMap = columnMap{}
2013-12-18 03:31:32 +00:00
statement.AltTableName = ""
statement.tableName = ""
2017-03-01 08:55:53 +00:00
statement.idParam = nil
2013-12-18 03:31:32 +00:00
statement.RawSQL = ""
statement.RawParams = make([]interface{}, 0)
2014-01-07 09:33:27 +00:00
statement.UseCache = true
2013-12-18 03:31:32 +00:00
statement.UseAutoTime = true
2016-01-02 15:55:01 +00:00
statement.noAutoCondition = false
2013-12-18 03:31:32 +00:00
statement.IsDistinct = false
statement.IsForUpdate = false
2014-11-18 16:41:03 +00:00
statement.TableAlias = ""
statement.selectStr = ""
2013-12-18 03:31:32 +00:00
statement.allUseBool = false
statement.useAllCols = false
statement.mustColumnMap = make(map[string]bool)
statement.nullableMap = make(map[string]bool)
2013-12-18 03:31:32 +00:00
statement.checkVersion = true
statement.unscoped = false
2014-04-18 14:14:15 +00:00
statement.incrColumns = make(map[string]incrParam)
2014-07-15 15:25:24 +00:00
statement.decrColumns = make(map[string]decrParam)
2015-01-28 05:23:01 +00:00
statement.exprColumns = make(map[string]exprParam)
statement.cond = builder.NewCond()
2017-09-19 12:59:41 +00:00
statement.bufferSize = 0
2018-09-23 02:18:23 +00:00
statement.context = nil
2013-05-06 08:01:17 +00:00
}
2016-01-28 08:54:15 +00:00
// NoAutoCondition if you do not want convert bean's field as query condition, then use this function
2016-01-02 15:55:01 +00:00
func (statement *Statement) NoAutoCondition(no ...bool) *Statement {
statement.noAutoCondition = true
if len(no) > 0 {
statement.noAutoCondition = no[0]
}
return statement
}
// Alias set the table alias
func (statement *Statement) Alias(alias string) *Statement {
statement.TableAlias = alias
return statement
}
// SQL adds raw sql statement
func (statement *Statement) SQL(query interface{}, args ...interface{}) *Statement {
switch query.(type) {
case (*builder.Builder):
var err error
statement.RawSQL, statement.RawParams, err = query.(*builder.Builder).ToSQL()
if err != nil {
statement.Engine.logger.Error(err)
}
case string:
statement.RawSQL = query.(string)
statement.RawParams = args
default:
statement.Engine.logger.Error("unsupported sql type")
}
2013-12-18 03:31:32 +00:00
return statement
2013-06-16 03:05:16 +00:00
}
2017-01-09 01:52:23 +00:00
// Where add Where statement
func (statement *Statement) Where(query interface{}, args ...interface{}) *Statement {
return statement.And(query, args...)
2014-11-18 16:41:03 +00:00
}
2017-01-09 01:52:23 +00:00
// And add Where & and statement
func (statement *Statement) And(query interface{}, args ...interface{}) *Statement {
switch query.(type) {
case string:
cond := builder.Expr(query.(string), args...)
statement.cond = statement.cond.And(cond)
case map[string]interface{}:
cond := builder.Eq(query.(map[string]interface{}))
statement.cond = statement.cond.And(cond)
case builder.Cond:
cond := query.(builder.Cond)
statement.cond = statement.cond.And(cond)
for _, v := range args {
if vv, ok := v.(builder.Cond); ok {
statement.cond = statement.cond.And(vv)
}
}
default:
// TODO: not support condition type
}
return statement
}
2017-01-09 01:52:23 +00:00
// Or add Where & Or statement
func (statement *Statement) Or(query interface{}, args ...interface{}) *Statement {
switch query.(type) {
case string:
cond := builder.Expr(query.(string), args...)
statement.cond = statement.cond.Or(cond)
case map[string]interface{}:
cond := builder.Eq(query.(map[string]interface{}))
statement.cond = statement.cond.Or(cond)
case builder.Cond:
cond := query.(builder.Cond)
statement.cond = statement.cond.Or(cond)
for _, v := range args {
if vv, ok := v.(builder.Cond); ok {
statement.cond = statement.cond.Or(vv)
}
}
default:
// TODO: not support condition type
2014-04-29 06:16:53 +00:00
}
2013-12-18 03:31:32 +00:00
return statement
2013-05-03 07:26:51 +00:00
}
2017-01-09 01:52:23 +00:00
// In generate "Where column IN (?) " statement
func (statement *Statement) In(column string, args ...interface{}) *Statement {
in := builder.In(statement.Engine.Quote(column), args...)
statement.cond = statement.cond.And(in)
2013-12-18 03:31:32 +00:00
return statement
}
2017-01-09 01:52:23 +00:00
// NotIn generate "Where column NOT IN (?) " statement
func (statement *Statement) NotIn(column string, args ...interface{}) *Statement {
notIn := builder.NotIn(statement.Engine.Quote(column), args...)
2017-02-24 04:45:33 +00:00
statement.cond = statement.cond.And(notIn)
2013-12-18 03:31:32 +00:00
return statement
}
2017-04-02 10:02:47 +00:00
func (statement *Statement) setRefValue(v reflect.Value) error {
var err error
statement.RefTable, err = statement.Engine.autoMapType(reflect.Indirect(v))
if err != nil {
return err
}
statement.tableName = statement.Engine.TableName(v, true)
2017-04-02 10:02:47 +00:00
return nil
}
func (statement *Statement) setRefBean(bean interface{}) error {
var err error
statement.RefTable, err = statement.Engine.autoMapType(rValue(bean))
if err != nil {
return err
2013-12-18 03:31:32 +00:00
}
statement.tableName = statement.Engine.TableName(bean, true)
return nil
2013-05-19 05:25:52 +00:00
}
2015-12-02 06:54:58 +00:00
// Auto generating update columnes and values according a struct
2018-04-11 04:57:13 +00:00
func (statement *Statement) buildUpdates(bean interface{},
includeVersion, includeUpdated, includeNil,
includeAutoIncr, update bool) ([]string, []interface{}) {
engine := statement.Engine
table := statement.RefTable
allUseBool := statement.allUseBool
useAllCols := statement.useAllCols
mustColumnMap := statement.mustColumnMap
nullableMap := statement.nullableMap
columnMap := statement.columnMap
omitColumnMap := statement.omitColumnMap
unscoped := statement.unscoped
2013-12-18 03:31:32 +00:00
2016-04-07 00:54:02 +00:00
var colNames = make([]string, 0)
2013-12-18 03:31:32 +00:00
var args = make([]interface{}, 0)
2014-01-07 09:33:27 +00:00
for _, col := range table.Columns() {
2013-12-18 03:31:32 +00:00
if !includeVersion && col.IsVersion {
continue
}
2014-05-02 00:48:51 +00:00
if col.IsCreated {
continue
}
2013-12-18 03:31:32 +00:00
if !includeUpdated && col.IsUpdated {
continue
}
2013-12-20 06:53:40 +00:00
if !includeAutoIncr && col.IsAutoIncrement {
continue
}
2015-10-06 14:56:28 +00:00
if col.IsDeleted && !unscoped {
2014-11-03 13:03:12 +00:00
continue
}
2018-04-11 03:52:16 +00:00
if omitColumnMap.contain(col.Name) {
continue
}
if len(columnMap) > 0 && !columnMap.contain(col.Name) {
2015-03-03 07:14:44 +00:00
continue
}
2014-05-23 06:18:45 +00:00
if col.MapType == core.ONLYFROMDB {
continue
}
2014-01-09 06:44:41 +00:00
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
engine.logger.Error(err)
2013-12-20 06:53:40 +00:00
continue
}
2014-01-09 06:44:41 +00:00
fieldValue := *fieldValuePtr
2013-12-18 03:31:32 +00:00
fieldType := reflect.TypeOf(fieldValue.Interface())
2017-08-05 02:46:29 +00:00
if fieldType == nil {
continue
}
2013-12-18 03:31:32 +00:00
2014-03-24 12:41:07 +00:00
requiredField := useAllCols
2014-05-31 04:19:46 +00:00
includeNil := useAllCols
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
if b {
requiredField = true
} else {
continue
}
}
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
if b, ok := getFlagForColumn(nullableMap, col); ok {
if b && col.Nullable && isZero(fieldValue.Interface()) {
var nilValue *int
fieldValue = reflect.ValueOf(nilValue)
fieldType = reflect.TypeOf(fieldValue.Interface())
includeNil = true
}
}
2014-05-05 06:45:42 +00:00
var val interface{}
if fieldValue.CanAddr() {
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
data, err := structConvert.ToDB()
if err != nil {
engine.logger.Error(err)
2014-05-05 06:45:42 +00:00
} else {
val = data
}
2014-05-15 14:32:57 +00:00
goto APPEND
2014-05-05 06:45:42 +00:00
}
}
if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
data, err := structConvert.ToDB()
if err != nil {
engine.logger.Error(err)
2014-05-05 06:45:42 +00:00
} else {
val = data
}
2014-05-15 14:32:57 +00:00
goto APPEND
2014-05-05 06:45:42 +00:00
}
2013-12-18 03:31:32 +00:00
if fieldType.Kind() == reflect.Ptr {
if fieldValue.IsNil() {
if includeNil {
args = append(args, nil)
2014-05-02 00:48:51 +00:00
colNames = append(colNames, fmt.Sprintf("%v=?", engine.Quote(col.Name)))
2013-12-18 03:31:32 +00:00
}
continue
} else if !fieldValue.IsValid() {
continue
} else {
// dereference ptr type to instance type
fieldValue = fieldValue.Elem()
fieldType = reflect.TypeOf(fieldValue.Interface())
requiredField = true
}
}
switch fieldType.Kind() {
case reflect.Bool:
if allUseBool || requiredField {
val = fieldValue.Interface()
} else {
// if a bool in a struct, it will not be as a condition because it default is false,
// please use Where() instead
continue
}
case reflect.String:
if !requiredField && fieldValue.String() == "" {
continue
}
// for MyString, should convert to string or panic
if fieldType.String() != reflect.String.String() {
val = fieldValue.String()
} else {
val = fieldValue.Interface()
}
case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
if !requiredField && fieldValue.Int() == 0 {
continue
}
val = fieldValue.Interface()
case reflect.Float32, reflect.Float64:
if !requiredField && fieldValue.Float() == 0.0 {
continue
}
val = fieldValue.Interface()
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
if !requiredField && fieldValue.Uint() == 0 {
continue
}
t := int64(fieldValue.Uint())
val = reflect.ValueOf(&t).Interface()
2013-12-18 03:31:32 +00:00
case reflect.Struct:
2015-05-26 06:06:54 +00:00
if fieldType.ConvertibleTo(core.TimeType) {
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
2013-12-18 03:31:32 +00:00
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
continue
}
val = engine.formatColTime(col, t)
} else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok {
val, _ = nulType.Value()
2013-12-18 03:31:32 +00:00
} else {
if !col.SQLType.IsJson() {
engine.autoMapType(fieldValue)
if table, ok := engine.Tables[fieldValue.Type()]; ok {
if len(table.PrimaryKeys) == 1 {
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
// fix non-int pk issues
2016-04-27 03:31:02 +00:00
if pkField.IsValid() && (!requiredField && !isZero(pkField.Interface())) {
val = pkField.Interface()
} else {
continue
}
} else {
//TODO: how to handler?
panic("not supported")
}
2013-12-18 03:31:32 +00:00
} else {
val = fieldValue.Interface()
2013-12-18 03:31:32 +00:00
}
} else {
2016-04-27 03:31:02 +00:00
// Blank struct could not be as update data
if requiredField || !isStructZero(fieldValue) {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
panic(fmt.Sprintf("mashal %v failed", fieldValue.Interface()))
}
if col.SQLType.IsText() {
val = string(bytes)
} else if col.SQLType.IsBlob() {
val = bytes
}
} else {
continue
}
2013-12-18 03:31:32 +00:00
}
}
case reflect.Array, reflect.Slice, reflect.Map:
2015-12-02 06:54:58 +00:00
if !requiredField {
if fieldValue == reflect.Zero(fieldType) {
continue
}
2017-03-27 07:45:15 +00:00
if fieldType.Kind() == reflect.Array {
if isArrayValueZero(fieldValue) {
continue
}
} else if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
2015-12-02 06:54:58 +00:00
continue
}
2013-12-18 03:31:32 +00:00
}
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
2013-12-18 03:31:32 +00:00
continue
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
2017-03-27 07:45:15 +00:00
if fieldType.Kind() == reflect.Slice &&
2013-12-18 03:31:32 +00:00
fieldType.Elem().Kind() == reflect.Uint8 {
if fieldValue.Len() > 0 {
val = fieldValue.Bytes()
} else {
continue
}
2017-03-27 07:45:15 +00:00
} else if fieldType.Kind() == reflect.Array &&
fieldType.Elem().Kind() == reflect.Uint8 {
val = fieldValue.Slice(0, 0).Interface()
2013-12-18 03:31:32 +00:00
} else {
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
2013-12-18 03:31:32 +00:00
continue
}
val = bytes
}
} else {
continue
}
default:
val = fieldValue.Interface()
}
2014-05-15 14:32:57 +00:00
APPEND:
2013-12-18 03:31:32 +00:00
args = append(args, val)
2014-05-07 07:56:33 +00:00
if col.IsPrimaryKey && engine.dialect.DBType() == "ql" {
continue
}
colNames = append(colNames, fmt.Sprintf("%v = ?", engine.Quote(col.Name)))
2014-05-02 00:48:51 +00:00
}
return colNames, args
}
func (statement *Statement) needTableName() bool {
return len(statement.JoinStr) > 0
}
func (statement *Statement) colName(col *core.Column, tableName string) string {
if statement.needTableName() {
var nm = tableName
if len(statement.TableAlias) > 0 {
nm = statement.TableAlias
}
return statement.Engine.Quote(nm) + "." + statement.Engine.Quote(col.Name)
}
return statement.Engine.Quote(col.Name)
}
2016-04-07 00:54:02 +00:00
// TableName return current tableName
2013-05-19 05:25:52 +00:00
func (statement *Statement) TableName() string {
2013-12-18 03:31:32 +00:00
if statement.AltTableName != "" {
return statement.AltTableName
}
return statement.tableName
2013-05-19 05:25:52 +00:00
}
2017-01-09 01:52:23 +00:00
// ID generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?"
2016-12-11 04:45:37 +00:00
func (statement *Statement) ID(id interface{}) *Statement {
2013-12-18 03:31:32 +00:00
idValue := reflect.ValueOf(id)
idType := reflect.TypeOf(idValue.Interface())
switch idType {
case ptrPkType:
if pkPtr, ok := (id).(*core.PK); ok {
2017-03-01 08:55:53 +00:00
statement.idParam = pkPtr
return statement
2013-12-18 03:31:32 +00:00
}
case pkType:
if pk, ok := (id).(core.PK); ok {
2017-03-01 08:55:53 +00:00
statement.idParam = &pk
return statement
2013-12-18 03:31:32 +00:00
}
}
switch idType.Kind() {
case reflect.String:
2017-03-01 08:55:53 +00:00
statement.idParam = &core.PK{idValue.Convert(reflect.TypeOf("")).Interface()}
return statement
}
2017-03-01 08:55:53 +00:00
statement.idParam = &core.PK{id}
2013-12-18 03:31:32 +00:00
return statement
2013-05-09 01:56:58 +00:00
}
2013-12-18 03:31:32 +00:00
2017-01-09 01:52:23 +00:00
// Incr Generate "Update ... Set column = column + arg" statement
2014-04-15 04:14:18 +00:00
func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
2014-04-15 01:54:49 +00:00
k := strings.ToLower(column)
2014-04-15 04:14:18 +00:00
if len(arg) > 0 {
2014-04-18 14:14:15 +00:00
statement.incrColumns[k] = incrParam{column, arg[0]}
2014-04-15 04:14:18 +00:00
} else {
2014-04-18 14:14:15 +00:00
statement.incrColumns[k] = incrParam{column, 1}
2014-04-15 04:14:18 +00:00
}
2013-12-18 03:31:32 +00:00
return statement
2013-05-09 01:56:58 +00:00
}
2017-01-09 01:52:23 +00:00
// Decr Generate "Update ... Set column = column - arg" statement
2014-07-15 15:25:24 +00:00
func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
k := strings.ToLower(column)
if len(arg) > 0 {
statement.decrColumns[k] = decrParam{column, arg[0]}
} else {
statement.decrColumns[k] = decrParam{column, 1}
}
return statement
}
2017-01-09 01:52:23 +00:00
// SetExpr Generate "Update ... Set column = {expression}" statement
2015-01-28 06:10:45 +00:00
func (statement *Statement) SetExpr(column string, expression string) *Statement {
2015-01-28 05:23:01 +00:00
k := strings.ToLower(column)
statement.exprColumns[k] = exprParam{column, expression}
return statement
}
2017-01-09 01:52:23 +00:00
// Generate "Update ... Set column = column + arg" statement
2014-04-18 14:14:15 +00:00
func (statement *Statement) getInc() map[string]incrParam {
return statement.incrColumns
2014-04-15 01:54:49 +00:00
}
2014-04-15 02:24:59 +00:00
2017-01-09 01:52:23 +00:00
// Generate "Update ... Set column = column - arg" statement
2014-07-15 15:25:24 +00:00
func (statement *Statement) getDec() map[string]decrParam {
return statement.decrColumns
}
2017-01-09 01:52:23 +00:00
// Generate "Update ... Set column = {expression}" statement
2015-01-28 05:23:01 +00:00
func (statement *Statement) getExpr() map[string]exprParam {
return statement.exprColumns
}
2014-08-18 13:20:18 +00:00
func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
newColumns := make([]string, 0)
for _, col := range columns {
2014-11-21 15:40:59 +00:00
col = strings.Replace(col, "`", "", -1)
col = strings.Replace(col, statement.Engine.QuoteStr(), "", -1)
2014-08-18 13:20:18 +00:00
ccols := strings.Split(col, ",")
for _, c := range ccols {
fields := strings.Split(strings.TrimSpace(c), ".")
if len(fields) == 1 {
2016-03-06 04:05:20 +00:00
newColumns = append(newColumns, statement.Engine.quote(fields[0]))
2014-08-18 13:20:18 +00:00
} else if len(fields) == 2 {
2016-03-06 04:05:20 +00:00
newColumns = append(newColumns, statement.Engine.quote(fields[0])+"."+
statement.Engine.quote(fields[1]))
2014-08-18 13:20:18 +00:00
} else {
panic(errors.New("unwanted colnames"))
}
}
}
return newColumns
}
2017-07-24 14:09:47 +00:00
func (statement *Statement) colmap2NewColsWithQuote() []string {
2018-04-11 03:52:16 +00:00
newColumns := make([]string, len(statement.columnMap), len(statement.columnMap))
copy(newColumns, statement.columnMap)
for i := 0; i < len(statement.columnMap); i++ {
newColumns[i] = statement.Engine.Quote(newColumns[i])
2017-07-24 14:09:47 +00:00
}
return newColumns
}
// Distinct generates "DISTINCT col1, col2 " statement
2013-11-22 06:11:07 +00:00
func (statement *Statement) Distinct(columns ...string) *Statement {
2013-12-18 03:31:32 +00:00
statement.IsDistinct = true
statement.Cols(columns...)
return statement
}
// ForUpdate generates "SELECT ... FOR UPDATE" statement
func (statement *Statement) ForUpdate() *Statement {
statement.IsForUpdate = true
return statement
}
2016-04-07 00:54:02 +00:00
// Select replace select
func (statement *Statement) Select(str string) *Statement {
statement.selectStr = str
return statement
}
2016-04-07 00:54:02 +00:00
// Cols generate "col1, col2" statement
2013-11-22 06:11:07 +00:00
func (statement *Statement) Cols(columns ...string) *Statement {
2016-03-06 04:05:20 +00:00
cols := col2NewCols(columns...)
for _, nc := range cols {
2018-05-04 05:09:54 +00:00
statement.columnMap.add(nc)
2013-12-18 03:31:32 +00:00
}
2016-03-06 04:05:20 +00:00
2017-07-24 14:09:47 +00:00
newColumns := statement.colmap2NewColsWithQuote()
2018-04-11 03:52:16 +00:00
2016-03-06 04:05:20 +00:00
statement.ColumnStr = strings.Join(newColumns, ", ")
statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.quote("*"), "*", -1)
2013-12-18 03:31:32 +00:00
return statement
}
2016-04-07 00:54:02 +00:00
// AllCols update use only: update all columns
2014-03-24 12:41:07 +00:00
func (statement *Statement) AllCols() *Statement {
statement.useAllCols = true
return statement
}
2016-04-07 00:54:02 +00:00
// MustCols update use only: must update columns
func (statement *Statement) MustCols(columns ...string) *Statement {
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
statement.mustColumnMap[strings.ToLower(nc)] = true
}
return statement
}
2016-04-07 00:54:02 +00:00
// UseBool indicates that use bool fields as update contents and query contiditions
2013-11-22 06:11:07 +00:00
func (statement *Statement) UseBool(columns ...string) *Statement {
2013-12-18 03:31:32 +00:00
if len(columns) > 0 {
statement.MustCols(columns...)
2013-12-18 03:31:32 +00:00
} else {
statement.allUseBool = true
}
return statement
}
2016-04-07 00:54:02 +00:00
// Omit do not use the columns
func (statement *Statement) Omit(columns ...string) {
2013-12-18 03:31:32 +00:00
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
2018-04-11 03:52:16 +00:00
statement.omitColumnMap = append(statement.omitColumnMap, nc)
2013-12-18 03:31:32 +00:00
}
statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
}
2016-04-07 00:54:02 +00:00
// Nullable Update use only: update columns to null when value is nullable and zero-value
func (statement *Statement) Nullable(columns ...string) {
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
statement.nullableMap[strings.ToLower(nc)] = true
}
}
2016-04-07 00:54:02 +00:00
// Top generate LIMIT limit statement
2013-11-20 17:26:07 +00:00
func (statement *Statement) Top(limit int) *Statement {
2013-12-18 03:31:32 +00:00
statement.Limit(limit)
return statement
2013-11-20 17:26:07 +00:00
}
2016-04-07 00:54:02 +00:00
// Limit generate LIMIT start, limit statement
2013-11-22 06:11:07 +00:00
func (statement *Statement) Limit(limit int, start ...int) *Statement {
2013-12-18 03:31:32 +00:00
statement.LimitN = limit
if len(start) > 0 {
statement.Start = start[0]
}
return statement
2013-05-03 07:26:51 +00:00
}
2016-04-07 00:54:02 +00:00
// OrderBy generate "Order By order" statement
2013-11-22 06:11:07 +00:00
func (statement *Statement) OrderBy(order string) *Statement {
if len(statement.OrderStr) > 0 {
2014-08-18 13:20:18 +00:00
statement.OrderStr += ", "
}
2014-10-09 12:57:57 +00:00
statement.OrderStr += order
2013-12-18 03:31:32 +00:00
return statement
2013-05-03 07:26:51 +00:00
}
2016-04-07 00:54:02 +00:00
// Desc generate `ORDER BY xx DESC`
2014-08-18 13:20:18 +00:00
func (statement *Statement) Desc(colNames ...string) *Statement {
var buf builder.StringBuilder
if len(statement.OrderStr) > 0 {
fmt.Fprint(&buf, statement.OrderStr, ", ")
2014-08-18 13:20:18 +00:00
}
newColNames := statement.col2NewColsWithQuote(colNames...)
2015-10-27 07:41:13 +00:00
fmt.Fprintf(&buf, "%v DESC", strings.Join(newColNames, " DESC, "))
statement.OrderStr = buf.String()
2014-08-18 13:20:18 +00:00
return statement
}
2016-04-07 00:54:02 +00:00
// Asc provide asc order by query condition, the input parameters are columns.
2014-08-18 13:20:18 +00:00
func (statement *Statement) Asc(colNames ...string) *Statement {
var buf builder.StringBuilder
if len(statement.OrderStr) > 0 {
fmt.Fprint(&buf, statement.OrderStr, ", ")
2014-08-18 13:20:18 +00:00
}
newColNames := statement.col2NewColsWithQuote(colNames...)
2015-10-27 07:41:13 +00:00
fmt.Fprintf(&buf, "%v ASC", strings.Join(newColNames, " ASC, "))
statement.OrderStr = buf.String()
2014-08-18 13:20:18 +00:00
return statement
}
// Table tempororily set table name, the parameter could be a string or a pointer of struct
func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
v := rValue(tableNameOrBean)
t := v.Type()
if t.Kind() == reflect.Struct {
var err error
statement.RefTable, err = statement.Engine.autoMapType(v)
if err != nil {
statement.Engine.logger.Error(err)
return statement
}
}
statement.AltTableName = statement.Engine.TableName(tableNameOrBean, true)
return statement
}
2016-04-07 00:54:02 +00:00
// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
var buf builder.StringBuilder
if len(statement.JoinStr) > 0 {
2016-04-07 00:54:02 +00:00
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
} else {
2016-04-07 00:54:02 +00:00
fmt.Fprintf(&buf, "%v JOIN ", joinOP)
}
tbName := statement.Engine.TableName(tablename, true)
fmt.Fprintf(&buf, "%s ON %v", tbName, condition)
statement.JoinStr = buf.String()
statement.joinArgs = append(statement.joinArgs, args...)
2013-12-18 03:31:32 +00:00
return statement
2013-05-06 08:01:17 +00:00
}
2016-04-07 00:54:02 +00:00
// GroupBy generate "Group By keys" statement
2013-11-22 06:11:07 +00:00
func (statement *Statement) GroupBy(keys string) *Statement {
2013-12-18 03:31:32 +00:00
statement.GroupByStr = keys
return statement
2013-05-06 08:01:17 +00:00
}
2016-04-07 00:54:02 +00:00
// Having generate "Having conditions" statement
2013-11-22 06:11:07 +00:00
func (statement *Statement) Having(conditions string) *Statement {
2013-12-18 03:31:32 +00:00
statement.HavingStr = fmt.Sprintf("HAVING %v", conditions)
return statement
2013-05-03 07:26:51 +00:00
}
2016-04-07 00:54:02 +00:00
// Unscoped always disable struct tag "deleted"
func (statement *Statement) Unscoped() *Statement {
statement.unscoped = true
return statement
}
func (statement *Statement) genColumnStr() string {
if statement.RefTable == nil {
return ""
}
var buf builder.StringBuilder
columns := statement.RefTable.Columns()
for _, col := range columns {
2018-04-11 03:52:16 +00:00
if statement.omitColumnMap.contain(col.Name) {
continue
}
if len(statement.columnMap) > 0 && !statement.columnMap.contain(col.Name) {
continue
2013-12-18 03:31:32 +00:00
}
2014-01-09 06:44:41 +00:00
if col.MapType == core.ONLYTODB {
2013-12-18 03:31:32 +00:00
continue
}
2014-04-29 06:16:53 +00:00
if buf.Len() != 0 {
buf.WriteString(", ")
}
2014-04-29 06:16:53 +00:00
if statement.JoinStr != "" {
2014-11-18 16:41:03 +00:00
if statement.TableAlias != "" {
buf.WriteString(statement.TableAlias)
2014-11-18 16:41:03 +00:00
} else {
buf.WriteString(statement.TableName())
2014-04-29 06:16:53 +00:00
}
buf.WriteString(".")
}
statement.Engine.QuoteTo(&buf, col.Name)
2013-12-18 03:31:32 +00:00
}
return buf.String()
2013-05-19 05:25:52 +00:00
}
2013-12-17 01:38:20 +00:00
func (statement *Statement) genCreateTableSQL() string {
return statement.Engine.dialect.CreateTableSql(statement.RefTable, statement.TableName(),
2014-01-07 09:33:27 +00:00
statement.StoreEngine, statement.Charset)
}
func (statement *Statement) genIndexSQL() []string {
var sqls []string
tbName := statement.TableName()
for _, index := range statement.RefTable.Indexes {
2014-01-07 09:33:27 +00:00
if index.Type == core.IndexType {
sql := statement.Engine.dialect.CreateIndexSql(tbName, index)
/*idxTBName := strings.Replace(tbName, ".", "_", -1)
idxTBName = strings.Replace(idxTBName, `"`, "", -1)
sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(idxTBName, idxName)),
quote(tbName), quote(strings.Join(index.Cols, quote(","))))*/
2013-12-18 03:31:32 +00:00
sqls = append(sqls, sql)
}
}
return sqls
}
func uniqueName(tableName, uqeName string) string {
2013-12-18 03:31:32 +00:00
return fmt.Sprintf("UQE_%v_%v", tableName, uqeName)
}
func (statement *Statement) genUniqueSQL() []string {
var sqls []string
tbName := statement.TableName()
for _, index := range statement.RefTable.Indexes {
2014-04-17 02:13:16 +00:00
if index.Type == core.UniqueType {
sql := statement.Engine.dialect.CreateIndexSql(tbName, index)
2013-12-18 03:31:32 +00:00
sqls = append(sqls, sql)
}
}
return sqls
2013-05-19 05:25:52 +00:00
}
func (statement *Statement) genDelIndexSQL() []string {
var sqls []string
tbName := statement.TableName()
idxPrefixName := strings.Replace(tbName, `"`, "", -1)
idxPrefixName = strings.Replace(idxPrefixName, `.`, "_", -1)
for idxName, index := range statement.RefTable.Indexes {
2013-12-18 03:31:32 +00:00
var rIdxName string
2014-01-07 09:33:27 +00:00
if index.Type == core.UniqueType {
rIdxName = uniqueName(idxPrefixName, idxName)
2014-01-07 09:33:27 +00:00
} else if index.Type == core.IndexType {
rIdxName = indexName(idxPrefixName, idxName)
2013-12-18 03:31:32 +00:00
}
sql := fmt.Sprintf("DROP INDEX %v", statement.Engine.Quote(statement.Engine.TableName(rIdxName, true)))
if statement.Engine.dialect.IndexOnTable() {
sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(tbName))
2013-12-18 03:31:32 +00:00
}
sqls = append(sqls, sql)
}
return sqls
2013-09-26 07:19:39 +00:00
}
func (statement *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) {
quote := statement.Engine.Quote
2017-11-20 07:20:28 +00:00
sql := fmt.Sprintf("ALTER TABLE %v ADD %v", quote(statement.TableName()),
col.String(statement.Engine.dialect))
2017-11-20 07:20:28 +00:00
if statement.Engine.dialect.DBType() == core.MYSQL && len(col.Comment) > 0 {
sql += " COMMENT '" + col.Comment + "'"
}
sql += ";"
2016-09-19 03:13:40 +00:00
return sql, []interface{}{}
}
2013-05-19 05:25:52 +00:00
2016-09-19 03:13:40 +00:00
func (statement *Statement) buildConds(table *core.Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, addedTableName bool) (builder.Cond, error) {
2017-06-15 12:09:46 +00:00
return statement.Engine.buildConds(table, bean, includeVersion, includeUpdated, includeNil, includeAutoIncr, statement.allUseBool, statement.useAllCols,
2016-09-19 03:13:40 +00:00
statement.unscoped, statement.mustColumnMap, statement.TableName(), statement.TableAlias, addedTableName)
}
func (statement *Statement) mergeConds(bean interface{}) error {
2016-01-02 15:55:01 +00:00
if !statement.noAutoCondition {
var addedTableName = (len(statement.JoinStr) > 0)
autoCond, err := statement.buildConds(statement.RefTable, bean, true, true, false, true, addedTableName)
if err != nil {
return err
}
statement.cond = statement.cond.And(autoCond)
2016-01-02 15:55:01 +00:00
}
2013-05-19 05:25:52 +00:00
2017-06-08 11:38:52 +00:00
if err := statement.processIDParam(); err != nil {
return err
}
return nil
}
func (statement *Statement) genConds(bean interface{}) (string, []interface{}, error) {
if err := statement.mergeConds(bean); err != nil {
2017-06-08 11:38:52 +00:00
return "", nil, err
}
return builder.ToSQL(statement.cond)
2016-09-19 03:13:40 +00:00
}
2017-06-08 11:38:52 +00:00
func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}, error) {
2017-04-01 02:09:00 +00:00
v := rValue(bean)
isStruct := v.Kind() == reflect.Struct
if isStruct {
statement.setRefBean(bean)
2017-04-01 02:09:00 +00:00
}
2016-09-19 03:13:40 +00:00
var columnStr = statement.ColumnStr
if len(statement.selectStr) > 0 {
columnStr = statement.selectStr
2014-05-23 06:18:45 +00:00
} else {
// TODO: always generate column names, not use * even if join
if len(statement.JoinStr) == 0 {
if len(columnStr) == 0 {
if len(statement.GroupByStr) > 0 {
2018-08-09 06:37:44 +00:00
columnStr = statement.Engine.quoteColumns(statement.GroupByStr)
} else {
columnStr = statement.genColumnStr()
}
}
} else {
if len(columnStr) == 0 {
if len(statement.GroupByStr) > 0 {
2018-08-09 06:37:44 +00:00
columnStr = statement.Engine.quoteColumns(statement.GroupByStr)
}
2015-03-12 14:26:45 +00:00
}
2014-05-23 06:18:45 +00:00
}
2013-12-18 03:31:32 +00:00
}
2014-05-15 14:32:57 +00:00
2017-04-01 02:09:00 +00:00
if len(columnStr) == 0 {
columnStr = "*"
}
if isStruct {
if err := statement.mergeConds(bean); err != nil {
return "", nil, err
}
} else {
if err := statement.processIDParam(); err != nil {
return "", nil, err
}
2017-06-08 11:38:52 +00:00
}
condSQL, condArgs, err := builder.ToSQL(statement.cond)
2017-06-08 11:38:52 +00:00
if err != nil {
return "", nil, err
}
sqlStr, err := statement.genSelectSQL(columnStr, condSQL, true, true)
2017-06-08 11:38:52 +00:00
if err != nil {
return "", nil, err
2017-04-01 02:09:00 +00:00
}
2017-06-08 11:38:52 +00:00
return sqlStr, append(statement.joinArgs, condArgs...), nil
2013-05-19 05:25:52 +00:00
}
2017-07-25 08:50:20 +00:00
func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interface{}, error) {
var condSQL string
var condArgs []interface{}
var err error
if len(beans) > 0 {
statement.setRefBean(beans[0])
2017-07-25 08:50:20 +00:00
condSQL, condArgs, err = statement.genConds(beans[0])
} else {
condSQL, condArgs, err = builder.ToSQL(statement.cond)
}
2017-06-08 11:38:52 +00:00
if err != nil {
return "", nil, err
}
2016-12-11 04:45:37 +00:00
var selectSQL = statement.selectStr
if len(selectSQL) <= 0 {
2016-09-29 06:13:15 +00:00
if statement.IsDistinct {
2016-12-11 04:45:37 +00:00
selectSQL = fmt.Sprintf("count(DISTINCT %s)", statement.ColumnStr)
2016-12-10 02:04:48 +00:00
} else {
2016-12-11 04:45:37 +00:00
selectSQL = "count(*)"
2016-09-29 06:13:15 +00:00
}
2016-09-29 06:10:03 +00:00
}
sqlStr, err := statement.genSelectSQL(selectSQL, condSQL, false, false)
2017-06-08 11:38:52 +00:00
if err != nil {
return "", nil, err
}
return sqlStr, append(statement.joinArgs, condArgs...), nil
2013-12-11 08:27:33 +00:00
}
2017-06-08 11:38:52 +00:00
func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) {
statement.setRefBean(bean)
2016-07-07 14:34:43 +00:00
var sumStrs = make([]string, 0, len(columns))
for _, colName := range columns {
2017-04-17 07:52:52 +00:00
if !strings.Contains(colName, " ") && !strings.Contains(colName, "(") {
2017-04-14 02:49:02 +00:00
colName = statement.Engine.Quote(colName)
}
sumStrs = append(sumStrs, fmt.Sprintf("COALESCE(sum(%s),0)", colName))
2016-07-07 14:34:43 +00:00
}
2017-04-14 02:49:02 +00:00
sumSelect := strings.Join(sumStrs, ", ")
2016-09-19 03:13:40 +00:00
2017-06-08 11:38:52 +00:00
condSQL, condArgs, err := statement.genConds(bean)
if err != nil {
return "", nil, err
}
sqlStr, err := statement.genSelectSQL(sumSelect, condSQL, true, true)
2017-06-08 11:38:52 +00:00
if err != nil {
return "", nil, err
}
2016-09-19 03:13:40 +00:00
2017-06-08 11:38:52 +00:00
return sqlStr, append(statement.joinArgs, condArgs...), nil
2016-07-07 14:34:43 +00:00
}
func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, needOrderBy bool) (string, error) {
var (
distinct string
dialect = statement.Engine.Dialect()
quote = statement.Engine.Quote
fromStr = " FROM "
top, mssqlCondi, whereStr string
)
2017-03-11 13:24:37 +00:00
if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
2013-12-18 03:31:32 +00:00
distinct = "DISTINCT "
}
if len(condSQL) > 0 {
whereStr = " WHERE " + condSQL
2014-05-06 03:11:44 +00:00
}
2017-04-14 05:55:55 +00:00
if dialect.DBType() == core.MSSQL && strings.Contains(statement.TableName(), "..") {
fromStr += statement.TableName()
} else {
fromStr += quote(statement.TableName())
}
2014-11-18 16:41:03 +00:00
if statement.TableAlias != "" {
2015-08-30 11:23:46 +00:00
if dialect.DBType() == core.ORACLE {
2016-01-28 08:54:15 +00:00
fromStr += " " + quote(statement.TableAlias)
} else {
2016-01-28 08:54:15 +00:00
fromStr += " AS " + quote(statement.TableAlias)
}
2014-11-18 16:41:03 +00:00
}
2014-05-06 03:11:44 +00:00
if statement.JoinStr != "" {
fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr)
}
2015-08-30 11:23:46 +00:00
if dialect.DBType() == core.MSSQL {
2014-05-06 06:19:37 +00:00
if statement.LimitN > 0 {
top = fmt.Sprintf(" TOP %d ", statement.LimitN)
}
2014-05-06 03:11:44 +00:00
if statement.Start > 0 {
2016-10-10 07:07:12 +00:00
var column string
2014-05-06 03:11:44 +00:00
if len(statement.RefTable.PKColumns()) == 0 {
for _, index := range statement.RefTable.Indexes {
if len(index.Cols) == 1 {
column = index.Cols[0]
break
}
}
if len(column) == 0 {
column = statement.RefTable.ColumnsSeq()[0]
}
2016-10-10 07:07:12 +00:00
} else {
column = statement.RefTable.PKColumns()[0].Name
2014-05-06 03:11:44 +00:00
}
2016-10-10 07:07:12 +00:00
if statement.needTableName() {
if len(statement.TableAlias) > 0 {
column = statement.TableAlias + "." + column
} else {
column = statement.TableName() + "." + column
}
}
2015-01-13 09:17:34 +00:00
var orderStr string
if needOrderBy && len(statement.OrderStr) > 0 {
2015-01-13 09:31:08 +00:00
orderStr = " ORDER BY " + statement.OrderStr
2015-01-13 09:17:34 +00:00
}
2015-01-14 07:04:48 +00:00
var groupStr string
if len(statement.GroupByStr) > 0 {
groupStr = " GROUP BY " + statement.GroupByStr
}
mssqlCondi = fmt.Sprintf("(%s NOT IN (SELECT TOP %d %s%s%s%s%s))",
column, statement.Start, column, fromStr, whereStr, orderStr, groupStr)
2014-05-06 03:11:44 +00:00
}
}
var buf builder.StringBuilder
fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
if len(mssqlCondi) > 0 {
if len(whereStr) > 0 {
fmt.Fprint(&buf, " AND ", mssqlCondi)
2014-05-06 06:19:37 +00:00
} else {
fmt.Fprint(&buf, " WHERE ", mssqlCondi)
2014-05-06 06:19:37 +00:00
}
2013-12-18 03:31:32 +00:00
}
if statement.GroupByStr != "" {
fmt.Fprint(&buf, " GROUP BY ", statement.GroupByStr)
2013-12-18 03:31:32 +00:00
}
if statement.HavingStr != "" {
fmt.Fprint(&buf, " ", statement.HavingStr)
2013-12-18 03:31:32 +00:00
}
if needOrderBy && statement.OrderStr != "" {
fmt.Fprint(&buf, " ORDER BY ", statement.OrderStr)
2013-12-18 03:31:32 +00:00
}
2018-02-23 02:24:40 +00:00
if needLimit {
if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE {
if statement.Start > 0 {
fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", statement.LimitN, statement.Start)
2018-02-23 02:24:40 +00:00
} else if statement.LimitN > 0 {
fmt.Fprint(&buf, " LIMIT ", statement.LimitN)
2018-02-23 02:24:40 +00:00
}
} else if dialect.DBType() == core.ORACLE {
if statement.Start != 0 || statement.LimitN != 0 {
oldString := buf.String()
buf.Reset()
fmt.Fprintf(&buf, "SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d",
columnStr, columnStr, oldString, statement.Start+statement.LimitN, statement.Start)
2018-02-23 02:24:40 +00:00
}
}
2013-12-18 03:31:32 +00:00
}
if statement.IsForUpdate {
return dialect.ForUpdateSql(buf.String()), nil
}
2013-12-20 06:53:40 +00:00
return buf.String(), nil
2013-05-03 07:26:51 +00:00
}
2013-12-17 01:38:20 +00:00
2017-06-08 11:38:52 +00:00
func (statement *Statement) processIDParam() error {
if statement.idParam == nil || statement.RefTable == nil {
2017-06-08 11:38:52 +00:00
return nil
}
if len(statement.RefTable.PrimaryKeys) != len(*statement.idParam) {
return fmt.Errorf("ID condition is error, expect %d primarykeys, there are %d",
len(statement.RefTable.PrimaryKeys),
len(*statement.idParam),
)
2016-09-19 03:13:40 +00:00
}
for i, col := range statement.RefTable.PKColumns() {
var colName = statement.colName(col, statement.TableName())
2017-06-08 11:38:52 +00:00
statement.cond = statement.cond.And(builder.Eq{colName: (*(statement.idParam))[i]})
2013-12-18 03:31:32 +00:00
}
2017-06-08 11:38:52 +00:00
return nil
2013-12-17 01:38:20 +00:00
}
2016-05-13 10:09:11 +00:00
2016-09-19 03:13:40 +00:00
func (statement *Statement) joinColumns(cols []*core.Column, includeTableName bool) string {
2016-05-13 10:09:11 +00:00
var colnames = make([]string, len(cols))
for i, col := range cols {
if includeTableName {
colnames[i] = statement.Engine.Quote(statement.TableName()) +
"." + statement.Engine.Quote(col.Name)
} else {
colnames[i] = statement.Engine.Quote(col.Name)
}
}
return strings.Join(colnames, ", ")
}
2016-09-19 03:13:40 +00:00
func (statement *Statement) convertIDSQL(sqlStr string) string {
2016-05-13 10:09:11 +00:00
if statement.RefTable != nil {
cols := statement.RefTable.PKColumns()
if len(cols) == 0 {
return ""
}
2016-09-19 03:13:40 +00:00
colstrs := statement.joinColumns(cols, false)
2016-05-13 10:09:11 +00:00
sqls := splitNNoCase(sqlStr, " from ", 2)
if len(sqls) != 2 {
return ""
}
2016-09-19 03:13:40 +00:00
2016-12-01 06:48:40 +00:00
var top string
if statement.LimitN > 0 && statement.Engine.dialect.DBType() == core.MSSQL {
top = fmt.Sprintf("TOP %d ", statement.LimitN)
}
newsql := fmt.Sprintf("SELECT %s%s FROM %v", top, colstrs, sqls[1])
return newsql
2016-05-13 10:09:11 +00:00
}
return ""
}
func (statement *Statement) convertUpdateSQL(sqlStr string) (string, string) {
if statement.RefTable == nil || len(statement.RefTable.PrimaryKeys) != 1 {
return "", ""
}
2016-09-19 03:13:40 +00:00
colstrs := statement.joinColumns(statement.RefTable.PKColumns(), true)
2016-05-13 10:09:11 +00:00
sqls := splitNNoCase(sqlStr, "where", 2)
if len(sqls) != 2 {
if len(sqls) == 1 {
return sqls[0], fmt.Sprintf("SELECT %v FROM %v",
colstrs, statement.Engine.Quote(statement.TableName()))
}
return "", ""
}
var whereStr = sqls[1]
//TODO: for postgres only, if any other database?
var paraStr string
if statement.Engine.dialect.DBType() == core.POSTGRES {
paraStr = "$"
} else if statement.Engine.dialect.DBType() == core.MSSQL {
paraStr = ":"
}
if paraStr != "" {
if strings.Contains(sqls[1], paraStr) {
dollers := strings.Split(sqls[1], paraStr)
whereStr = dollers[0]
for i, c := range dollers[1:] {
ccs := strings.SplitN(c, " ", 2)
whereStr += fmt.Sprintf(paraStr+"%v %v", i+1, ccs[1])
}
}
}
return sqls[0], fmt.Sprintf("SELECT %v FROM %v WHERE %v",
colstrs, statement.Engine.Quote(statement.TableName()),
whereStr)
}