Merge remote-tracking branch 'origin/master' into feature/cacher-tag

This commit is contained in:
Nash Tsai 2014-08-22 16:55:43 +08:00
commit 48798e566f
7 changed files with 264 additions and 68 deletions

View File

@ -31,13 +31,16 @@ type Engine struct {
mutex *sync.RWMutex mutex *sync.RWMutex
Cacher core.Cacher Cacher core.Cacher
ShowSQL bool
// !nashtsai! TODO ought to deprecate these but having logger to control its log level
ShowInfo bool ShowInfo bool
ShowSQL bool
ShowErr bool ShowErr bool
ShowDebug bool ShowDebug bool
ShowWarn bool ShowWarn bool
// --
Logger ILogger // io.Writer Logger core.ILogger
TZLocation *time.Location TZLocation *time.Location
disableGlobalCache bool disableGlobalCache bool
@ -182,6 +185,7 @@ func (engine *Engine) Ping() error {
// logging sql // logging sql
func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) { func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
if engine.ShowSQL { if engine.ShowSQL {
overrideLogLevel(LOG_INFO)
if len(sqlArgs) > 0 { if len(sqlArgs) > 0 {
engine.Logger.Info(fmt.Sprintf("[sql] %v [args] %v", sqlStr, sqlArgs)) engine.Logger.Info(fmt.Sprintf("[sql] %v [args] %v", sqlStr, sqlArgs))
} else { } else {
@ -215,54 +219,73 @@ func (engine *Engine) LogSQLExecutionTime(sqlStr string, args interface{}, execu
} }
// logging error // logging error
func (engine *Engine) overrideLogLevel(overrideLevel core.LogLevel) {
logLevel := engine.Logger.Level()
if logLevel == core.LOG_UNKNOWN {
// intend to left empty
}
else if logLevel < core.overrideLevel { // TODO can remove if deprecated engine.ShowErr
engine.Logger.SetLevel(LOG_ERR) // try override logger's log level
}
}
func (engine *Engine) LogError(contents ...interface{}) { func (engine *Engine) LogError(contents ...interface{}) {
if engine.ShowErr { if engine.ShowErr {
engine.Logger.Err(fmt.Sprint(contents...)) overrideLogLevel(LOG_ERR)
engine.Logger.Err(contents...)
} }
} }
func (engine *Engine) LogErrorf(format string, contents ...interface{}) { func (engine *Engine) LogErrorf(format string, contents ...interface{}) {
if engine.ShowErr { if engine.ShowErr {
engine.Logger.Err(fmt.Sprintf(format, contents...)) overrideLogLevel(LOG_ERR)
engine.Logger.Errf(format, contents...)
} }
} }
// logging info // logging info
func (engine *Engine) LogInfo(contents ...interface{}) { func (engine *Engine) LogInfo(contents ...interface{}) {
if engine.ShowInfo { if engine.ShowInfo {
engine.Logger.Info(fmt.Sprint(contents...)) overrideLogLevel(LOG_INFO)
engine.Logger.Info(contents...)
} }
} }
func (engine *Engine) LogInfof(format string, contents ...interface{}) { func (engine *Engine) LogInfof(format string, contents ...interface{}) {
if engine.ShowErr { if engine.ShowErr {
engine.Logger.Info(fmt.Sprintf(format, contents...)) overrideLogLevel(LOG_INFO)
engine.Logger.Infof(format, contents...)
} }
} }
// logging debug // logging debug
func (engine *Engine) LogDebug(contents ...interface{}) { func (engine *Engine) LogDebug(contents ...interface{}) {
if engine.ShowDebug { if engine.ShowDebug {
engine.Logger.Debug(fmt.Sprint(contents...)) overrideLogLevel(LOG_DEBUG)
engine.Logger.Debug(contents...)
} }
} }
func (engine *Engine) LogDebugf(format string, contents ...interface{}) { func (engine *Engine) LogDebugf(format string, contents ...interface{}) {
if engine.ShowDebug { if engine.ShowDebug {
engine.Logger.Debug(fmt.Sprintf(format, contents...)) overrideLogLevel(LOG_DEBUG)
engine.Logger.Debugf(format, contents...)
} }
} }
// logging warn // logging warn
func (engine *Engine) LogWarn(contents ...interface{}) { func (engine *Engine) LogWarn(contents ...interface{}) {
if engine.ShowWarn { if engine.ShowWarn {
engine.Logger.Warning(fmt.Sprint(contents...)) overrideLogLevel(LOG_WARNING)
engine.Logger.Warning(contents...)
} }
} }
func (engine *Engine) LogWarnf(format string, contents ...interface{}) { func (engine *Engine) LogWarnf(format string, contents ...interface{}) {
if engine.ShowWarn { if engine.ShowWarn {
engine.Logger.Warning(fmt.Sprintf(format, contents...)) overrideLogLevel(LOG_WARNING)
engine.Logger.Warningf(format, contents...)
} }
} }
@ -1467,8 +1490,16 @@ func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
return results, lastError return results, lastError
} }
var (
NULL_TIME time.Time
)
func (engine *Engine) TZTime(t time.Time) time.Time { func (engine *Engine) TZTime(t time.Time) time.Time {
return t.In(engine.TZLocation)
if NULL_TIME != t { // if time is not initialized it's not suitable for Time.In()
return t.In(engine.TZLocation)
}
return t
} }
func (engine *Engine) NowTime(sqlTypeName string) interface{} { func (engine *Engine) NowTime(sqlTypeName string) interface{} {

View File

@ -4,57 +4,103 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"github.com/go-xorm/core"
) )
// logger interface, log/syslog conform with this interface const (
type ILogger interface { DEFAULT_LOG_PREFIX = "[xorm]"
Debug(m string) (err error) DEFAULT_LOG_FLAG = log.Ldate | log.Lmicroseconds
Err(m string) (err error) DEFAULT_LOG_LEVEL = core.LOG_DEBUG
Info(m string) (err error) )
Warning(m string) (err error)
}
type SimpleLogger struct { type SimpleLogger struct {
DEBUG *log.Logger DEBUG *log.Logger
ERR *log.Logger ERR *log.Logger
INFO *log.Logger INFO *log.Logger
WARN *log.Logger WARN *log.Logger
level core.LogLevel
} }
func NewSimpleLogger(out io.Writer) *SimpleLogger { func NewSimpleLogger(out io.Writer) *SimpleLogger {
return &SimpleLogger{ return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
DEBUG: log.New(out, "[xorm] [debug] ", log.Ldate|log.Lmicroseconds),
ERR: log.New(out, "[xorm] [error] ", log.Ldate|log.Lmicroseconds),
INFO: log.New(out, "[xorm] [info] ", log.Ldate|log.Lmicroseconds),
WARN: log.New(out, "[xorm] [warn] ", log.Ldate|log.Lmicroseconds),
}
} }
func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger { func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger {
return NewSimpleLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL)
}
func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *SimpleLogger {
return &SimpleLogger{ return &SimpleLogger{
DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), log.Ldate|log.Lmicroseconds), DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), flag),
ERR: log.New(out, fmt.Sprintf("%s [error] ", prefix), log.Ldate|log.Lmicroseconds), ERR: log.New(out, fmt.Sprintf("%s [error] ", prefix), flag),
INFO: log.New(out, fmt.Sprintf("%s [info] ", prefix), log.Ldate|log.Lmicroseconds), INFO: log.New(out, fmt.Sprintf("%s [info] ", prefix), flag),
WARN: log.New(out, fmt.Sprintf("%s [warn] ", prefix), log.Ldate|log.Lmicroseconds), WARN: log.New(out, fmt.Sprintf("%s [warn] ", prefix), flag),
level: l,
} }
} }
func (s *SimpleLogger) Debug(m string) (err error) { func (s *SimpleLogger) Err(v ...interface{}) (err error) {
s.DEBUG.Println(m) if s.level > core.LOG_OFF && s.level <= core.LOG_ERR {
s.ERR.Println(v...)
}
return return
} }
func (s *SimpleLogger) Err(m string) (err error) { func (s *SimpleLogger) Errf(format string, v ...interface{}) (err error) {
s.ERR.Println(m) if s.level > core.LOG_OFF && s.level <= core.LOG_ERR {
s.ERR.Printf(format, v...)
}
return return
} }
func (s *SimpleLogger) Info(m string) (err error) { func (s *SimpleLogger) Debug(v ...interface{}) (err error) {
s.INFO.Println(m) if s.level > core.LOG_OFF && s.level <= core.LOG_DEBUG {
s.DEBUG.Println(v...)
}
return return
} }
func (s *SimpleLogger) Warning(m string) (err error) { func (s *SimpleLogger) Debugf(format string, v ...interface{}) (err error) {
s.WARN.Println(m) if s.level > core.LOG_OFF && s.level >= core.LOG_DEBUG {
s.DEBUG.Printf(format, v...)
}
return
}
func (s *SimpleLogger) Info(v ...interface{}) (err error) {
if s.level > core.LOG_OFF && s.level >= core.LOG_INFO {
s.INFO.Println(v...)
}
return
}
func (s *SimpleLogger) Infof(format string, v ...interface{}) (err error) {
if s.level > core.LOG_OFF && s.level >= core.LOG_INFO {
s.INFO.Printf(format, v...)
}
return
}
func (s *SimpleLogger) Warning(v ...interface{}) (err error) {
if s.level > core.LOG_OFF && s.level >= core.LOG_WARNING {
s.WARN.Println(v...)
}
return
}
func (s *SimpleLogger) Warningf(format string, v ...interface{}) (err error) {
if s.level > core.LOG_OFF && s.level >= core.LOG_WARNING {
s.WARN.Printf(format, v...)
}
return
}
func (s *SimpleLogger) Level() core.LogLevel {
return s.level
}
func (s *SimpleLogger) SetLevel(l core.LogLevel) (err error) {
s.level = l
return return
} }

View File

@ -24,7 +24,7 @@ type LRUCacher struct {
} }
func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher { func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
return NewLRUCacher2(store, 0, maxElementSize) return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
} }
func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher { func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {

View File

@ -56,24 +56,20 @@ func (db *mysql) SqlType(c *core.Column) string {
case core.Enum: //mysql enum case core.Enum: //mysql enum
res = core.Enum res = core.Enum
res += "(" res += "("
for v, k := range c.EnumOptions { opts := ""
if k > 0 { for v, _ := range c.EnumOptions {
res += fmt.Sprintf(",'%v'", v) opts += fmt.Sprintf(",'%v'", v)
} else {
res += fmt.Sprintf("'%v'", v)
}
} }
res += strings.TrimLeft(opts,",")
res += ")" res += ")"
case core.Set: //mysql set case core.Set: //mysql set
res = core.Set res = core.Set
res += "(" res += "("
for v, k := range c.SetOptions { opts := ""
if k > 0 { for v, _ := range c.SetOptions {
res += fmt.Sprintf(",'%v'", v) opts += fmt.Sprintf(",'%v'", v)
} else {
res += fmt.Sprintf("'%v'", v)
}
} }
res += strings.TrimLeft(opts,",")
res += ")" res += ")"
default: default:
res = t res = t

View File

@ -219,12 +219,7 @@ func (session *Session) OrderBy(order string) *Session {
// Method Desc provide desc order by query condition, the input parameters are columns. // Method Desc provide desc order by query condition, the input parameters are columns.
func (session *Session) Desc(colNames ...string) *Session { func (session *Session) Desc(colNames ...string) *Session {
if session.Statement.OrderStr != "" { session.Statement.Desc(colNames...)
session.Statement.OrderStr += ", "
}
newColNames := col2NewCols(colNames...)
sqlStr := strings.Join(newColNames, session.Engine.Quote(" DESC, "))
session.Statement.OrderStr += session.Engine.Quote(sqlStr) + " DESC"
return session return session
} }
@ -850,8 +845,9 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
for j := 0; j < len(temps); j++ { for j := 0; j < len(temps); j++ {
bean := temps[j] bean := temps[j]
if bean == nil { if bean == nil {
session.Engine.LogError("[xorm:cacheFind] cache error:", tableName, ides[j], bean) session.Engine.LogWarn("[xorm:cacheFind] cache no hit:", tableName, ides[j])
return errors.New("cache error") // return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
continue
} }
if sliceValue.Kind() == reflect.Slice { if sliceValue.Kind() == reflect.Slice {
if t.Kind() == reflect.Ptr { if t.Kind() == reflect.Ptr {
@ -1186,16 +1182,15 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
} }
} }
for rawRows.Next() { var newValue reflect.Value = newElemFunc()
var newValue reflect.Value = newElemFunc() dataStruct := rValue(newValue.Interface())
if sliceValueSetFunc != nil { if dataStruct.Kind() != reflect.Struct {
err := session.row2Bean(rawRows, fields, fieldsCount, newValue.Interface()) return errors.New("Expected a pointer to a struct")
if err != nil {
return err
}
sliceValueSetFunc(&newValue)
}
} }
table := session.Engine.autoMapType(dataStruct)
return session.rows2Beans(rawRows, fields, fieldsCount, table, newElemFunc, sliceValueSetFunc)
} else { } else {
resultsSlice, err := session.query(sqlStr, args...) resultsSlice, err := session.query(sqlStr, args...)
if err != nil { if err != nil {
@ -1452,6 +1447,24 @@ func (session *Session) getField(dataStruct *reflect.Value, key string, table *c
type Cell *interface{} type Cell *interface{}
func (session *Session) rows2Beans(rows *core.Rows, fields []string, fieldsCount int,
table *core.Table, newElemFunc func() reflect.Value,
sliceValueSetFunc func(*reflect.Value)) error {
for rows.Next() {
var newValue reflect.Value = newElemFunc()
bean := newValue.Interface()
dataStruct := rValue(bean)
err := session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table)
if err != nil {
return err
}
sliceValueSetFunc(&newValue)
}
return nil
}
func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error { func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error {
dataStruct := rValue(bean) dataStruct := rValue(bean)
if dataStruct.Kind() != reflect.Struct { if dataStruct.Kind() != reflect.Struct {
@ -1459,8 +1472,12 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
} }
table := session.Engine.autoMapType(dataStruct) table := session.Engine.autoMapType(dataStruct)
return session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table)
}
scanResults := make([]interface{}, len(fields)) func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) error {
scanResults := make([]interface{}, fieldsCount)
for i := 0; i < len(fields); i++ { for i := 0; i < len(fields); i++ {
var cell interface{} var cell interface{}
scanResults[i] = &cell scanResults[i] = &cell
@ -1486,7 +1503,7 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
} }
tempMap[strings.ToLower(key)] = idx tempMap[strings.ToLower(key)] = idx
if fieldValue := session.getField(&dataStruct, key, table, idx); fieldValue != nil { if fieldValue := session.getField(dataStruct, key, table, idx); fieldValue != nil {
rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii])) rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
//if row is null then ignore //if row is null then ignore

View File

@ -2,6 +2,7 @@ package xorm
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@ -87,6 +88,7 @@ func (statement *Statement) Init() {
statement.UseAutoTime = true statement.UseAutoTime = true
statement.IsDistinct = false statement.IsDistinct = false
statement.allUseBool = false statement.allUseBool = false
statement.useAllCols = false
statement.mustColumnMap = make(map[string]bool) statement.mustColumnMap = make(map[string]bool)
statement.checkVersion = true statement.checkVersion = true
statement.inColumns = make(map[string]*inParam) statement.inColumns = make(map[string]*inParam)
@ -771,6 +773,27 @@ func col2NewCols(columns ...string) []string {
return newColumns return newColumns
} }
func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
newColumns := make([]string, 0)
for _, col := range columns {
strings.Replace(col, "`", "", -1)
strings.Replace(col, statement.Engine.QuoteStr(), "", -1)
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
}
// Generate "Distince col1, col2 " statment // Generate "Distince col1, col2 " statment
func (statement *Statement) Distinct(columns ...string) *Statement { func (statement *Statement) Distinct(columns ...string) *Statement {
statement.IsDistinct = true statement.IsDistinct = true
@ -851,10 +874,34 @@ func (statement *Statement) Limit(limit int, start ...int) *Statement {
// Generate "Order By order" statement // Generate "Order By order" statement
func (statement *Statement) OrderBy(order string) *Statement { func (statement *Statement) OrderBy(order string) *Statement {
if statement.OrderStr != "" {
statement.OrderStr += ", "
}
statement.OrderStr = order statement.OrderStr = order
return statement return statement
} }
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
}
//The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN //The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (statement *Statement) Join(join_operator, tablename, condition string) *Statement { func (statement *Statement) Join(join_operator, tablename, condition string) *Statement {
if statement.JoinStr != "" { if statement.JoinStr != "" {

59
syslogger.go Normal file
View File

@ -0,0 +1,59 @@
// +build !windows,!nacl,!plan9
package xorm
import (
"fmt"
"log/syslog"
"github.com/go-xorm/core"
)
type SyslogLogger struct {
w *syslog.Writer
}
func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
return &SyslogLogger{w: w}
}
func (s *SyslogLogger) Debug(v ...interface{}) (err error) {
return s.w.Debug(fmt.Sprint(v...))
}
func (s *SyslogLogger) Debugf(format string, v ...interface{}) (err error) {
return s.w.Debug(fmt.Sprintf(format, v...))
}
func (s *SyslogLogger) Err(v ...interface{}) (err error) {
return s.w.Err(fmt.Sprint(v...))
}
func (s *SyslogLogger) Errf(format string, v ...interface{}) (err error) {
return s.w.Err(fmt.Sprintf(format, v...))
}
func (s *SyslogLogger) Info(v ...interface{}) (err error) {
return s.w.Info(fmt.Sprint(v...))
}
func (s *SyslogLogger) Infof(format string, v ...interface{}) (err error) {
return s.w.Info(fmt.Sprintf(format, v...))
}
func (s *SyslogLogger) Warning(v ...interface{}) (err error) {
return s.w.Warning(fmt.Sprint(v...))
}
func (s *SyslogLogger) Warningf(format string, v ...interface{}) (err error) {
return s.w.Warning(fmt.Sprintf(format, v...))
}
func (s *SyslogLogger) Level() core.LogLevel {
return core.LOG_UNKNOWN
}
// SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
func (s *SyslogLogger) SetLevel(l core.LogLevel) (err error) {
return fmt.Errorf("unable to set syslog level")
}