2013-05-03 07:26:51 +00:00
package xorm
import (
2014-04-11 07:37:27 +00:00
"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
2014-04-11 07:37:27 +00:00
"github.com/go-xorm/core"
2013-05-03 07:26:51 +00:00
)
2014-01-09 09:55:33 +00:00
type inParam struct {
colName string
args [ ] interface { }
}
2014-04-18 14:14:15 +00:00
type incrParam struct {
colName string
arg interface { }
}
2014-07-15 15:25:24 +00:00
type decrParam struct {
colName string
arg interface { }
}
2015-01-28 05:23:01 +00:00
type exprParam struct {
colName string
expr string
}
2013-11-22 06:11:07 +00:00
// statement save all the sql info for executing SQL
2013-05-03 07:26:51 +00:00
type Statement struct {
2014-01-07 09:33:27 +00:00
RefTable * core . Table
2013-12-18 03:31:32 +00:00
Engine * Engine
Start int
LimitN int
WhereStr string
2014-01-25 02:07:11 +00:00
IdParam * core . PK
2013-12-18 03:31:32 +00:00
Params [ ] interface { }
OrderStr string
JoinStr string
GroupByStr string
HavingStr string
ColumnStr string
columnMap map [ string ] bool
2014-04-05 14:14:00 +00:00
useAllCols bool
2013-12-18 03:31:32 +00:00
OmitStr string
ConditionStr string
AltTableName string
RawSQL string
RawParams [ ] interface { }
UseCascade bool
UseAutoJoin bool
StoreEngine string
Charset string
BeanArgs [ ] interface { }
UseCache bool
UseAutoTime bool
IsDistinct bool
2014-11-18 16:41:03 +00:00
TableAlias string
2013-12-18 03:31:32 +00:00
allUseBool bool
checkVersion bool
2014-11-05 07:04:53 +00:00
unscoped bool
2014-04-06 04:58:16 +00:00
mustColumnMap map [ string ] bool
2014-01-09 09:55:33 +00:00
inColumns map [ string ] * inParam
2014-04-18 14:14:15 +00:00
incrColumns map [ string ] incrParam
2014-07-15 15:25:24 +00:00
decrColumns map [ string ] decrParam
2015-01-28 05:23:01 +00:00
exprColumns map [ string ] exprParam
2013-05-03 07:26:51 +00:00
}
2013-11-22 06:11:07 +00:00
// init
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 . WhereStr = ""
statement . Params = make ( [ ] interface { } , 0 )
statement . OrderStr = ""
statement . UseCascade = true
statement . JoinStr = ""
statement . GroupByStr = ""
statement . HavingStr = ""
statement . ColumnStr = ""
statement . OmitStr = ""
statement . columnMap = make ( map [ string ] bool )
statement . ConditionStr = ""
statement . AltTableName = ""
2014-02-25 10:45:24 +00:00
statement . IdParam = nil
2013-12-18 03:31:32 +00:00
statement . RawSQL = ""
statement . RawParams = make ( [ ] interface { } , 0 )
statement . BeanArgs = 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
statement . IsDistinct = false
2014-11-18 16:41:03 +00:00
statement . TableAlias = ""
2013-12-18 03:31:32 +00:00
statement . allUseBool = false
2014-08-18 13:38:24 +00:00
statement . useAllCols = false
2014-04-06 04:58:16 +00:00
statement . mustColumnMap = make ( map [ string ] bool )
2013-12-18 03:31:32 +00:00
statement . checkVersion = true
2014-11-05 07:04:53 +00:00
statement . unscoped = false
2014-01-09 09:55:33 +00:00
statement . inColumns = make ( map [ string ] * inParam )
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 )
2013-05-06 08:01:17 +00:00
}
2013-11-22 06:11:07 +00:00
// add the raw sql statement
func ( statement * Statement ) Sql ( querystring string , args ... interface { } ) * Statement {
2013-12-18 03:31:32 +00:00
statement . RawSQL = querystring
statement . RawParams = args
return statement
2013-06-16 03:05:16 +00:00
}
2014-11-18 16:41:03 +00:00
// set the table alias
func ( statement * Statement ) Alias ( alias string ) * Statement {
statement . TableAlias = alias
return statement
}
2013-11-22 06:11:07 +00:00
// add Where statment
func ( statement * Statement ) Where ( querystring string , args ... interface { } ) * Statement {
2014-04-29 06:16:53 +00:00
if ! strings . Contains ( querystring , statement . Engine . dialect . EqStr ( ) ) {
querystring = strings . Replace ( querystring , "=" , statement . Engine . dialect . EqStr ( ) , - 1 )
}
2013-12-18 03:31:32 +00:00
statement . WhereStr = querystring
statement . Params = args
return statement
2013-05-03 07:26:51 +00:00
}
2013-11-22 06:11:07 +00:00
// add Where & and statment
func ( statement * Statement ) And ( querystring string , args ... interface { } ) * Statement {
2013-12-18 03:31:32 +00:00
if statement . WhereStr != "" {
2014-04-17 02:13:16 +00:00
statement . WhereStr = fmt . Sprintf ( "(%v) %s (%v)" , statement . WhereStr ,
statement . Engine . dialect . AndStr ( ) , querystring )
2013-12-18 03:31:32 +00:00
} else {
statement . WhereStr = querystring
}
statement . Params = append ( statement . Params , args ... )
return statement
2013-11-09 13:13:16 +00:00
}
2013-11-22 06:11:07 +00:00
// add Where & Or statment
func ( statement * Statement ) Or ( querystring string , args ... interface { } ) * Statement {
2013-12-18 03:31:32 +00:00
if statement . WhereStr != "" {
2014-04-17 02:13:16 +00:00
statement . WhereStr = fmt . Sprintf ( "(%v) %s (%v)" , statement . WhereStr ,
statement . Engine . dialect . OrStr ( ) , querystring )
2013-12-18 03:31:32 +00:00
} else {
statement . WhereStr = querystring
}
statement . Params = append ( statement . Params , args ... )
return statement
2013-11-09 13:13:16 +00:00
}
2013-11-22 06:11:07 +00:00
// tempororily set table name
func ( statement * Statement ) Table ( tableNameOrBean interface { } ) * Statement {
2014-04-08 08:46:23 +00:00
v := rValue ( tableNameOrBean )
t := v . Type ( )
2013-12-18 03:31:32 +00:00
if t . Kind ( ) == reflect . String {
statement . AltTableName = tableNameOrBean . ( string )
} else if t . Kind ( ) == reflect . Struct {
2014-04-08 08:46:23 +00:00
statement . RefTable = statement . Engine . autoMapType ( v )
2013-12-18 03:31:32 +00:00
}
return statement
2013-05-19 05:25:52 +00:00
}
2013-12-02 14:34:17 +00:00
/ * func ( statement * Statement ) genFields ( bean interface { } ) map [ string ] interface { } {
2013-12-09 02:29:23 +00:00
results := make ( map [ string ] interface { } )
2014-08-28 16:34:09 +00:00
table := statement . Engine . TableInfo ( bean )
2013-12-09 02:29:23 +00:00
for _ , col := range table . Columns {
fieldValue := col . ValueOf ( bean )
fieldType := reflect . TypeOf ( fieldValue . Interface ( ) )
var val interface { }
switch fieldType . Kind ( ) {
case reflect . Bool :
if allUseBool {
val = fieldValue . Interface ( )
} else if _ , ok := boolColumnMap [ col . Name ] ; ok {
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 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 fieldValue . Int ( ) == 0 {
continue
}
val = fieldValue . Interface ( )
case reflect . Float32 , reflect . Float64 :
if fieldValue . Float ( ) == 0.0 {
continue
}
val = fieldValue . Interface ( )
case reflect . Uint8 , reflect . Uint16 , reflect . Uint , reflect . Uint32 , reflect . Uint64 :
if fieldValue . Uint ( ) == 0 {
continue
}
val = fieldValue . Interface ( )
case reflect . Struct :
if fieldType == reflect . TypeOf ( time . Now ( ) ) {
t := fieldValue . Interface ( ) . ( time . Time )
if t . IsZero ( ) || ! fieldValue . IsValid ( ) {
continue
}
var str string
if col . SQLType . Name == Time {
s := t . UTC ( ) . Format ( "2006-01-02 15:04:05" )
val = s [ 11 : 19 ]
} else if col . SQLType . Name == Date {
str = t . Format ( "2006-01-02" )
val = str
} else {
val = t
}
} else {
engine . autoMapType ( fieldValue . Type ( ) )
if table , ok := engine . Tables [ fieldValue . Type ( ) ] ; ok {
pkField := reflect . Indirect ( fieldValue ) . FieldByName ( table . PKColumn ( ) . FieldName )
if pkField . Int ( ) != 0 {
val = pkField . Interface ( )
} else {
continue
}
} else {
val = fieldValue . Interface ( )
}
}
case reflect . Array , reflect . Slice , reflect . Map :
if fieldValue == reflect . Zero ( fieldType ) {
continue
}
if fieldValue . IsNil ( ) || ! fieldValue . IsValid ( ) {
continue
}
if col . SQLType . IsText ( ) {
bytes , err := json . Marshal ( fieldValue . Interface ( ) )
if err != nil {
2014-02-11 17:35:26 +00:00
engine . LogError ( err )
2013-12-09 02:29:23 +00:00
continue
}
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 . Marshal ( fieldValue . Interface ( ) )
if err != nil {
2014-02-11 17:35:26 +00:00
engine . LogError ( err )
2013-12-09 02:29:23 +00:00
continue
}
val = bytes
}
} else {
continue
}
default :
val = fieldValue . Interface ( )
}
results [ col . Name ] = val
}
return results
2013-12-02 14:34:17 +00:00
} * /
2013-12-02 06:54:44 +00:00
2013-11-06 07:36:38 +00:00
// Auto generating conditions according a struct
2014-05-02 00:48:51 +00:00
func buildUpdates ( engine * Engine , table * core . Table , bean interface { } ,
2014-04-05 14:14:00 +00:00
includeVersion bool , includeUpdated bool , includeNil bool ,
2014-03-24 12:41:07 +00:00
includeAutoIncr bool , allUseBool bool , useAllCols bool ,
2015-03-03 07:14:44 +00:00
mustColumnMap map [ string ] bool , columnMap map [ string ] bool , update bool ) ( [ ] string , [ ] interface { } ) {
2013-12-18 03:31:32 +00:00
colNames := make ( [ ] string , 0 )
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
}
2014-11-05 06:29:34 +00:00
if col . IsDeleted {
2014-11-03 13:03:12 +00:00
continue
}
2015-03-03 07:14:44 +00:00
if use , ok := columnMap [ col . Name ] ; ok && ! use {
continue
}
2014-05-23 06:18:45 +00:00
2014-01-07 09:33:27 +00:00
if engine . dialect . DBType ( ) == core . MSSQL && col . SQLType . Name == core . Text {
2013-12-20 06:53:40 +00:00
continue
}
2014-06-11 06:01:14 +00:00
2014-01-09 06:44:41 +00:00
fieldValuePtr , err := col . ValueOf ( bean )
if err != nil {
engine . LogError ( 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 ( ) )
2014-03-24 12:41:07 +00:00
requiredField := useAllCols
2014-05-31 04:19:46 +00:00
includeNil := useAllCols
2014-04-06 04:58:16 +00:00
if b , ok := mustColumnMap [ strings . ToLower ( col . Name ) ] ; ok {
if b {
requiredField = true
} else {
continue
}
}
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 . LogError ( err )
} 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 . LogError ( err )
} 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
}
2014-07-11 17:40:41 +00:00
t := int64 ( fieldValue . Uint ( ) )
val = reflect . ValueOf ( & t ) . Interface ( )
2013-12-18 03:31:32 +00:00
case reflect . Struct :
if fieldType == reflect . TypeOf ( time . Now ( ) ) {
t := fieldValue . Interface ( ) . ( time . Time )
if ! requiredField && ( t . IsZero ( ) || ! fieldValue . IsValid ( ) ) {
continue
}
2014-04-15 15:27:08 +00:00
val = engine . FormatTime ( col . SQLType . Name , t )
2013-12-18 03:31:32 +00:00
} else {
2014-04-08 08:46:23 +00:00
engine . autoMapType ( fieldValue )
2013-12-18 03:31:32 +00:00
if table , ok := engine . Tables [ fieldValue . Type ( ) ] ; ok {
2013-12-24 10:18:48 +00:00
if len ( table . PrimaryKeys ) == 1 {
pkField := reflect . Indirect ( fieldValue ) . FieldByName ( table . PKColumns ( ) [ 0 ] . FieldName )
2015-03-10 01:15:50 +00:00
// fix non-int pk issues
//if pkField.Int() != 0 {
2015-03-12 09:46:24 +00:00
if pkField . IsValid ( ) && ! isZero ( pkField . Interface ( ) ) {
2013-12-24 10:18:48 +00:00
val = pkField . Interface ( )
} else {
continue
}
2013-12-18 03:31:32 +00:00
} else {
2013-12-24 10:18:48 +00:00
//TODO: how to handler?
2015-03-12 09:46:24 +00:00
panic ( "not supported" )
2013-12-18 03:31:32 +00:00
}
} else {
val = fieldValue . Interface ( )
}
}
case reflect . Array , reflect . Slice , reflect . Map :
if fieldValue == reflect . Zero ( fieldType ) {
continue
}
2013-12-20 06:53:40 +00:00
if fieldValue . IsNil ( ) || ! fieldValue . IsValid ( ) || fieldValue . Len ( ) == 0 {
2013-12-18 03:31:32 +00:00
continue
}
if col . SQLType . IsText ( ) {
bytes , err := json . Marshal ( fieldValue . Interface ( ) )
if err != nil {
2014-02-11 17:35:26 +00:00
engine . LogError ( err )
2013-12-18 03:31:32 +00:00
continue
}
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 . Marshal ( fieldValue . Interface ( ) )
if err != nil {
2014-02-11 17:35:26 +00:00
engine . LogError ( 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 :
//fmt.Println("==", col.Name, "==", fmt.Sprintf("%v", val))
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
}
2013-11-06 07:36:38 +00:00
// Auto generating conditions according a struct
2014-01-07 09:33:27 +00:00
func buildConditions ( engine * Engine , table * core . Table , bean interface { } ,
2014-04-05 14:14:00 +00:00
includeVersion bool , includeUpdated bool , includeNil bool ,
2014-11-05 07:04:53 +00:00
includeAutoIncr bool , allUseBool bool , useAllCols bool , unscoped bool ,
2014-04-06 04:58:16 +00:00
mustColumnMap map [ string ] bool ) ( [ ] string , [ ] interface { } ) {
2013-12-18 03:31:32 +00:00
colNames := make ( [ ] string , 0 )
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
}
if ! includeUpdated && col . IsUpdated {
continue
}
2013-12-20 06:53:40 +00:00
if ! includeAutoIncr && col . IsAutoIncrement {
continue
}
2014-05-23 06:18:45 +00:00
2014-01-07 09:33:27 +00:00
if engine . dialect . DBType ( ) == core . MSSQL && col . SQLType . Name == core . Text {
2013-12-20 06:53:40 +00:00
continue
}
2014-01-09 06:44:41 +00:00
fieldValuePtr , err := col . ValueOf ( bean )
if err != nil {
engine . LogError ( err )
2013-12-20 06:53:40 +00:00
continue
}
2014-01-09 06:44:41 +00:00
2014-11-05 07:04:53 +00:00
if col . IsDeleted && ! unscoped { // tag "deleted" is enabled
2014-11-23 10:04:22 +00:00
colNames = append ( colNames , fmt . Sprintf ( "(%v IS NULL or %v = '0001-01-01 00:00:00')" , engine . Quote ( col . Name ) , engine . Quote ( col . Name ) ) )
2014-11-03 13:03:12 +00:00
}
2014-01-09 06:44:41 +00:00
fieldValue := * fieldValuePtr
2014-05-04 05:53:38 +00:00
if fieldValue . Interface ( ) == nil {
continue
}
2013-12-18 03:31:32 +00:00
2014-05-04 05:53:38 +00:00
fieldType := reflect . TypeOf ( fieldValue . Interface ( ) )
2014-03-24 12:41:07 +00:00
requiredField := useAllCols
2014-04-06 04:58:16 +00:00
if b , ok := mustColumnMap [ strings . ToLower ( col . Name ) ] ; ok {
if b {
requiredField = true
} else {
continue
}
}
2013-12-18 03:31:32 +00:00
if fieldType . Kind ( ) == reflect . Ptr {
if fieldValue . IsNil ( ) {
if includeNil {
args = append ( args , nil )
2014-05-07 07:56:33 +00:00
colNames = append ( colNames , fmt . Sprintf ( "%v %s ?" , engine . Quote ( col . Name ) , engine . dialect . EqStr ( ) ) )
2013-12-18 03:31:32 +00:00
}
continue
} else if ! fieldValue . IsValid ( ) {
2014-04-29 06:16:53 +00:00
continue
} else {
2013-12-18 03:31:32 +00:00
// dereference ptr type to instance type
fieldValue = fieldValue . Elem ( )
fieldType = reflect . TypeOf ( fieldValue . Interface ( ) )
requiredField = true
2014-04-29 06:16:53 +00:00
}
2013-12-18 03:31:32 +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 ( )
2014-04-29 06:16:53 +00:00
} else {
2013-12-18 03:31:32 +00:00
val = fieldValue . Interface ( )
2014-04-29 06:16:53 +00:00
}
2013-12-18 03:31:32 +00:00
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
}
2014-07-11 17:40:41 +00:00
t := int64 ( fieldValue . Uint ( ) )
val = reflect . ValueOf ( & t ) . Interface ( )
2013-12-18 03:31:32 +00:00
case reflect . Struct :
2015-02-28 09:31:51 +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
}
2014-04-15 15:27:08 +00:00
val = engine . FormatTime ( col . SQLType . Name , t )
2015-02-22 15:52:53 +00:00
} else if _ , ok := reflect . New ( fieldType ) . Interface ( ) . ( core . Conversion ) ; ok {
continue
2013-12-18 03:31:32 +00:00
} else {
2014-04-08 08:46:23 +00:00
engine . autoMapType ( fieldValue )
2013-12-18 03:31:32 +00:00
if table , ok := engine . Tables [ fieldValue . Type ( ) ] ; ok {
2013-12-24 10:18:48 +00:00
if len ( table . PrimaryKeys ) == 1 {
pkField := reflect . Indirect ( fieldValue ) . FieldByName ( table . PKColumns ( ) [ 0 ] . FieldName )
2015-03-09 14:00:34 +00:00
// fix non-int pk issues
//if pkField.Int() != 0 {
2015-03-12 09:46:24 +00:00
if pkField . IsValid ( ) && ! isZero ( pkField . Interface ( ) ) {
2013-12-24 10:18:48 +00:00
val = pkField . Interface ( )
} else {
continue
}
2013-12-18 03:31:32 +00:00
} else {
2013-12-24 10:18:48 +00:00
//TODO: how to handler?
2015-03-12 09:46:24 +00:00
panic ( "not supported" )
2013-12-18 03:31:32 +00:00
}
} else {
val = fieldValue . Interface ( )
}
}
case reflect . Array , reflect . Slice , reflect . Map :
if fieldValue == reflect . Zero ( fieldType ) {
continue
}
2013-12-20 06:53:40 +00:00
if fieldValue . IsNil ( ) || ! fieldValue . IsValid ( ) || fieldValue . Len ( ) == 0 {
2013-12-18 03:31:32 +00:00
continue
}
if col . SQLType . IsText ( ) {
bytes , err := json . Marshal ( fieldValue . Interface ( ) )
if err != nil {
2014-02-11 17:35:26 +00:00
engine . LogError ( err )
2013-12-18 03:31:32 +00:00
continue
}
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 . Marshal ( fieldValue . Interface ( ) )
if err != nil {
2014-02-11 17:35:26 +00:00
engine . LogError ( err )
2013-12-18 03:31:32 +00:00
continue
}
val = bytes
}
} else {
continue
}
default :
val = fieldValue . Interface ( )
}
args = append ( args , val )
2014-05-07 07:56:33 +00:00
var condi string
if col . IsPrimaryKey && engine . dialect . DBType ( ) == "ql" {
condi = "id() == ?"
} else {
condi = fmt . Sprintf ( "%v %s ?" , engine . Quote ( col . Name ) , engine . dialect . EqStr ( ) )
2014-04-29 06:16:53 +00:00
}
colNames = append ( colNames , condi )
2013-12-18 03:31:32 +00:00
}
return colNames , args
2013-05-19 05:25:52 +00:00
}
2013-11-22 06:11:07 +00:00
// 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
2013-12-18 03:31:32 +00:00
if statement . RefTable != nil {
return statement . RefTable . Name
}
return ""
2013-05-19 05:25:52 +00:00
}
2014-01-25 02:07:11 +00:00
var (
ptrPkType = reflect . TypeOf ( & core . PK { } )
pkType = reflect . TypeOf ( core . PK { } )
)
2013-12-17 01:38:20 +00:00
// Generate "where id = ? " statment or for composite key "where key1 = ? and key2 = ?"
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 :
if pkPtr , ok := ( id ) . ( * core . PK ) ; ok {
2013-12-18 03:31:32 +00:00
statement . IdParam = pkPtr
}
2014-01-25 02:07:11 +00:00
case pkType :
if pk , ok := ( id ) . ( core . PK ) ; ok {
2013-12-18 03:31:32 +00:00
statement . IdParam = & pk
}
default :
2014-04-17 02:13:16 +00:00
// TODO: treat as int primitve for now, need to handle type check?
2014-01-25 02:07:11 +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
2014-04-15 01:54:49 +00:00
// Generate "Update ... Set column = column + arg" statment
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
}
2014-07-15 15:25:24 +00:00
// Generate "Update ... Set column = column - arg" statment
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
}
2015-01-28 05:23:01 +00:00
// Generate "Update ... Set column = {expression}" statment
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
}
2014-04-15 01:54:49 +00:00
// Generate "Update ... Set column = column + arg" statment
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
2014-07-15 15:25:24 +00:00
// Generate "Update ... Set column = column - arg" statment
func ( statement * Statement ) getDec ( ) map [ string ] decrParam {
return statement . decrColumns
}
2015-01-28 05:23:01 +00:00
// Generate "Update ... Set column = {expression}" statment
func ( statement * Statement ) getExpr ( ) map [ string ] exprParam {
return statement . exprColumns
}
2013-11-22 06:11:07 +00:00
// Generate "Where column IN (?) " statment
func ( statement * Statement ) In ( column string , args ... interface { } ) * Statement {
2013-12-18 03:31:32 +00:00
k := strings . ToLower ( column )
2014-05-06 07:16:23 +00:00
var newargs [ ] interface { }
if len ( args ) == 1 &&
reflect . TypeOf ( args [ 0 ] ) . Kind ( ) == reflect . Slice {
newargs = make ( [ ] interface { } , 0 )
v := reflect . ValueOf ( args [ 0 ] )
for i := 0 ; i < v . Len ( ) ; i ++ {
newargs = append ( newargs , v . Index ( i ) . Interface ( ) )
}
} else {
newargs = args
}
2014-01-09 09:55:33 +00:00
if _ , ok := statement . inColumns [ k ] ; ok {
2014-05-06 07:16:23 +00:00
statement . inColumns [ k ] . args = append ( statement . inColumns [ k ] . args , newargs ... )
2013-12-18 03:31:32 +00:00
} else {
2014-05-06 07:16:23 +00:00
statement . inColumns [ k ] = & inParam { column , newargs }
2013-12-18 03:31:32 +00:00
}
return statement
2013-12-11 08:27:33 +00:00
}
func ( statement * Statement ) genInSql ( ) ( string , [ ] interface { } ) {
2013-12-18 03:31:32 +00:00
if len ( statement . inColumns ) == 0 {
return "" , [ ] interface { } { }
}
2013-12-11 08:27:33 +00:00
2013-12-18 03:31:32 +00:00
inStrs := make ( [ ] string , 0 , len ( statement . inColumns ) )
args := make ( [ ] interface { } , 0 )
2014-01-09 09:55:33 +00:00
for _ , params := range statement . inColumns {
inStrs = append ( inStrs , fmt . Sprintf ( "(%v IN (%v))" ,
2014-11-21 15:40:59 +00:00
statement . Engine . autoQuote ( params . colName ) ,
2014-01-09 09:55:33 +00:00
strings . Join ( makeArray ( "?" , len ( params . args ) ) , "," ) ) )
args = append ( args , params . args ... )
2013-12-18 03:31:32 +00:00
}
2013-12-11 08:27:33 +00:00
2013-12-18 03:31:32 +00:00
if len ( statement . inColumns ) == 1 {
return inStrs [ 0 ] , args
}
2014-04-17 02:13:16 +00:00
return fmt . Sprintf ( "(%v)" , strings . Join ( inStrs , " " + statement . Engine . dialect . AndStr ( ) + " " ) ) , args
2013-12-11 08:27:33 +00:00
}
func ( statement * Statement ) attachInSql ( ) {
2013-12-18 03:31:32 +00:00
inSql , inArgs := statement . genInSql ( )
if len ( inSql ) > 0 {
if statement . ConditionStr != "" {
2014-04-17 02:13:16 +00:00
statement . ConditionStr += " " + statement . Engine . dialect . AndStr ( ) + " "
2013-12-18 03:31:32 +00:00
}
statement . ConditionStr += inSql
statement . Params = append ( statement . Params , inArgs ... )
}
2013-05-11 08:27:17 +00:00
}
2013-10-04 16:44:43 +00:00
func col2NewCols ( columns ... string ) [ ] string {
2013-12-18 03:31:32 +00:00
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 , ` " ` , "" , - 1 )
2013-12-18 03:31:32 +00:00
ccols := strings . Split ( col , "," )
for _ , c := range ccols {
newColumns = append ( newColumns , strings . TrimSpace ( c ) )
}
}
return newColumns
2013-10-04 16:44:43 +00:00
}
2014-11-21 15:40:59 +00:00
func ( engine * Engine ) autoQuote ( col string ) string {
col = strings . Replace ( col , "`" , "" , - 1 )
col = strings . Replace ( col , engine . QuoteStr ( ) , "" , - 1 )
fields := strings . Split ( strings . TrimSpace ( col ) , "." )
for i , field := range fields {
fields [ i ] = engine . Quote ( field )
}
return strings . Join ( fields , "." )
}
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 {
newColumns = append ( newColumns , statement . Engine . Quote ( fields [ 0 ] ) )
} else if len ( fields ) == 2 {
newColumns = append ( newColumns , statement . Engine . Quote ( fields [ 0 ] ) + "." +
statement . Engine . Quote ( fields [ 1 ] ) )
} else {
panic ( errors . New ( "unwanted colnames" ) )
}
}
}
return newColumns
}
2013-11-22 06:11:07 +00:00
// Generate "Distince col1, col2 " statment
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
}
2013-11-22 06:11:07 +00:00
// Generate "col1, col2" statement
func ( statement * Statement ) Cols ( columns ... string ) * Statement {
2013-12-18 03:31:32 +00:00
newColumns := col2NewCols ( columns ... )
for _ , nc := range newColumns {
2014-01-08 14:47:30 +00:00
statement . columnMap [ strings . ToLower ( nc ) ] = true
2013-12-18 03:31:32 +00:00
}
statement . ColumnStr = statement . Engine . Quote ( strings . Join ( newColumns , statement . Engine . Quote ( ", " ) ) )
2014-04-13 02:03:07 +00:00
if strings . Contains ( statement . ColumnStr , "." ) {
statement . ColumnStr = strings . Replace ( statement . ColumnStr , "." , statement . Engine . Quote ( "." ) , - 1 )
}
2013-12-18 03:31:32 +00:00
return statement
2013-08-08 05:24:38 +00:00
}
2014-04-06 04:58:16 +00:00
// Update use only: update all columns
2014-03-24 12:41:07 +00:00
func ( statement * Statement ) AllCols ( ) * Statement {
statement . useAllCols = true
return statement
}
2014-04-06 04:58:16 +00:00
// 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
}
// Update use only: not update columns
/ * func ( statement * Statement ) NotCols ( columns ... string ) * Statement {
newColumns := col2NewCols ( columns ... )
for _ , nc := range newColumns {
statement . mustColumnMap [ strings . ToLower ( nc ) ] = false
}
return statement
} * /
2013-11-22 06:11:07 +00:00
// indicates that use bool fields as update contents and query contiditions
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
}
2013-11-22 06:11:07 +00:00
// 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 {
2014-01-08 14:47:30 +00:00
statement . columnMap [ strings . ToLower ( nc ) ] = false
2013-12-18 03:31:32 +00:00
}
statement . OmitStr = statement . Engine . Quote ( strings . Join ( newColumns , statement . Engine . Quote ( ", " ) ) )
2013-10-17 04:50:46 +00:00
}
2013-11-22 06:11:07 +00:00
// 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
}
2013-11-22 06:11:07 +00:00
// Generate LIMIT start, limit statement
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
}
2013-11-22 06:11:07 +00:00
// Generate "Order By order" statement
func ( statement * Statement ) OrderBy ( order string ) * Statement {
2014-08-18 13:20:18 +00:00
if statement . OrderStr != "" {
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
}
2014-08-18 13:20:18 +00:00
func ( statement * Statement ) Desc ( colNames ... string ) * Statement {
if statement . OrderStr != "" {
statement . OrderStr += ", "
}
newColNames := statement . col2NewColsWithQuote ( colNames ... )
sqlStr := strings . Join ( newColNames , " DESC, " )
statement . OrderStr += sqlStr + " DESC"
return statement
}
// Method Asc provide asc order by query condition, the input parameters are columns.
func ( statement * Statement ) Asc ( colNames ... string ) * Statement {
if statement . OrderStr != "" {
statement . OrderStr += ", "
}
newColNames := statement . col2NewColsWithQuote ( colNames ... )
sqlStr := strings . Join ( newColNames , " ASC, " )
statement . OrderStr += sqlStr + " ASC"
return statement
}
2013-05-06 08:01:17 +00:00
//The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
2014-11-18 16:41:03 +00:00
func ( statement * Statement ) Join ( join_operator string , tablename interface { } , condition string ) * Statement {
var joinTable string
switch tablename . ( type ) {
case [ ] string :
t := tablename . ( [ ] string )
l := len ( t )
if l > 1 {
table := t [ 0 ]
joinTable = statement . Engine . Quote ( table ) + " AS " + statement . Engine . Quote ( t [ 1 ] )
} else if l == 1 {
table := t [ 0 ]
joinTable = statement . Engine . Quote ( table )
}
case [ ] interface { } :
t := tablename . ( [ ] interface { } )
l := len ( t )
table := ""
if l > 0 {
f := t [ 0 ]
v := rValue ( f )
t := v . Type ( )
if t . Kind ( ) == reflect . String {
table = f . ( string )
} else if t . Kind ( ) == reflect . Struct {
r := statement . Engine . autoMapType ( v )
table = r . Name
}
}
if l > 1 {
joinTable = statement . Engine . Quote ( table ) + " AS " + statement . Engine . Quote ( fmt . Sprintf ( "%v" , t [ 1 ] ) )
} else if l == 1 {
joinTable = statement . Engine . Quote ( table )
}
default :
t := fmt . Sprintf ( "%v" , tablename )
joinTable = statement . Engine . Quote ( t )
}
2013-12-18 03:31:32 +00:00
if statement . JoinStr != "" {
2014-09-07 01:18:54 +00:00
statement . JoinStr = statement . JoinStr + fmt . Sprintf ( " %v JOIN %v ON %v" , join_operator ,
2014-11-18 16:41:03 +00:00
joinTable , condition )
2013-12-18 03:31:32 +00:00
} else {
2014-09-07 01:18:54 +00:00
statement . JoinStr = fmt . Sprintf ( "%v JOIN %v ON %v" , join_operator ,
2014-11-18 16:41:03 +00:00
joinTable , condition )
2013-12-18 03:31:32 +00:00
}
return statement
2013-05-06 08:01:17 +00:00
}
2013-11-22 06:11:07 +00:00
// Generate "Group By keys" statement
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
}
2013-11-22 06:11:07 +00:00
// Generate "Having conditions" statement
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
}
2014-11-05 07:04:53 +00:00
// Always disable struct tag "deleted"
func ( statement * Statement ) Unscoped ( ) * Statement {
statement . unscoped = true
return statement
}
2013-08-08 05:24:38 +00:00
func ( statement * Statement ) genColumnStr ( ) string {
2013-12-18 03:31:32 +00:00
table := statement . RefTable
colNames := make ( [ ] string , 0 )
2014-01-07 09:33:27 +00:00
for _ , col := range table . Columns ( ) {
2013-12-18 03:31:32 +00:00
if statement . OmitStr != "" {
2014-01-08 14:47:30 +00:00
if _ , ok := statement . columnMap [ strings . ToLower ( col . Name ) ] ; ok {
2013-12-18 03:31:32 +00:00
continue
}
}
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 statement . JoinStr != "" {
2014-11-18 16:41:03 +00:00
var name string
if statement . TableAlias != "" {
name = statement . Engine . Quote ( statement . TableAlias )
} else {
name = statement . Engine . Quote ( statement . TableName ( ) )
}
name += "." + statement . Engine . Quote ( col . Name )
2014-04-29 06:16:53 +00:00
if col . IsPrimaryKey && statement . Engine . Dialect ( ) . DBType ( ) == "ql" {
2014-11-18 16:41:03 +00:00
colNames = append ( colNames , "id() AS " + name )
2014-04-29 06:16:53 +00:00
} else {
colNames = append ( colNames , name )
}
} else {
name := statement . Engine . Quote ( col . Name )
if col . IsPrimaryKey && statement . Engine . Dialect ( ) . DBType ( ) == "ql" {
2014-11-18 16:41:03 +00:00
colNames = append ( colNames , "id() AS " + name )
2014-04-29 06:16:53 +00:00
} else {
colNames = append ( colNames , name )
}
}
2013-12-18 03:31:32 +00:00
}
return strings . Join ( colNames , ", " )
2013-05-19 05:25:52 +00:00
}
2013-12-17 01:38:20 +00:00
func ( statement * Statement ) genCreateTableSQL ( ) string {
2014-01-07 09:33:27 +00:00
return statement . Engine . dialect . CreateTableSql ( statement . RefTable , statement . AltTableName ,
statement . StoreEngine , statement . Charset )
2013-07-27 04:24:38 +00:00
}
2013-09-28 15:14:42 +00:00
func indexName ( tableName , idxName string ) string {
2013-12-18 03:31:32 +00:00
return fmt . Sprintf ( "IDX_%v_%v" , tableName , idxName )
2013-09-28 15:14:42 +00:00
}
func ( s * Statement ) genIndexSQL ( ) [ ] string {
2013-12-18 03:31:32 +00:00
var sqls [ ] string = make ( [ ] string , 0 )
tbName := s . TableName ( )
quote := s . Engine . Quote
for idxName , index := range s . RefTable . Indexes {
2014-01-07 09:33:27 +00:00
if index . Type == core . IndexType {
2013-12-18 03:31:32 +00:00
sql := fmt . Sprintf ( "CREATE INDEX %v ON %v (%v);" , quote ( indexName ( tbName , idxName ) ) ,
quote ( tbName ) , quote ( strings . Join ( index . Cols , quote ( "," ) ) ) )
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
}
2013-10-04 16:44:43 +00:00
func ( s * Statement ) genUniqueSQL ( ) [ ] string {
2013-12-18 03:31:32 +00:00
var sqls [ ] string = make ( [ ] string , 0 )
tbName := s . TableName ( )
2014-04-17 02:13:16 +00:00
for _ , index := range s . RefTable . Indexes {
if index . Type == core . UniqueType {
sql := s . 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
}
2013-09-28 15:14:42 +00:00
func ( s * Statement ) genDelIndexSQL ( ) [ ] string {
2013-12-18 03:31:32 +00:00
var sqls [ ] string = make ( [ ] string , 0 )
for idxName , index := range s . RefTable . Indexes {
var rIdxName string
2014-01-07 09:33:27 +00:00
if index . Type == core . UniqueType {
2013-12-18 03:31:32 +00:00
rIdxName = uniqueName ( s . TableName ( ) , idxName )
2014-01-07 09:33:27 +00:00
} else if index . Type == core . IndexType {
2013-12-18 03:31:32 +00:00
rIdxName = indexName ( s . TableName ( ) , idxName )
}
sql := fmt . Sprintf ( "DROP INDEX %v" , s . Engine . Quote ( rIdxName ) )
if s . Engine . dialect . IndexOnTable ( ) {
sql += fmt . Sprintf ( " ON %v" , s . Engine . Quote ( s . TableName ( ) ) )
}
sqls = append ( sqls , sql )
}
return sqls
2013-09-26 07:19:39 +00:00
}
2013-09-28 15:14:42 +00:00
func ( s * Statement ) genDropSQL ( ) string {
2014-04-05 14:14:00 +00:00
return s . Engine . dialect . DropTableSql ( s . TableName ( ) ) + ";"
2013-05-19 05:25:52 +00:00
}
2013-12-11 08:27:33 +00:00
func ( statement * Statement ) genGetSql ( bean interface { } ) ( string , [ ] interface { } ) {
2014-05-23 06:18:45 +00:00
var table * core . Table
if statement . RefTable == nil {
2014-08-28 16:34:09 +00:00
table = statement . Engine . TableInfo ( bean )
2014-05-23 06:18:45 +00:00
statement . RefTable = table
} else {
table = statement . RefTable
}
2013-05-19 05:25:52 +00:00
2013-12-18 03:31:32 +00:00
colNames , args := buildConditions ( statement . Engine , table , bean , true , true ,
2014-03-24 12:41:07 +00:00
false , true , statement . allUseBool , statement . useAllCols ,
2014-11-05 07:04:53 +00:00
statement . unscoped , statement . mustColumnMap )
2013-12-07 20:27:48 +00:00
2014-04-17 02:13:16 +00:00
statement . ConditionStr = strings . Join ( colNames , " " + statement . Engine . dialect . AndStr ( ) + " " )
2013-12-18 03:31:32 +00:00
statement . BeanArgs = args
2013-05-19 05:25:52 +00:00
2013-12-18 03:31:32 +00:00
var columnStr string = statement . ColumnStr
2014-05-23 06:18:45 +00:00
if statement . JoinStr == "" {
if columnStr == "" {
columnStr = statement . genColumnStr ( )
}
} else {
if columnStr == "" {
columnStr = "*"
}
2013-12-18 03:31:32 +00:00
}
2014-05-15 14:32:57 +00:00
2014-05-12 03:25:36 +00:00
statement . attachInSql ( ) // !admpub! fix bug:Iterate func missing "... IN (...)"
2013-12-18 03:31:32 +00:00
return statement . genSelectSql ( columnStr ) , append ( statement . Params , statement . BeanArgs ... )
2013-05-19 05:25:52 +00:00
}
2014-01-07 09:33:27 +00:00
func ( s * Statement ) genAddColumnStr ( col * core . Column ) ( string , [ ] interface { } ) {
2013-12-18 03:31:32 +00:00
quote := s . Engine . Quote
2014-05-06 06:59:58 +00:00
sql := fmt . Sprintf ( "ALTER TABLE %v ADD %v;" , quote ( s . TableName ( ) ) ,
2013-12-18 03:31:32 +00:00
col . String ( s . Engine . dialect ) )
return sql , [ ] interface { } { }
2013-09-28 15:14:42 +00:00
}
2014-04-17 02:13:16 +00:00
/ * func ( s * Statement ) genAddIndexStr ( idxName string , cols [ ] string ) ( string , [ ] interface { } ) {
2013-12-18 03:31:32 +00:00
quote := s . Engine . Quote
colstr := quote ( strings . Join ( cols , quote ( ", " ) ) )
sql := fmt . Sprintf ( "CREATE INDEX %v ON %v (%v);" , quote ( idxName ) , quote ( s . TableName ( ) ) , colstr )
return sql , [ ] interface { } { }
2013-09-28 15:14:42 +00:00
}
func ( s * Statement ) genAddUniqueStr ( uqeName string , cols [ ] string ) ( string , [ ] interface { } ) {
2013-12-18 03:31:32 +00:00
quote := s . Engine . Quote
colstr := quote ( strings . Join ( cols , quote ( ", " ) ) )
sql := fmt . Sprintf ( "CREATE UNIQUE INDEX %v ON %v (%v);" , quote ( uqeName ) , quote ( s . TableName ( ) ) , colstr )
return sql , [ ] interface { } { }
2014-04-17 02:13:16 +00:00
} * /
2013-12-11 08:27:33 +00:00
func ( statement * Statement ) genCountSql ( bean interface { } ) ( string , [ ] interface { } ) {
2014-08-28 16:34:09 +00:00
table := statement . Engine . TableInfo ( bean )
2013-12-18 03:31:32 +00:00
statement . RefTable = table
2013-12-11 08:27:33 +00:00
2013-12-18 03:31:32 +00:00
colNames , args := buildConditions ( statement . Engine , table , bean , true , true , false ,
2014-11-05 07:04:53 +00:00
true , statement . allUseBool , statement . useAllCols ,
statement . unscoped , statement . mustColumnMap )
2013-12-11 08:27:33 +00:00
2014-04-29 06:16:53 +00:00
statement . ConditionStr = strings . Join ( colNames , " " + statement . Engine . Dialect ( ) . AndStr ( ) + " " )
2013-12-18 03:31:32 +00:00
statement . BeanArgs = args
2014-05-07 07:56:33 +00:00
2013-12-24 10:18:48 +00:00
// count(index fieldname) > count(0) > count(*)
2014-05-07 07:56:33 +00:00
var id string = "*"
2014-04-29 06:16:53 +00:00
if statement . Engine . Dialect ( ) . DBType ( ) == "ql" {
id = ""
2013-12-18 03:31:32 +00:00
}
2014-08-08 06:05:51 +00:00
statement . attachInSql ( )
2014-04-29 06:16:53 +00:00
return statement . genSelectSql ( fmt . Sprintf ( "count(%v) AS %v" , id , statement . Engine . Quote ( "total" ) ) ) , append ( statement . Params , statement . BeanArgs ... )
2013-12-11 08:27:33 +00:00
}
func ( statement * Statement ) genSelectSql ( columnStr string ) ( a string ) {
2013-12-18 03:31:32 +00:00
if statement . GroupByStr != "" {
2015-01-23 08:25:28 +00:00
if columnStr == "" {
columnStr = statement . Engine . Quote ( strings . Replace ( statement . GroupByStr , "," , statement . Engine . Quote ( "," ) , - 1 ) )
}
2015-02-13 06:40:08 +00:00
//statement.GroupByStr = columnStr
2013-12-18 03:31:32 +00:00
}
var distinct string
if statement . IsDistinct {
distinct = "DISTINCT "
}
2014-05-06 03:11:44 +00:00
var top string
var mssqlCondi string
2014-10-09 12:57:57 +00:00
/ * var orderBy string
2014-05-06 03:11:44 +00:00
if statement . OrderStr != "" {
orderBy = fmt . Sprintf ( " ORDER BY %v" , statement . OrderStr )
2014-10-09 12:57:57 +00:00
} * /
2013-12-18 03:31:32 +00:00
statement . processIdParam ( )
2014-05-06 03:11:44 +00:00
var whereStr string
2013-12-18 03:31:32 +00:00
if statement . WhereStr != "" {
2014-05-06 03:11:44 +00:00
whereStr = fmt . Sprintf ( " WHERE %v" , statement . WhereStr )
2013-12-18 03:31:32 +00:00
if statement . ConditionStr != "" {
2014-05-07 07:56:33 +00:00
whereStr = fmt . Sprintf ( "%v %s %v" , whereStr , statement . Engine . Dialect ( ) . AndStr ( ) ,
2014-04-29 06:16:53 +00:00
statement . ConditionStr )
2013-12-18 03:31:32 +00:00
}
} else if statement . ConditionStr != "" {
2014-05-06 03:11:44 +00:00
whereStr = fmt . Sprintf ( " WHERE %v" , statement . ConditionStr )
}
var fromStr string = " FROM " + statement . Engine . Quote ( statement . TableName ( ) )
2014-11-18 16:41:03 +00:00
if statement . TableAlias != "" {
2015-03-05 01:56:15 +00:00
if statement . Engine . dialect . DBType ( ) == core . ORACLE {
fromStr += " " + statement . Engine . Quote ( statement . TableAlias )
} else {
fromStr += " AS " + statement . Engine . 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 )
}
if statement . Engine . 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 {
var column string = "(id)"
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 ]
}
}
2015-01-13 09:17:34 +00:00
var orderStr string
if 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
}
}
// !nashtsai! REVIEW Sprintf is considered slowest mean of string concatnation, better to work with builder pattern
a = fmt . Sprintf ( "SELECT %v%v%v%v%v" , top , distinct , columnStr ,
fromStr , whereStr )
if mssqlCondi != "" {
2014-05-06 06:19:37 +00:00
if whereStr != "" {
a += " AND " + mssqlCondi
} else {
a += " WHERE " + mssqlCondi
}
2013-12-18 03:31:32 +00:00
}
if statement . GroupByStr != "" {
a = fmt . Sprintf ( "%v GROUP BY %v" , a , statement . GroupByStr )
}
if statement . HavingStr != "" {
a = fmt . Sprintf ( "%v %v" , a , statement . HavingStr )
}
if statement . OrderStr != "" {
a = fmt . Sprintf ( "%v ORDER BY %v" , a , statement . OrderStr )
}
2015-03-05 01:56:15 +00:00
if statement . Engine . dialect . DBType ( ) != core . MSSQL && statement . Engine . dialect . DBType ( ) != core . ORACLE {
2013-12-20 06:53:40 +00:00
if statement . Start > 0 {
a = fmt . Sprintf ( "%v LIMIT %v OFFSET %v" , a , statement . LimitN , statement . Start )
} else if statement . LimitN > 0 {
a = fmt . Sprintf ( "%v LIMIT %v" , a , statement . LimitN )
}
2015-03-05 01:56:15 +00:00
} else if statement . Engine . dialect . DBType ( ) == core . ORACLE {
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 )
}
2013-12-18 03:31:32 +00:00
}
2013-12-20 06:53:40 +00:00
2013-12-18 03:31:32 +00:00
return
2013-05-03 07:26:51 +00:00
}
2013-12-17 01:38:20 +00:00
func ( statement * Statement ) processIdParam ( ) {
2013-12-18 03:31:32 +00:00
if statement . IdParam != nil {
2014-04-29 06:16:53 +00:00
if statement . Engine . dialect . DBType ( ) != "ql" {
for i , col := range statement . RefTable . PKColumns ( ) {
if i < len ( * ( statement . IdParam ) ) {
statement . And ( fmt . Sprintf ( "%v %s ?" , statement . Engine . Quote ( col . Name ) ,
statement . Engine . dialect . EqStr ( ) ) , ( * ( statement . IdParam ) ) [ i ] )
} else {
statement . And ( fmt . Sprintf ( "%v %s ?" , statement . Engine . Quote ( col . Name ) ,
statement . Engine . dialect . EqStr ( ) ) , "" )
}
}
} else {
if len ( * ( statement . IdParam ) ) <= 1 {
statement . And ( "id() == ?" , ( * ( statement . IdParam ) ) [ 0 ] )
2013-12-18 03:31:32 +00:00
}
}
}
2013-12-17 01:38:20 +00:00
}