diff --git a/engine.go b/engine.go index a035a63d..afb38766 100644 --- a/engine.go +++ b/engine.go @@ -726,33 +726,24 @@ func (engine *Engine) newTable() *core.Table { return table } +type TableName interface { + TableName() string +} + func (engine *Engine) mapType(v reflect.Value) *core.Table { t := v.Type() table := engine.newTable() - method := v.MethodByName("TableName") - if !method.IsValid() { - if v.CanAddr() { - method = v.Addr().MethodByName("TableName") - } - } - if method.IsValid() { - params := []reflect.Value{} - results := method.Call(params) - if len(results) == 1 { - table.Name = results[0].Interface().(string) - } - } - - if table.Name == "" { + if tb, ok := v.Interface().(TableName); ok { + table.Name = tb.TableName() + } else { table.Name = engine.TableMapper.Obj2Table(t.Name()) } + table.Type = t var idFieldColName string var err error - - hasCacheTag := false - hasNoCacheTag := false + var hasCacheTag, hasNoCacheTag bool for i := 0; i < t.NumField(); i++ { tag := t.Field(i).Tag @@ -839,6 +830,16 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { case k == "VERSION": col.IsVersion = true col.Default = "1" + case k == "UTC": + col.TimeZone = time.UTC + case k == "LOCAL": + col.TimeZone = time.Local + case strings.HasPrefix(k, "LOCALE(") && strings.HasSuffix(k, ")"): + location := k[len("INDEX")+1 : len(k)-1] + col.TimeZone, err = time.LoadLocation(location) + if err != nil { + engine.LogError(err) + } case k == "UPDATED": col.IsUpdated = true case k == "DELETED": @@ -1422,7 +1423,6 @@ var ( ) func (engine *Engine) TZTime(t time.Time) time.Time { - if NULL_TIME != t { // if time is not initialized it's not suitable for Time.In() return t.In(engine.TZLocation) } @@ -1440,35 +1440,51 @@ func (engine *Engine) NowTime2(sqlTypeName string) (interface{}, time.Time) { } func (engine *Engine) FormatTime(sqlTypeName string, t time.Time) (v interface{}) { + return engine.formatTime(engine.TZLocation, sqlTypeName, t) +} + +func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) { + if col.DisableTimeZone { + return engine.formatTime(nil, col.SQLType.Name, t) + } else if col.TimeZone != nil { + return engine.formatTime(col.TimeZone, col.SQLType.Name, t) + } + return engine.formatTime(engine.TZLocation, col.SQLType.Name, t) +} + +func (engine *Engine) formatTime(tz *time.Location, sqlTypeName string, t time.Time) (v interface{}) { if engine.dialect.DBType() == core.ORACLE { return t } + if tz != nil { + t = engine.TZTime(t) + } switch sqlTypeName { case core.Time: - s := engine.TZTime(t).Format("2006-01-02 15:04:05") //time.RFC3339 + s := t.Format("2006-01-02 15:04:05") //time.RFC3339 v = s[11:19] case core.Date: - v = engine.TZTime(t).Format("2006-01-02") + v = t.Format("2006-01-02") case core.DateTime, core.TimeStamp: if engine.dialect.DBType() == "ql" { - v = engine.TZTime(t) + v = t } else if engine.dialect.DBType() == "sqlite3" { - v = engine.TZTime(t).UTC().Format("2006-01-02 15:04:05") + v = t.UTC().Format("2006-01-02 15:04:05") } else { - v = engine.TZTime(t).Format("2006-01-02 15:04:05") + v = t.Format("2006-01-02 15:04:05") } case core.TimeStampz: if engine.dialect.DBType() == core.MSSQL { - v = engine.TZTime(t).Format("2006-01-02T15:04:05.9999999Z07:00") + v = t.Format("2006-01-02T15:04:05.9999999Z07:00") } else if engine.DriverName() == "mssql" { - v = engine.TZTime(t) + v = t } else { - v = engine.TZTime(t).Format(time.RFC3339Nano) + v = t.Format(time.RFC3339Nano) } case core.BigInt, core.Int: - v = engine.TZTime(t).Unix() + v = t.Unix() default: - v = engine.TZTime(t) + v = t } return } diff --git a/session.go b/session.go index eb0b7855..5d4e95c2 100644 --- a/session.go +++ b/session.go @@ -1792,7 +1792,11 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount t.Minute(), t.Second(), t.Nanosecond(), time.Local) } // !nashtsai! convert to engine location - t = t.In(session.Engine.TZLocation) + if col.TimeZone == nil { + t = t.In(session.Engine.TZLocation) + } else { + t = t.In(col.TimeZone) + } fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) // t = fieldValue.Interface().(time.Time) @@ -1801,7 +1805,13 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount } else if rawValueType == core.IntType || rawValueType == core.Int64Type || rawValueType == core.Int32Type { hasAssigned = true - t := time.Unix(vv.Int(), 0).In(session.Engine.TZLocation) + var tz *time.Location + if col.TimeZone == nil { + tz = session.Engine.TZLocation + } else { + tz = col.TimeZone + } + t := time.Unix(vv.Int(), 0).In(tz) //vv = reflect.ValueOf(t) fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) } else { @@ -2382,10 +2392,12 @@ func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.T x = time.Unix(sd, 0) // !nashtsai! HACK mymysql driver is casuing Local location being change to CHAT and cause wrong time conversion //fmt.Println(x.In(session.Engine.TZLocation), "===") - x = x.In(session.Engine.TZLocation) + if col.TimeZone == nil { + x = x.In(session.Engine.TZLocation) + } else { + x = x.In(col.TimeZone) + } //fmt.Println(x, "=====") - /*x = time.Date(x.Year(), x.Month(), x.Day(), x.Hour(), - x.Minute(), x.Second(), x.Nanosecond(), session.Engine.TZLocation)*/ session.Engine.LogDebugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) } else { session.Engine.LogDebugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) diff --git a/statement.go b/statement.go index 444f4e93..bf6b3779 100644 --- a/statement.go +++ b/statement.go @@ -121,7 +121,7 @@ func (statement *Statement) Init() { statement.exprColumns = make(map[string]exprParam) } -// NoAutoCondition +// NoAutoCondition if you do not want convert bean's field as query condition, then use this function func (statement *Statement) NoAutoCondition(no ...bool) *Statement { statement.noAutoCondition = true if len(no) > 0 { @@ -130,20 +130,20 @@ func (statement *Statement) NoAutoCondition(no ...bool) *Statement { return statement } -// add the raw sql statement +// Sql add the raw sql statement func (statement *Statement) Sql(querystring string, args ...interface{}) *Statement { statement.RawSQL = querystring statement.RawParams = args return statement } -// set the table alias +// Alias set the table alias func (statement *Statement) Alias(alias string) *Statement { statement.TableAlias = alias return statement } -// add Where statment +// Where add Where statment func (statement *Statement) Where(querystring string, args ...interface{}) *Statement { if !strings.Contains(querystring, statement.Engine.dialect.EqStr()) { querystring = strings.Replace(querystring, "=", statement.Engine.dialect.EqStr(), -1) @@ -153,7 +153,7 @@ func (statement *Statement) Where(querystring string, args ...interface{}) *Stat return statement } -// add Where & and statment +// And add Where & and statment func (statement *Statement) And(querystring string, args ...interface{}) *Statement { if len(statement.WhereStr) > 0 { var buf bytes.Buffer @@ -167,7 +167,7 @@ func (statement *Statement) And(querystring string, args ...interface{}) *Statem return statement } -// add Where & Or statment +// Or add Where & Or statment func (statement *Statement) Or(querystring string, args ...interface{}) *Statement { if len(statement.WhereStr) > 0 { var buf bytes.Buffer @@ -181,7 +181,7 @@ func (statement *Statement) Or(querystring string, args ...interface{}) *Stateme return statement } -// tempororily set table name +// 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() @@ -684,7 +684,7 @@ func (statement *Statement) Id(id interface{}) *Statement { return statement } -// Generate "Update ... Set column = column + arg" statment +// Incr Generate "Update ... Set column = column + arg" statment func (statement *Statement) Incr(column string, arg ...interface{}) *Statement { k := strings.ToLower(column) if len(arg) > 0 { @@ -695,7 +695,7 @@ func (statement *Statement) Incr(column string, arg ...interface{}) *Statement { return statement } -// Generate "Update ... Set column = column - arg" statment +// Decr Generate "Update ... Set column = column - arg" statment func (statement *Statement) Decr(column string, arg ...interface{}) *Statement { k := strings.ToLower(column) if len(arg) > 0 { @@ -706,7 +706,7 @@ func (statement *Statement) Decr(column string, arg ...interface{}) *Statement { return statement } -// Generate "Update ... Set column = {expression}" statment +// SetExpr Generate "Update ... Set column = {expression}" statment func (statement *Statement) SetExpr(column string, expression string) *Statement { k := strings.ToLower(column) statement.exprColumns[k] = exprParam{column, expression} @@ -1214,7 +1214,8 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) { distinct = "DISTINCT " } - var dialect core.Dialect = statement.Engine.Dialect() + var dialect = statement.Engine.Dialect() + var quote = statement.Engine.Quote var top string var mssqlCondi string @@ -1235,12 +1236,12 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) { } var whereStr = buf.String() - var fromStr string = " FROM " + statement.Engine.Quote(statement.TableName()) + var fromStr string = " FROM " + quote(statement.TableName()) if statement.TableAlias != "" { if dialect.DBType() == core.ORACLE { - fromStr += " " + statement.Engine.Quote(statement.TableAlias) + fromStr += " " + quote(statement.TableAlias) } else { - fromStr += " AS " + statement.Engine.Quote(statement.TableAlias) + fromStr += " AS " + quote(statement.TableAlias) } } if statement.JoinStr != "" {