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.
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
package statements
|
2013-05-03 07:26:51 +00:00
|
|
|
|
|
|
|
import (
|
2015-07-20 03:23:29 +00:00
|
|
|
"database/sql/driver"
|
2020-02-28 12:29:08 +00:00
|
|
|
"errors"
|
2013-12-18 03:31:32 +00:00
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2014-01-07 09:33:27 +00:00
|
|
|
|
2019-06-17 05:38:13 +00:00
|
|
|
"xorm.io/builder"
|
2020-02-28 12:29:08 +00:00
|
|
|
"xorm.io/xorm/contexts"
|
2020-02-27 03:58:31 +00:00
|
|
|
"xorm.io/xorm/convert"
|
2020-02-24 08:53:18 +00:00
|
|
|
"xorm.io/xorm/dialects"
|
2020-02-28 12:29:08 +00:00
|
|
|
"xorm.io/xorm/internal/json"
|
2020-02-26 12:45:10 +00:00
|
|
|
"xorm.io/xorm/internal/utils"
|
2020-02-24 08:53:18 +00:00
|
|
|
"xorm.io/xorm/schemas"
|
2020-02-28 12:29:08 +00:00
|
|
|
"xorm.io/xorm/tags"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// ErrConditionType condition type unsupported
|
|
|
|
ErrConditionType = errors.New("Unsupported condition type")
|
|
|
|
// ErrUnSupportedSQLType parameter of SQL is not supported
|
|
|
|
ErrUnSupportedSQLType = errors.New("Unsupported sql type")
|
|
|
|
// ErrUnSupportedType unsupported error
|
|
|
|
ErrUnSupportedType = errors.New("Unsupported type error")
|
|
|
|
// ErrTableNotFound table not found error
|
|
|
|
ErrTableNotFound = errors.New("Table not found")
|
2013-05-03 07:26:51 +00:00
|
|
|
)
|
|
|
|
|
2016-03-29 01:17:06 +00:00
|
|
|
// Statement save all the sql info for executing SQL
|
2013-05-03 07:26:51 +00:00
|
|
|
type Statement struct {
|
2020-02-28 12:29:08 +00:00
|
|
|
RefTable *schemas.Table
|
|
|
|
dialect dialects.Dialect
|
|
|
|
//Engine *Engine
|
|
|
|
defaultTimeZone *time.Location
|
|
|
|
tagParser *tags.Parser
|
2016-01-02 15:55:01 +00:00
|
|
|
Start int
|
2020-01-20 08:22:06 +00:00
|
|
|
LimitN *int
|
2020-02-24 08:53:18 +00:00
|
|
|
idParam *schemas.PK
|
2016-01-02 15:55:01 +00:00
|
|
|
OrderStr string
|
|
|
|
JoinStr string
|
2016-03-29 01:17:06 +00:00
|
|
|
joinArgs []interface{}
|
2016-01-02 15:55:01 +00:00
|
|
|
GroupByStr string
|
|
|
|
HavingStr string
|
2020-02-28 12:29:08 +00:00
|
|
|
SelectStr string
|
2016-01-02 15:55:01 +00:00
|
|
|
useAllCols bool
|
|
|
|
AltTableName string
|
2016-07-09 00:15:53 +00:00
|
|
|
tableName string
|
2016-01-02 15:55:01 +00:00
|
|
|
RawSQL string
|
|
|
|
RawParams []interface{}
|
|
|
|
UseCascade bool
|
|
|
|
UseAutoJoin bool
|
|
|
|
StoreEngine string
|
|
|
|
Charset string
|
|
|
|
UseCache bool
|
|
|
|
UseAutoTime bool
|
2020-02-28 12:29:08 +00:00
|
|
|
NoAutoCondition bool
|
2016-01-02 15:55:01 +00:00
|
|
|
IsDistinct bool
|
|
|
|
IsForUpdate bool
|
|
|
|
TableAlias string
|
|
|
|
allUseBool bool
|
2020-02-28 12:29:08 +00:00
|
|
|
CheckVersion bool
|
2016-01-02 15:55:01 +00:00
|
|
|
unscoped bool
|
2020-02-28 12:29:08 +00:00
|
|
|
ColumnMap columnMap
|
|
|
|
OmitColumnMap columnMap
|
|
|
|
MustColumnMap map[string]bool
|
|
|
|
NullableMap map[string]bool
|
|
|
|
IncrColumns exprParams
|
|
|
|
DecrColumns exprParams
|
|
|
|
ExprColumns exprParams
|
2016-09-17 12:04:52 +00:00
|
|
|
cond builder.Cond
|
2020-02-28 12:29:08 +00:00
|
|
|
BufferSize int
|
|
|
|
Context contexts.ContextCache
|
|
|
|
LastError error
|
2013-05-03 07:26:51 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
// NewStatement creates a new statement
|
|
|
|
func NewStatement(dialect dialects.Dialect, tagParser *tags.Parser, defaultTimeZone *time.Location) *Statement {
|
2020-02-27 00:34:16 +00:00
|
|
|
statement := &Statement{
|
2020-02-28 12:29:08 +00:00
|
|
|
dialect: dialect,
|
|
|
|
tagParser: tagParser,
|
|
|
|
defaultTimeZone: defaultTimeZone,
|
2020-02-27 00:34:16 +00:00
|
|
|
}
|
|
|
|
statement.Reset()
|
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) SetTableName(tableName string) {
|
|
|
|
statement.tableName = tableName
|
|
|
|
}
|
|
|
|
|
2020-02-27 00:34:16 +00:00
|
|
|
func (statement *Statement) omitStr() string {
|
2020-02-28 12:29:08 +00:00
|
|
|
return statement.dialect.Quoter().Join(statement.OmitColumnMap, " ,")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (statement *Statement) SetContextCache(ctxCache contexts.ContextCache) {
|
|
|
|
statement.Context = ctxCache
|
2020-02-27 00:34:16 +00:00
|
|
|
}
|
|
|
|
|
2017-01-09 01:52:23 +00:00
|
|
|
// Init reset all the statement's fields
|
2020-02-27 00:34:16 +00:00
|
|
|
func (statement *Statement) Reset() {
|
2013-12-18 03:31:32 +00:00
|
|
|
statement.RefTable = nil
|
|
|
|
statement.Start = 0
|
2020-01-20 08:22:06 +00:00
|
|
|
statement.LimitN = nil
|
2013-12-18 03:31:32 +00:00
|
|
|
statement.OrderStr = ""
|
|
|
|
statement.UseCascade = true
|
|
|
|
statement.JoinStr = ""
|
2016-03-29 01:17:06 +00:00
|
|
|
statement.joinArgs = make([]interface{}, 0)
|
2013-12-18 03:31:32 +00:00
|
|
|
statement.GroupByStr = ""
|
|
|
|
statement.HavingStr = ""
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.ColumnMap = columnMap{}
|
|
|
|
statement.OmitColumnMap = columnMap{}
|
2013-12-18 03:31:32 +00:00
|
|
|
statement.AltTableName = ""
|
2016-07-09 00:15:53 +00:00
|
|
|
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
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.NoAutoCondition = false
|
2013-12-18 03:31:32 +00:00
|
|
|
statement.IsDistinct = false
|
2015-08-28 07:54:19 +00:00
|
|
|
statement.IsForUpdate = false
|
2014-11-18 16:41:03 +00:00
|
|
|
statement.TableAlias = ""
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.SelectStr = ""
|
2013-12-18 03:31:32 +00:00
|
|
|
statement.allUseBool = false
|
2014-08-18 13:38:24 +00:00
|
|
|
statement.useAllCols = false
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.MustColumnMap = make(map[string]bool)
|
|
|
|
statement.NullableMap = make(map[string]bool)
|
|
|
|
statement.CheckVersion = true
|
2014-11-05 07:04:53 +00:00
|
|
|
statement.unscoped = false
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.IncrColumns = exprParams{}
|
|
|
|
statement.DecrColumns = exprParams{}
|
|
|
|
statement.ExprColumns = exprParams{}
|
2016-09-17 12:04:52 +00:00
|
|
|
statement.cond = builder.NewCond()
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.BufferSize = 0
|
|
|
|
statement.Context = nil
|
|
|
|
statement.LastError = 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
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) SetNoAutoCondition(no ...bool) *Statement {
|
|
|
|
statement.NoAutoCondition = true
|
2016-01-02 15:55:01 +00:00
|
|
|
if len(no) > 0 {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.NoAutoCondition = no[0]
|
2016-01-02 15:55:01 +00:00
|
|
|
}
|
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2016-09-17 12:04:52 +00:00
|
|
|
// Alias set the table alias
|
|
|
|
func (statement *Statement) Alias(alias string) *Statement {
|
|
|
|
statement.TableAlias = alias
|
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2016-11-08 15:31:41 +00:00
|
|
|
// SQL adds raw sql statement
|
2016-09-23 02:08:28 +00:00
|
|
|
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 {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.LastError = err
|
2016-09-23 02:08:28 +00:00
|
|
|
}
|
|
|
|
case string:
|
|
|
|
statement.RawSQL = query.(string)
|
|
|
|
statement.RawParams = args
|
|
|
|
default:
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.LastError = ErrUnSupportedSQLType
|
2016-09-23 02:08:28 +00:00
|
|
|
}
|
|
|
|
|
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
|
2016-09-17 12:04:52 +00:00
|
|
|
func (statement *Statement) Where(query interface{}, args ...interface{}) *Statement {
|
|
|
|
return statement.And(query, args...)
|
2014-11-18 16:41:03 +00:00
|
|
|
}
|
|
|
|
|
2020-02-27 00:34:16 +00:00
|
|
|
func (statement *Statement) quote(s string) string {
|
|
|
|
return statement.dialect.Quoter().Quote(s)
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:52:23 +00:00
|
|
|
// And add Where & and statement
|
2016-09-17 12:04:52 +00:00
|
|
|
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)
|
2017-10-30 03:07:56 +00:00
|
|
|
case map[string]interface{}:
|
2019-10-05 06:36:18 +00:00
|
|
|
queryMap := query.(map[string]interface{})
|
|
|
|
newMap := make(map[string]interface{})
|
|
|
|
for k, v := range queryMap {
|
2020-02-27 00:34:16 +00:00
|
|
|
newMap[statement.quote(k)] = v
|
2019-10-05 06:36:18 +00:00
|
|
|
}
|
|
|
|
statement.cond = statement.cond.And(builder.Eq(newMap))
|
2016-09-17 12:04:52 +00:00
|
|
|
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:
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.LastError = ErrConditionType
|
2016-03-23 08:22:08 +00:00
|
|
|
}
|
|
|
|
|
2016-09-17 12:04:52 +00:00
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:52:23 +00:00
|
|
|
// Or add Where & Or statement
|
2016-09-17 12:04:52 +00:00
|
|
|
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)
|
2017-10-30 03:07:56 +00:00
|
|
|
case map[string]interface{}:
|
|
|
|
cond := builder.Eq(query.(map[string]interface{}))
|
|
|
|
statement.cond = statement.cond.Or(cond)
|
2016-09-17 12:04:52 +00:00
|
|
|
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
|
2016-09-17 12:04:52 +00:00
|
|
|
func (statement *Statement) In(column string, args ...interface{}) *Statement {
|
2020-02-27 00:34:16 +00:00
|
|
|
in := builder.In(statement.quote(column), args...)
|
2016-09-17 12:04:52 +00:00
|
|
|
statement.cond = statement.cond.And(in)
|
2013-12-18 03:31:32 +00:00
|
|
|
return statement
|
2013-11-09 13:13:16 +00:00
|
|
|
}
|
|
|
|
|
2017-01-09 01:52:23 +00:00
|
|
|
// NotIn generate "Where column NOT IN (?) " statement
|
2016-09-17 12:04:52 +00:00
|
|
|
func (statement *Statement) NotIn(column string, args ...interface{}) *Statement {
|
2020-02-27 00:34:16 +00:00
|
|
|
notIn := builder.NotIn(statement.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
|
2013-11-09 13:13:16 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) SetRefValue(v reflect.Value) error {
|
2017-04-02 10:02:47 +00:00
|
|
|
var err error
|
2020-02-29 08:59:59 +00:00
|
|
|
statement.RefTable, err = statement.tagParser.ParseWithCache(reflect.Indirect(v))
|
2017-04-02 10:02:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-02-29 08:59:59 +00:00
|
|
|
statement.tableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), v, true)
|
2017-04-02 10:02:47 +00:00
|
|
|
return nil
|
2016-07-09 00:15:53 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func rValue(bean interface{}) reflect.Value {
|
|
|
|
return reflect.Indirect(reflect.ValueOf(bean))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (statement *Statement) SetRefBean(bean interface{}) error {
|
2018-04-10 01:50:29 +00:00
|
|
|
var err error
|
2020-02-29 08:59:59 +00:00
|
|
|
statement.RefTable, err = statement.tagParser.ParseWithCache(rValue(bean))
|
2018-04-10 01:50:29 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
2020-02-29 08:59:59 +00:00
|
|
|
statement.tableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), bean, true)
|
2018-04-10 01:50:29 +00:00
|
|
|
return nil
|
2013-05-19 05:25:52 +00:00
|
|
|
}
|
|
|
|
|
2016-03-29 01:17:06 +00:00
|
|
|
func (statement *Statement) needTableName() bool {
|
|
|
|
return len(statement.JoinStr) > 0
|
|
|
|
}
|
|
|
|
|
2020-02-24 08:53:18 +00:00
|
|
|
func (statement *Statement) colName(col *schemas.Column, tableName string) string {
|
2016-03-29 01:17:06 +00:00
|
|
|
if statement.needTableName() {
|
|
|
|
var nm = tableName
|
|
|
|
if len(statement.TableAlias) > 0 {
|
|
|
|
nm = statement.TableAlias
|
|
|
|
}
|
2020-02-27 00:34:16 +00:00
|
|
|
return statement.quote(nm) + "." + statement.quote(col.Name)
|
2016-03-29 01:17:06 +00:00
|
|
|
}
|
2020-02-27 00:34:16 +00:00
|
|
|
return statement.quote(col.Name)
|
2016-03-29 01:17:06 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
2013-07-03 03:49:29 +00:00
|
|
|
|
2016-07-09 00:15:53 +00:00
|
|
|
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 {
|
2014-01-25 02:07:11 +00:00
|
|
|
case ptrPkType:
|
2020-02-24 08:53:18 +00:00
|
|
|
if pkPtr, ok := (id).(*schemas.PK); ok {
|
2017-03-01 08:55:53 +00:00
|
|
|
statement.idParam = pkPtr
|
2016-04-06 14:19:38 +00:00
|
|
|
return statement
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
2014-01-25 02:07:11 +00:00
|
|
|
case pkType:
|
2020-02-24 08:53:18 +00:00
|
|
|
if pk, ok := (id).(schemas.PK); ok {
|
2017-03-01 08:55:53 +00:00
|
|
|
statement.idParam = &pk
|
2016-04-06 14:19:38 +00:00
|
|
|
return statement
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-06 14:19:38 +00:00
|
|
|
switch idType.Kind() {
|
|
|
|
case reflect.String:
|
2020-02-24 08:53:18 +00:00
|
|
|
statement.idParam = &schemas.PK{idValue.Convert(reflect.TypeOf("")).Interface()}
|
2016-04-06 14:19:38 +00:00
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2020-02-24 08:53:18 +00:00
|
|
|
statement.idParam = &schemas.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 {
|
|
|
|
if len(arg) > 0 {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.IncrColumns.addParam(column, arg[0])
|
2014-04-15 04:14:18 +00:00
|
|
|
} else {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.IncrColumns.addParam(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 {
|
|
|
|
if len(arg) > 0 {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.DecrColumns.addParam(column, arg[0])
|
2014-07-15 15:25:24 +00:00
|
|
|
} else {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.DecrColumns.addParam(column, 1)
|
2014-07-15 15:25:24 +00:00
|
|
|
}
|
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2017-01-09 01:52:23 +00:00
|
|
|
// SetExpr Generate "Update ... Set column = {expression}" statement
|
2019-09-23 15:34:26 +00:00
|
|
|
func (statement *Statement) SetExpr(column string, expression interface{}) *Statement {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.ExprColumns.addParam(column, expression)
|
2015-01-28 05:23:01 +00:00
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2016-11-08 15:31:41 +00:00
|
|
|
// 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
|
2013-11-14 15:07:33 +00:00
|
|
|
}
|
|
|
|
|
2016-11-08 15:31:41 +00:00
|
|
|
// ForUpdate generates "SELECT ... FOR UPDATE" statement
|
2015-08-28 07:54:19 +00:00
|
|
|
func (statement *Statement) ForUpdate() *Statement {
|
|
|
|
statement.IsForUpdate = true
|
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2016-04-07 00:54:02 +00:00
|
|
|
// Select replace select
|
2016-11-09 14:43:27 +00:00
|
|
|
func (statement *Statement) Select(str string) *Statement {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.SelectStr = str
|
2016-11-09 14:43:27 +00:00
|
|
|
return statement
|
2015-05-24 13:32:27 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func col2NewCols(columns ...string) []string {
|
|
|
|
newColumns := make([]string, 0, len(columns))
|
|
|
|
for _, col := range columns {
|
|
|
|
col = strings.Replace(col, "`", "", -1)
|
|
|
|
col = strings.Replace(col, `"`, "", -1)
|
|
|
|
ccols := strings.Split(col, ",")
|
|
|
|
for _, c := range ccols {
|
|
|
|
newColumns = append(newColumns, strings.TrimSpace(c))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newColumns
|
|
|
|
}
|
|
|
|
|
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 {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.ColumnMap.add(nc)
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
|
|
|
return statement
|
2013-08-08 05:24:38 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) ColumnStr() string {
|
|
|
|
return statement.dialect.Quoter().Join(statement.ColumnMap, ", ")
|
2020-02-27 01:30:06 +00:00
|
|
|
}
|
|
|
|
|
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
|
2014-04-06 04:58:16 +00:00
|
|
|
func (statement *Statement) MustCols(columns ...string) *Statement {
|
|
|
|
newColumns := col2NewCols(columns...)
|
|
|
|
for _, nc := range newColumns {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.MustColumnMap[strings.ToLower(nc)] = true
|
2014-04-06 04:58:16 +00:00
|
|
|
}
|
|
|
|
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 {
|
2014-04-06 04:58:16 +00:00
|
|
|
statement.MustCols(columns...)
|
2013-12-18 03:31:32 +00:00
|
|
|
} else {
|
|
|
|
statement.allUseBool = true
|
|
|
|
}
|
|
|
|
return statement
|
2013-11-15 02:16:08 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 00:54:02 +00:00
|
|
|
// Omit do not use the columns
|
2013-10-17 04:50:46 +00:00
|
|
|
func (statement *Statement) Omit(columns ...string) {
|
2013-12-18 03:31:32 +00:00
|
|
|
newColumns := col2NewCols(columns...)
|
|
|
|
for _, nc := range newColumns {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.OmitColumnMap = append(statement.OmitColumnMap, nc)
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
2013-10-17 04:50:46 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 00:54:02 +00:00
|
|
|
// Nullable Update use only: update columns to null when value is nullable and zero-value
|
2015-06-10 14:04:14 +00:00
|
|
|
func (statement *Statement) Nullable(columns ...string) {
|
|
|
|
newColumns := col2NewCols(columns...)
|
|
|
|
for _, nc := range newColumns {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.NullableMap[strings.ToLower(nc)] = true
|
2015-06-10 14:04:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 {
|
2020-01-20 08:22:06 +00:00
|
|
|
statement.LimitN = &limit
|
2013-12-18 03:31:32 +00:00
|
|
|
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 {
|
2015-10-27 06:45:48 +00:00
|
|
|
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 {
|
2019-09-06 14:15:04 +00:00
|
|
|
var buf strings.Builder
|
2015-10-27 06:45:48 +00:00
|
|
|
if len(statement.OrderStr) > 0 {
|
2018-07-11 00:59:00 +00:00
|
|
|
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
2014-08-18 13:20:18 +00:00
|
|
|
}
|
2020-02-27 00:34:16 +00:00
|
|
|
for i, col := range colNames {
|
|
|
|
if i > 0 {
|
|
|
|
fmt.Fprint(&buf, ", ")
|
|
|
|
}
|
|
|
|
statement.dialect.Quoter().QuoteTo(&buf, col)
|
|
|
|
fmt.Fprint(&buf, " DESC")
|
|
|
|
}
|
2015-10-27 06:45:48 +00:00
|
|
|
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 {
|
2019-09-06 14:15:04 +00:00
|
|
|
var buf strings.Builder
|
2015-10-27 06:45:48 +00:00
|
|
|
if len(statement.OrderStr) > 0 {
|
2018-07-11 00:59:00 +00:00
|
|
|
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
2014-08-18 13:20:18 +00:00
|
|
|
}
|
2020-02-27 00:34:16 +00:00
|
|
|
for i, col := range colNames {
|
|
|
|
if i > 0 {
|
|
|
|
fmt.Fprint(&buf, ", ")
|
|
|
|
}
|
|
|
|
statement.dialect.Quoter().QuoteTo(&buf, col)
|
|
|
|
fmt.Fprint(&buf, " ASC")
|
|
|
|
}
|
2015-10-27 06:45:48 +00:00
|
|
|
statement.OrderStr = buf.String()
|
2014-08-18 13:20:18 +00:00
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) Conds() builder.Cond {
|
|
|
|
return statement.cond
|
|
|
|
}
|
|
|
|
|
2018-04-10 01:50:29 +00:00
|
|
|
// Table tempororily set table name, the parameter could be a string or a pointer of struct
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) SetTable(tableNameOrBean interface{}) error {
|
2018-04-10 01:50:29 +00:00
|
|
|
v := rValue(tableNameOrBean)
|
|
|
|
t := v.Type()
|
|
|
|
if t.Kind() == reflect.Struct {
|
|
|
|
var err error
|
2020-02-29 08:59:59 +00:00
|
|
|
statement.RefTable, err = statement.tagParser.ParseWithCache(v)
|
2018-04-10 01:50:29 +00:00
|
|
|
if err != nil {
|
2020-02-28 12:29:08 +00:00
|
|
|
return err
|
2018-04-10 01:50:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-29 08:59:59 +00:00
|
|
|
statement.AltTableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), tableNameOrBean, true)
|
2020-02-28 12:29:08 +00:00
|
|
|
return nil
|
2018-04-10 01:50:29 +00:00
|
|
|
}
|
|
|
|
|
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 {
|
2019-09-06 14:15:04 +00:00
|
|
|
var buf strings.Builder
|
2015-10-27 06:45:48 +00:00
|
|
|
if len(statement.JoinStr) > 0 {
|
2016-04-07 00:54:02 +00:00
|
|
|
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
|
2015-10-27 06:45:48 +00:00
|
|
|
} else {
|
2016-04-07 00:54:02 +00:00
|
|
|
fmt.Fprintf(&buf, "%v JOIN ", joinOP)
|
2015-10-27 06:45:48 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 03:53:53 +00:00
|
|
|
switch tp := tablename.(type) {
|
|
|
|
case builder.Builder:
|
|
|
|
subSQL, subQueryArgs, err := tp.ToSQL()
|
|
|
|
if err != nil {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.LastError = err
|
2019-01-20 03:53:53 +00:00
|
|
|
return statement
|
|
|
|
}
|
2019-07-24 01:41:06 +00:00
|
|
|
|
2020-02-27 05:49:43 +00:00
|
|
|
fields := strings.Split(tp.TableName(), ".")
|
|
|
|
aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
|
|
|
|
aliasName = schemas.CommonQuoter.Trim(aliasName)
|
|
|
|
|
2019-01-20 03:53:53 +00:00
|
|
|
fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition)
|
|
|
|
statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
|
|
|
|
case *builder.Builder:
|
|
|
|
subSQL, subQueryArgs, err := tp.ToSQL()
|
|
|
|
if err != nil {
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.LastError = err
|
2019-01-20 03:53:53 +00:00
|
|
|
return statement
|
|
|
|
}
|
2019-07-24 01:41:06 +00:00
|
|
|
|
2020-02-27 05:49:43 +00:00
|
|
|
fields := strings.Split(tp.TableName(), ".")
|
|
|
|
aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
|
|
|
|
aliasName = schemas.CommonQuoter.Trim(aliasName)
|
|
|
|
|
2019-01-20 03:53:53 +00:00
|
|
|
fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition)
|
|
|
|
statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
|
|
|
|
default:
|
2020-02-29 08:59:59 +00:00
|
|
|
tbName := dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), tablename, true)
|
2020-02-28 12:29:08 +00:00
|
|
|
if !utils.IsSubQuery(tbName) {
|
2020-02-25 00:01:36 +00:00
|
|
|
var buf strings.Builder
|
2020-02-27 05:49:43 +00:00
|
|
|
statement.dialect.Quoter().QuoteTo(&buf, tbName)
|
2020-02-25 00:01:36 +00:00
|
|
|
tbName = buf.String()
|
|
|
|
}
|
2019-01-20 03:53:53 +00:00
|
|
|
fmt.Fprintf(&buf, "%s ON %v", tbName, condition)
|
|
|
|
}
|
2015-10-27 06:45:48 +00:00
|
|
|
|
|
|
|
statement.JoinStr = buf.String()
|
2016-04-18 22:21:08 +00:00
|
|
|
statement.joinArgs = append(statement.joinArgs, args...)
|
2013-12-18 03:31:32 +00:00
|
|
|
return statement
|
2013-05-06 08:01:17 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
// tbName get some table's table name
|
|
|
|
func (statement *Statement) tbNameNoSchema(table *schemas.Table) string {
|
|
|
|
if len(statement.AltTableName) > 0 {
|
|
|
|
return statement.AltTableName
|
|
|
|
}
|
|
|
|
|
|
|
|
return table.Name
|
|
|
|
}
|
|
|
|
|
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"
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) SetUnscoped() *Statement {
|
2014-11-05 07:04:53 +00:00
|
|
|
statement.unscoped = true
|
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) GetUnscoped() bool {
|
|
|
|
return statement.unscoped
|
|
|
|
}
|
|
|
|
|
2013-08-08 05:24:38 +00:00
|
|
|
func (statement *Statement) genColumnStr() string {
|
2017-01-03 05:31:47 +00:00
|
|
|
if statement.RefTable == nil {
|
|
|
|
return ""
|
|
|
|
}
|
2016-11-07 11:47:42 +00:00
|
|
|
|
2019-09-06 14:15:04 +00:00
|
|
|
var buf strings.Builder
|
2016-11-07 11:47:42 +00:00
|
|
|
columns := statement.RefTable.Columns()
|
|
|
|
|
2016-11-08 09:32:08 +00:00
|
|
|
for _, col := range columns {
|
2020-02-28 12:29:08 +00:00
|
|
|
if statement.OmitColumnMap.Contain(col.Name) {
|
2018-04-11 03:52:16 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
if len(statement.ColumnMap) > 0 && !statement.ColumnMap.Contain(col.Name) {
|
2018-04-11 03:52:16 +00:00
|
|
|
continue
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
2016-11-07 11:47:42 +00:00
|
|
|
|
2020-02-24 08:53:18 +00:00
|
|
|
if col.MapType == schemas.ONLYTODB {
|
2013-12-18 03:31:32 +00:00
|
|
|
continue
|
|
|
|
}
|
2014-04-29 06:16:53 +00:00
|
|
|
|
2016-11-08 09:32:08 +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 != "" {
|
2016-11-07 11:47:42 +00:00
|
|
|
buf.WriteString(statement.TableAlias)
|
2014-11-18 16:41:03 +00:00
|
|
|
} else {
|
2016-11-07 11:47:42 +00:00
|
|
|
buf.WriteString(statement.TableName())
|
2014-04-29 06:16:53 +00:00
|
|
|
}
|
2016-11-07 11:47:42 +00:00
|
|
|
|
|
|
|
buf.WriteString(".")
|
|
|
|
}
|
|
|
|
|
2020-02-27 05:49:43 +00:00
|
|
|
statement.dialect.Quoter().QuoteTo(&buf, col.Name)
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
2016-11-07 11:47:42 +00:00
|
|
|
|
|
|
|
return buf.String()
|
2013-05-19 05:25:52 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) GenCreateTableSQL() string {
|
2020-02-27 05:49:43 +00:00
|
|
|
return statement.dialect.CreateTableSQL(statement.RefTable, statement.TableName(),
|
2014-01-07 09:33:27 +00:00
|
|
|
statement.StoreEngine, statement.Charset)
|
2013-07-27 04:24:38 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) GenIndexSQL() []string {
|
2016-07-09 00:15:53 +00:00
|
|
|
var sqls []string
|
2016-11-09 14:43:27 +00:00
|
|
|
tbName := statement.TableName()
|
2018-04-10 01:50:29 +00:00
|
|
|
for _, index := range statement.RefTable.Indexes {
|
2020-02-24 08:53:18 +00:00
|
|
|
if index.Type == schemas.IndexType {
|
2020-02-27 05:49:43 +00:00
|
|
|
sql := statement.dialect.CreateIndexSQL(tbName, index)
|
2013-12-18 03:31:32 +00:00
|
|
|
sqls = append(sqls, sql)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sqls
|
2013-07-27 04:24:38 +00:00
|
|
|
}
|
|
|
|
|
2013-09-28 15:14:42 +00:00
|
|
|
func uniqueName(tableName, uqeName string) string {
|
2013-12-18 03:31:32 +00:00
|
|
|
return fmt.Sprintf("UQE_%v_%v", tableName, uqeName)
|
2013-09-28 15:14:42 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) GenUniqueSQL() []string {
|
2016-07-09 00:15:53 +00:00
|
|
|
var sqls []string
|
2016-11-09 14:43:27 +00:00
|
|
|
tbName := statement.TableName()
|
|
|
|
for _, index := range statement.RefTable.Indexes {
|
2020-02-24 08:53:18 +00:00
|
|
|
if index.Type == schemas.UniqueType {
|
2020-02-27 05:49:43 +00:00
|
|
|
sql := statement.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
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) GenDelIndexSQL() []string {
|
2016-07-09 00:15:53 +00:00
|
|
|
var sqls []string
|
2016-11-09 14:43:27 +00:00
|
|
|
tbName := statement.TableName()
|
2020-02-24 08:53:18 +00:00
|
|
|
idx := strings.Index(tbName, ".")
|
|
|
|
if idx > -1 {
|
|
|
|
tbName = tbName[idx+1:]
|
|
|
|
}
|
2018-04-10 01:50:29 +00:00
|
|
|
idxPrefixName := strings.Replace(tbName, `"`, "", -1)
|
|
|
|
idxPrefixName = strings.Replace(idxPrefixName, `.`, "_", -1)
|
2016-11-09 14:43:27 +00:00
|
|
|
for idxName, index := range statement.RefTable.Indexes {
|
2013-12-18 03:31:32 +00:00
|
|
|
var rIdxName string
|
2020-02-24 08:53:18 +00:00
|
|
|
if index.Type == schemas.UniqueType {
|
2018-04-10 01:50:29 +00:00
|
|
|
rIdxName = uniqueName(idxPrefixName, idxName)
|
2020-02-24 08:53:18 +00:00
|
|
|
} else if index.Type == schemas.IndexType {
|
2020-02-28 12:29:08 +00:00
|
|
|
rIdxName = utils.IndexName(idxPrefixName, idxName)
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
2020-02-29 08:59:59 +00:00
|
|
|
sql := fmt.Sprintf("DROP INDEX %v", statement.quote(dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), rIdxName, true)))
|
2020-02-27 05:49:43 +00:00
|
|
|
if statement.dialect.IndexOnTable() {
|
|
|
|
sql += fmt.Sprintf(" ON %v", statement.quote(tbName))
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
|
|
|
sqls = append(sqls, sql)
|
|
|
|
}
|
|
|
|
return sqls
|
2013-09-26 07:19:39 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) buildConds2(table *schemas.Table, bean interface{},
|
|
|
|
includeVersion bool, includeUpdated bool, includeNil bool,
|
|
|
|
includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
|
|
|
|
mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
|
|
|
|
var conds []builder.Cond
|
|
|
|
for _, col := range table.Columns() {
|
|
|
|
if !includeVersion && col.IsVersion {
|
|
|
|
continue
|
2016-09-17 12:04:52 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
if !includeUpdated && col.IsUpdated {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !includeAutoIncr && col.IsAutoIncrement {
|
|
|
|
continue
|
2014-05-23 06:18:45 +00:00
|
|
|
}
|
2017-04-01 02:09:00 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
if statement.dialect.DBType() == schemas.MSSQL && (col.SQLType.Name == schemas.Text || col.SQLType.IsBlob() || col.SQLType.Name == schemas.TimeStampz) {
|
|
|
|
continue
|
2017-07-24 13:26:14 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
if col.SQLType.IsJson() {
|
|
|
|
continue
|
2018-04-11 15:09:46 +00:00
|
|
|
}
|
2016-09-17 12:04:52 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
var colName string
|
|
|
|
if addedTableName {
|
|
|
|
var nm = tableName
|
|
|
|
if len(aliasName) > 0 {
|
|
|
|
nm = aliasName
|
|
|
|
}
|
|
|
|
colName = statement.quote(nm) + "." + statement.quote(col.Name)
|
2016-12-10 02:04:48 +00:00
|
|
|
} else {
|
2020-02-28 12:29:08 +00:00
|
|
|
colName = statement.quote(col.Name)
|
2016-09-29 06:13:15 +00:00
|
|
|
}
|
2013-12-11 08:27:33 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
fieldValuePtr, err := col.ValueOf(bean)
|
|
|
|
if err != nil {
|
|
|
|
if !strings.Contains(err.Error(), "is not valid") {
|
|
|
|
//engine.logger.Warn(err)
|
|
|
|
}
|
|
|
|
continue
|
2017-04-14 02:49:02 +00:00
|
|
|
}
|
2016-09-19 03:13:40 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
if col.IsDeleted && !unscoped { // tag "deleted" is enabled
|
|
|
|
conds = append(conds, statement.CondDeleted(col))
|
|
|
|
}
|
2016-07-07 14:34:43 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
fieldValue := *fieldValuePtr
|
|
|
|
if fieldValue.Interface() == nil {
|
|
|
|
continue
|
|
|
|
}
|
2017-04-14 05:55:55 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
fieldType := reflect.TypeOf(fieldValue.Interface())
|
|
|
|
requiredField := useAllCols
|
2015-10-27 06:45:48 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
|
|
|
|
if b {
|
|
|
|
requiredField = true
|
|
|
|
} else {
|
|
|
|
continue
|
|
|
|
}
|
2015-03-05 01:56:15 +00:00
|
|
|
}
|
2014-05-06 03:11:44 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
if fieldType.Kind() == reflect.Ptr {
|
|
|
|
if fieldValue.IsNil() {
|
|
|
|
if includeNil {
|
|
|
|
conds = append(conds, builder.Eq{colName: nil})
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
} else if !fieldValue.IsValid() {
|
|
|
|
continue
|
|
|
|
} else {
|
|
|
|
// dereference ptr type to instance type
|
|
|
|
fieldValue = fieldValue.Elem()
|
|
|
|
fieldType = reflect.TypeOf(fieldValue.Interface())
|
|
|
|
requiredField = true
|
|
|
|
}
|
2014-05-06 06:19:37 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
|
|
|
|
var val interface{}
|
|
|
|
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()
|
|
|
|
case reflect.Struct:
|
|
|
|
if fieldType.ConvertibleTo(schemas.TimeType) {
|
|
|
|
t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
|
|
|
|
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
|
|
|
continue
|
2014-05-06 03:11:44 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
val = dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
|
|
|
|
} else if _, ok := reflect.New(fieldType).Interface().(convert.Conversion); ok {
|
|
|
|
continue
|
|
|
|
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
|
|
|
|
val, _ = valNul.Value()
|
|
|
|
if val == nil {
|
|
|
|
continue
|
2014-05-06 03:11:44 +00:00
|
|
|
}
|
2016-10-10 07:07:12 +00:00
|
|
|
} else {
|
2020-02-28 12:29:08 +00:00
|
|
|
if col.SQLType.IsJson() {
|
|
|
|
if col.SQLType.IsText() {
|
|
|
|
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
val = string(bytes)
|
|
|
|
} else if col.SQLType.IsBlob() {
|
|
|
|
var bytes []byte
|
|
|
|
var err error
|
|
|
|
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
val = bytes
|
|
|
|
}
|
2016-10-10 07:07:12 +00:00
|
|
|
} else {
|
2020-02-29 08:59:59 +00:00
|
|
|
table, err := statement.tagParser.ParseWithCache(fieldValue)
|
2020-02-28 12:29:08 +00:00
|
|
|
if err != nil {
|
|
|
|
val = fieldValue.Interface()
|
|
|
|
} else {
|
|
|
|
if len(table.PrimaryKeys) == 1 {
|
|
|
|
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
|
|
|
// fix non-int pk issues
|
|
|
|
//if pkField.Int() != 0 {
|
|
|
|
if pkField.IsValid() && !utils.IsZero(pkField.Interface()) {
|
|
|
|
val = pkField.Interface()
|
|
|
|
} else {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//TODO: how to handler?
|
|
|
|
return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
|
|
|
|
}
|
|
|
|
}
|
2016-10-10 07:07:12 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
case reflect.Array:
|
|
|
|
continue
|
|
|
|
case reflect.Slice, reflect.Map:
|
|
|
|
if fieldValue == reflect.Zero(fieldType) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
|
|
|
continue
|
2015-01-13 09:17:34 +00:00
|
|
|
}
|
2018-04-10 04:52:47 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
if col.SQLType.IsText() {
|
|
|
|
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
val = string(bytes)
|
|
|
|
} else if col.SQLType.IsBlob() {
|
|
|
|
var bytes []byte
|
|
|
|
var err error
|
|
|
|
if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
|
|
|
|
fieldType.Elem().Kind() == reflect.Uint8 {
|
|
|
|
if fieldValue.Len() > 0 {
|
|
|
|
val = fieldValue.Bytes()
|
|
|
|
} else {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
val = bytes
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
continue
|
2015-01-14 07:04:48 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
default:
|
|
|
|
val = fieldValue.Interface()
|
2014-05-06 03:11:44 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
|
|
|
|
conds = append(conds, builder.Eq{colName: val})
|
2014-05-06 03:11:44 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
return builder.And(conds...), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (statement *Statement) BuildConds(table *schemas.Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, addedTableName bool) (builder.Cond, error) {
|
|
|
|
return statement.buildConds2(table, bean, includeVersion, includeUpdated, includeNil, includeAutoIncr, statement.allUseBool, statement.useAllCols,
|
|
|
|
statement.unscoped, statement.MustColumnMap, statement.TableName(), statement.TableAlias, addedTableName)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (statement *Statement) mergeConds(bean interface{}) error {
|
|
|
|
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
|
2014-05-06 06:19:37 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
statement.cond = statement.cond.And(autoCond)
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
if err := statement.ProcessIDParam(); err != nil {
|
|
|
|
return err
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (statement *Statement) GenConds(bean interface{}) (string, []interface{}, error) {
|
|
|
|
if err := statement.mergeConds(bean); err != nil {
|
|
|
|
return "", nil, err
|
2013-12-18 03:31:32 +00:00
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
|
|
|
|
return builder.ToSQL(statement.cond)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (statement *Statement) quoteColumnStr(columnStr string) string {
|
|
|
|
columns := strings.Split(columnStr, ",")
|
|
|
|
return statement.dialect.Quoter().Join(columns, ",")
|
|
|
|
}
|
|
|
|
|
|
|
|
func ConvertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
|
|
|
|
switch sqlOrArgs[0].(type) {
|
|
|
|
case string:
|
|
|
|
return sqlOrArgs[0].(string), sqlOrArgs[1:], nil
|
|
|
|
case *builder.Builder:
|
|
|
|
return sqlOrArgs[0].(*builder.Builder).ToSQL()
|
|
|
|
case builder.Builder:
|
|
|
|
bd := sqlOrArgs[0].(builder.Builder)
|
|
|
|
return bd.ToSQL()
|
2015-08-28 07:54:19 +00:00
|
|
|
}
|
2013-12-20 06:53:40 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
return "", nil, ErrUnSupportedType
|
2013-05-03 07:26:51 +00:00
|
|
|
}
|
2013-12-17 01:38:20 +00:00
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
func (statement *Statement) ProcessIDParam() error {
|
2018-04-11 15:09:46 +00:00
|
|
|
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
|
|
|
|
2020-02-24 08:53:18 +00:00
|
|
|
func (statement *Statement) joinColumns(cols []*schemas.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 {
|
2020-02-27 05:49:43 +00:00
|
|
|
colnames[i] = statement.quote(statement.TableName()) +
|
|
|
|
"." + statement.quote(col.Name)
|
2016-05-13 10:09:11 +00:00
|
|
|
} else {
|
2020-02-27 05:49:43 +00:00
|
|
|
colnames[i] = statement.quote(col.Name)
|
2016-05-13 10:09:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(colnames, ", ")
|
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
// CondDeleted returns the conditions whether a record is soft deleted.
|
|
|
|
func (statement *Statement) CondDeleted(col *schemas.Column) builder.Cond {
|
2020-03-03 12:45:27 +00:00
|
|
|
var colName = col.Name
|
|
|
|
if statement.JoinStr != "" {
|
|
|
|
colName = statement.quote(statement.TableName()) +
|
|
|
|
"." + statement.quote(col.Name)
|
|
|
|
}
|
2020-02-28 12:29:08 +00:00
|
|
|
var cond = builder.NewCond()
|
|
|
|
if col.SQLType.IsNumeric() {
|
2020-03-03 12:45:27 +00:00
|
|
|
cond = builder.Eq{colName: 0}
|
2020-02-28 12:29:08 +00:00
|
|
|
} else {
|
|
|
|
// FIXME: mssql: The conversion of a nvarchar data type to a datetime data type resulted in an out-of-range value.
|
|
|
|
if statement.dialect.DBType() != schemas.MSSQL {
|
2020-03-03 12:45:27 +00:00
|
|
|
cond = builder.Eq{colName: utils.ZeroTime1}
|
2016-05-13 10:09:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
if col.Nullable {
|
2020-03-03 12:45:27 +00:00
|
|
|
cond = cond.Or(builder.IsNull{colName})
|
2016-05-13 10:09:11 +00:00
|
|
|
}
|
|
|
|
|
2020-02-28 12:29:08 +00:00
|
|
|
return cond
|
2016-05-13 10:09:11 +00:00
|
|
|
}
|