diff options
Diffstat (limited to 'vendor/github.com/go-xorm/xorm/statement.go')
-rw-r--r-- | vendor/github.com/go-xorm/xorm/statement.go | 280 |
1 files changed, 128 insertions, 152 deletions
diff --git a/vendor/github.com/go-xorm/xorm/statement.go b/vendor/github.com/go-xorm/xorm/statement.go index 6400425b20..7856936f5c 100644 --- a/vendor/github.com/go-xorm/xorm/statement.go +++ b/vendor/github.com/go-xorm/xorm/statement.go @@ -5,7 +5,6 @@ package xorm import ( - "bytes" "database/sql/driver" "encoding/json" "errors" @@ -18,21 +17,6 @@ import ( "github.com/go-xorm/core" ) -type incrParam struct { - colName string - arg interface{} -} - -type decrParam struct { - colName string - arg interface{} -} - -type exprParam struct { - colName string - expr string -} - // Statement save all the sql info for executing SQL type Statement struct { RefTable *core.Table @@ -47,7 +31,6 @@ type Statement struct { HavingStr string ColumnStr string selectStr string - columnMap map[string]bool useAllCols bool OmitStr string AltTableName string @@ -67,6 +50,8 @@ type Statement struct { allUseBool bool checkVersion bool unscoped bool + columnMap columnMap + omitColumnMap columnMap mustColumnMap map[string]bool nullableMap map[string]bool incrColumns map[string]incrParam @@ -89,7 +74,8 @@ func (statement *Statement) Init() { statement.HavingStr = "" statement.ColumnStr = "" statement.OmitStr = "" - statement.columnMap = make(map[string]bool) + statement.columnMap = columnMap{} + statement.omitColumnMap = columnMap{} statement.AltTableName = "" statement.tableName = "" statement.idParam = nil @@ -221,34 +207,33 @@ func (statement *Statement) setRefValue(v reflect.Value) error { if err != nil { return err } - statement.tableName = statement.Engine.tbName(v) + statement.tableName = statement.Engine.TableName(v, true) return nil } -// Table tempororily set table name, the parameter could be a string or a pointer of struct -func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { - v := rValue(tableNameOrBean) - t := v.Type() - if t.Kind() == reflect.String { - statement.AltTableName = tableNameOrBean.(string) - } else if t.Kind() == reflect.Struct { - var err error - statement.RefTable, err = statement.Engine.autoMapType(v) - if err != nil { - statement.Engine.logger.Error(err) - return statement - } - statement.AltTableName = statement.Engine.tbName(v) +func (statement *Statement) setRefBean(bean interface{}) error { + var err error + statement.RefTable, err = statement.Engine.autoMapType(rValue(bean)) + if err != nil { + return err } - return statement + statement.tableName = statement.Engine.TableName(bean, true) + return nil } // Auto generating update columnes and values according a struct -func buildUpdates(engine *Engine, table *core.Table, bean interface{}, - includeVersion bool, includeUpdated bool, includeNil bool, - includeAutoIncr bool, allUseBool bool, useAllCols bool, - mustColumnMap map[string]bool, nullableMap map[string]bool, - columnMap map[string]bool, update, unscoped bool) ([]string, []interface{}) { +func (statement *Statement) buildUpdates(bean interface{}, + includeVersion, includeUpdated, includeNil, + includeAutoIncr, update bool) ([]string, []interface{}) { + engine := statement.Engine + table := statement.RefTable + allUseBool := statement.allUseBool + useAllCols := statement.useAllCols + mustColumnMap := statement.mustColumnMap + nullableMap := statement.nullableMap + columnMap := statement.columnMap + omitColumnMap := statement.omitColumnMap + unscoped := statement.unscoped var colNames = make([]string, 0) var args = make([]interface{}, 0) @@ -268,7 +253,14 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{}, if col.IsDeleted && !unscoped { continue } - if use, ok := columnMap[strings.ToLower(col.Name)]; ok && !use { + if omitColumnMap.contain(col.Name) { + continue + } + if len(columnMap) > 0 && !columnMap.contain(col.Name) { + continue + } + + if col.MapType == core.ONLYFROMDB { continue } @@ -604,17 +596,10 @@ func (statement *Statement) col2NewColsWithQuote(columns ...string) []string { } func (statement *Statement) colmap2NewColsWithQuote() []string { - newColumns := make([]string, 0, len(statement.columnMap)) - for col := range statement.columnMap { - fields := strings.Split(strings.TrimSpace(col), ".") - 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")) - } + newColumns := make([]string, len(statement.columnMap), len(statement.columnMap)) + copy(newColumns, statement.columnMap) + for i := 0; i < len(statement.columnMap); i++ { + newColumns[i] = statement.Engine.Quote(newColumns[i]) } return newColumns } @@ -642,10 +627,11 @@ func (statement *Statement) Select(str string) *Statement { func (statement *Statement) Cols(columns ...string) *Statement { cols := col2NewCols(columns...) for _, nc := range cols { - statement.columnMap[strings.ToLower(nc)] = true + statement.columnMap.add(nc) } newColumns := statement.colmap2NewColsWithQuote() + statement.ColumnStr = strings.Join(newColumns, ", ") statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.quote("*"), "*", -1) return statement @@ -680,7 +666,7 @@ func (statement *Statement) UseBool(columns ...string) *Statement { func (statement *Statement) Omit(columns ...string) { newColumns := col2NewCols(columns...) for _, nc := range newColumns { - statement.columnMap[strings.ToLower(nc)] = false + statement.omitColumnMap = append(statement.omitColumnMap, nc) } statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", "))) } @@ -719,10 +705,9 @@ func (statement *Statement) OrderBy(order string) *Statement { // Desc generate `ORDER BY xx DESC` func (statement *Statement) Desc(colNames ...string) *Statement { - var buf bytes.Buffer - fmt.Fprintf(&buf, statement.OrderStr) + var buf builder.StringBuilder if len(statement.OrderStr) > 0 { - fmt.Fprint(&buf, ", ") + fmt.Fprint(&buf, statement.OrderStr, ", ") } newColNames := statement.col2NewColsWithQuote(colNames...) fmt.Fprintf(&buf, "%v DESC", strings.Join(newColNames, " DESC, ")) @@ -732,10 +717,9 @@ func (statement *Statement) Desc(colNames ...string) *Statement { // Asc provide asc order by query condition, the input parameters are columns. func (statement *Statement) Asc(colNames ...string) *Statement { - var buf bytes.Buffer - fmt.Fprintf(&buf, statement.OrderStr) + var buf builder.StringBuilder if len(statement.OrderStr) > 0 { - fmt.Fprint(&buf, ", ") + fmt.Fprint(&buf, statement.OrderStr, ", ") } newColNames := statement.col2NewColsWithQuote(colNames...) fmt.Fprintf(&buf, "%v ASC", strings.Join(newColNames, " ASC, ")) @@ -743,48 +727,35 @@ func (statement *Statement) Asc(colNames ...string) *Statement { return statement } +// Table tempororily set table name, the parameter could be a string or a pointer of struct +func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { + v := rValue(tableNameOrBean) + t := v.Type() + if t.Kind() == reflect.Struct { + var err error + statement.RefTable, err = statement.Engine.autoMapType(v) + if err != nil { + statement.Engine.logger.Error(err) + return statement + } + } + + statement.AltTableName = statement.Engine.TableName(tableNameOrBean, true) + return statement +} + // Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement { - var buf bytes.Buffer + var buf builder.StringBuilder if len(statement.JoinStr) > 0 { fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP) } else { fmt.Fprintf(&buf, "%v JOIN ", joinOP) } - switch tablename.(type) { - case []string: - t := tablename.([]string) - if len(t) > 1 { - fmt.Fprintf(&buf, "%v AS %v", statement.Engine.Quote(t[0]), statement.Engine.Quote(t[1])) - } else if len(t) == 1 { - fmt.Fprintf(&buf, statement.Engine.Quote(t[0])) - } - case []interface{}: - t := tablename.([]interface{}) - l := len(t) - var table string - 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 { - table = statement.Engine.tbName(v) - } - } - if l > 1 { - fmt.Fprintf(&buf, "%v AS %v", statement.Engine.Quote(table), - statement.Engine.Quote(fmt.Sprintf("%v", t[1]))) - } else if l == 1 { - fmt.Fprintf(&buf, statement.Engine.Quote(table)) - } - default: - fmt.Fprintf(&buf, statement.Engine.Quote(fmt.Sprintf("%v", tablename))) - } + tbName := statement.Engine.TableName(tablename, true) - fmt.Fprintf(&buf, " ON %v", condition) + fmt.Fprintf(&buf, "%s ON %v", tbName, condition) statement.JoinStr = buf.String() statement.joinArgs = append(statement.joinArgs, args...) return statement @@ -809,18 +780,20 @@ func (statement *Statement) Unscoped() *Statement { } func (statement *Statement) genColumnStr() string { - var buf bytes.Buffer if statement.RefTable == nil { return "" } + var buf builder.StringBuilder columns := statement.RefTable.Columns() for _, col := range columns { - if statement.OmitStr != "" { - if _, ok := getFlagForColumn(statement.columnMap, col); ok { - continue - } + if statement.omitColumnMap.contain(col.Name) { + continue + } + + if len(statement.columnMap) > 0 && !statement.columnMap.contain(col.Name) { + continue } if col.MapType == core.ONLYTODB { @@ -831,10 +804,6 @@ func (statement *Statement) genColumnStr() string { buf.WriteString(", ") } - if col.IsPrimaryKey && statement.Engine.Dialect().DBType() == "ql" { - buf.WriteString("id() AS ") - } - if statement.JoinStr != "" { if statement.TableAlias != "" { buf.WriteString(statement.TableAlias) @@ -859,11 +828,13 @@ func (statement *Statement) genCreateTableSQL() string { func (statement *Statement) genIndexSQL() []string { var sqls []string tbName := statement.TableName() - quote := statement.Engine.Quote - for idxName, index := range statement.RefTable.Indexes { + for _, index := range statement.RefTable.Indexes { if index.Type == core.IndexType { - sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(tbName, idxName)), - quote(tbName), quote(strings.Join(index.Cols, quote(",")))) + sql := statement.Engine.dialect.CreateIndexSql(tbName, index) + /*idxTBName := strings.Replace(tbName, ".", "_", -1) + idxTBName = strings.Replace(idxTBName, `"`, "", -1) + sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(idxTBName, idxName)), + quote(tbName), quote(strings.Join(index.Cols, quote(","))))*/ sqls = append(sqls, sql) } } @@ -889,16 +860,18 @@ func (statement *Statement) genUniqueSQL() []string { func (statement *Statement) genDelIndexSQL() []string { var sqls []string tbName := statement.TableName() + idxPrefixName := strings.Replace(tbName, `"`, "", -1) + idxPrefixName = strings.Replace(idxPrefixName, `.`, "_", -1) for idxName, index := range statement.RefTable.Indexes { var rIdxName string if index.Type == core.UniqueType { - rIdxName = uniqueName(tbName, idxName) + rIdxName = uniqueName(idxPrefixName, idxName) } else if index.Type == core.IndexType { - rIdxName = indexName(tbName, idxName) + rIdxName = indexName(idxPrefixName, idxName) } - sql := fmt.Sprintf("DROP INDEX %v", statement.Engine.Quote(rIdxName)) + sql := fmt.Sprintf("DROP INDEX %v", statement.Engine.Quote(statement.Engine.TableName(rIdxName, true))) if statement.Engine.dialect.IndexOnTable() { - sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(statement.TableName())) + sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(tbName)) } sqls = append(sqls, sql) } @@ -949,7 +922,7 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}, v := rValue(bean) isStruct := v.Kind() == reflect.Struct if isStruct { - statement.setRefValue(v) + statement.setRefBean(bean) } var columnStr = statement.ColumnStr @@ -982,13 +955,17 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}, if err := statement.mergeConds(bean); err != nil { return "", nil, err } + } else { + if err := statement.processIDParam(); err != nil { + return "", nil, err + } } condSQL, condArgs, err := builder.ToSQL(statement.cond) if err != nil { return "", nil, err } - sqlStr, err := statement.genSelectSQL(columnStr, condSQL) + sqlStr, err := statement.genSelectSQL(columnStr, condSQL, true, true) if err != nil { return "", nil, err } @@ -1001,7 +978,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa var condArgs []interface{} var err error if len(beans) > 0 { - statement.setRefValue(rValue(beans[0])) + statement.setRefBean(beans[0]) condSQL, condArgs, err = statement.genConds(beans[0]) } else { condSQL, condArgs, err = builder.ToSQL(statement.cond) @@ -1018,7 +995,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa selectSQL = "count(*)" } } - sqlStr, err := statement.genSelectSQL(selectSQL, condSQL) + sqlStr, err := statement.genSelectSQL(selectSQL, condSQL, false, false) if err != nil { return "", nil, err } @@ -1027,7 +1004,7 @@ func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interfa } func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) { - statement.setRefValue(rValue(bean)) + statement.setRefBean(bean) var sumStrs = make([]string, 0, len(columns)) for _, colName := range columns { @@ -1043,7 +1020,7 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri return "", nil, err } - sqlStr, err := statement.genSelectSQL(sumSelect, condSQL) + sqlStr, err := statement.genSelectSQL(sumSelect, condSQL, true, true) if err != nil { return "", nil, err } @@ -1051,27 +1028,20 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri return sqlStr, append(statement.joinArgs, condArgs...), nil } -func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string, err error) { - var distinct string +func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, needOrderBy bool) (string, error) { + var ( + distinct string + dialect = statement.Engine.Dialect() + quote = statement.Engine.Quote + fromStr = " FROM " + top, mssqlCondi, whereStr string + ) if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") { distinct = "DISTINCT " } - - var dialect = statement.Engine.Dialect() - var quote = statement.Engine.Quote - var top string - var mssqlCondi string - - if err := statement.processIDParam(); err != nil { - return "", err - } - - var buf bytes.Buffer if len(condSQL) > 0 { - fmt.Fprintf(&buf, " WHERE %v", condSQL) + whereStr = " WHERE " + condSQL } - var whereStr = buf.String() - var fromStr = " FROM " if dialect.DBType() == core.MSSQL && strings.Contains(statement.TableName(), "..") { fromStr += statement.TableName() @@ -1118,9 +1088,10 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string, e } var orderStr string - if len(statement.OrderStr) > 0 { + if needOrderBy && len(statement.OrderStr) > 0 { orderStr = " ORDER BY " + statement.OrderStr } + var groupStr string if len(statement.GroupByStr) > 0 { groupStr = " GROUP BY " + statement.GroupByStr @@ -1130,45 +1101,50 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string) (a string, e } } - // !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", distinct, top, columnStr, fromStr, whereStr) + var buf builder.StringBuilder + fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr) if len(mssqlCondi) > 0 { if len(whereStr) > 0 { - a += " AND " + mssqlCondi + fmt.Fprint(&buf, " AND ", mssqlCondi) } else { - a += " WHERE " + mssqlCondi + fmt.Fprint(&buf, " WHERE ", mssqlCondi) } } if statement.GroupByStr != "" { - a = fmt.Sprintf("%v GROUP BY %v", a, statement.GroupByStr) + fmt.Fprint(&buf, " GROUP BY ", statement.GroupByStr) } if statement.HavingStr != "" { - a = fmt.Sprintf("%v %v", a, statement.HavingStr) + fmt.Fprint(&buf, " ", statement.HavingStr) } - if statement.OrderStr != "" { - a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr) + if needOrderBy && statement.OrderStr != "" { + fmt.Fprint(&buf, " ORDER BY ", statement.OrderStr) } - if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE { - 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) - } - } else if 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) + if needLimit { + if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE { + if statement.Start > 0 { + fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", statement.LimitN, statement.Start) + } else if statement.LimitN > 0 { + fmt.Fprint(&buf, " LIMIT ", statement.LimitN) + } + } else if dialect.DBType() == core.ORACLE { + if statement.Start != 0 || statement.LimitN != 0 { + oldString := buf.String() + buf.Reset() + fmt.Fprintf(&buf, "SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", + columnStr, columnStr, oldString, statement.Start+statement.LimitN, statement.Start) + } } } if statement.IsForUpdate { - a = dialect.ForUpdateSql(a) + return dialect.ForUpdateSql(buf.String()), nil } - return + return buf.String(), nil } func (statement *Statement) processIDParam() error { - if statement.idParam == nil { + if statement.idParam == nil || statement.RefTable == nil { return nil } |