فهرست منبع

serious extends bug fixed & correct logger file path

xormplus 9 سال پیش
والد
کامیت
858078832d
16فایلهای تغییر یافته به همراه1188 افزوده شده و 712 حذف شده
  1. 368 159
      engine.go
  2. 1 1
      engineplus.go
  3. 54 6
      helpers.go
  4. 2 4
      helpersplus.go
  5. 82 30
      logger.go
  6. 3 0
      mssql_dialect.go
  7. 4 11
      mysql_dialect.go
  8. 8 18
      oracle_dialect.go
  9. 9 16
      postgres_dialect.go
  10. 6 2
      pq_driver.go
  11. 231 169
      session.go
  12. 112 44
      sessionplus.go
  13. 9 14
      sqlite3_dialect.go
  14. 258 210
      statement.go
  15. 33 19
      syslogger.go
  16. 8 9
      xorm.go

+ 368 - 159
engine.go

@@ -37,54 +37,79 @@ type Engine struct {
 	mutex         *sync.RWMutex
 	mutex         *sync.RWMutex
 	Cacher        core.Cacher
 	Cacher        core.Cacher
 
 
-	ShowSQL bool
+	showSQL      bool
+	showExecTime bool
 
 
-	// !nashtsai! TODO ought to deprecate these but having logger to control its log level
-	ShowInfo  bool
-	ShowErr   bool
-	ShowDebug bool
-	ShowWarn  bool
-	// --227
-
-	Logger     core.ILogger
+	logger     core.ILogger
 	TZLocation *time.Location
 	TZLocation *time.Location
 
 
 	disableGlobalCache bool
 	disableGlobalCache bool
 }
 }
 
 
+// ShowSQL show SQL statment or not on logger if log level is great than INFO
+func (engine *Engine) ShowSQL(show ...bool) {
+	engine.logger.ShowSQL(show...)
+	if len(show) == 0 {
+		engine.showSQL = true
+	} else {
+		engine.showSQL = show[0]
+	}
+}
+
+// ShowExecTime show SQL statment and execute time or not on logger if log level is great than INFO
+func (engine *Engine) ShowExecTime(show ...bool) {
+	if len(show) == 0 {
+		engine.showExecTime = true
+	} else {
+		engine.showExecTime = show[0]
+	}
+}
+
+// Logger return the logger interface
+func (engine *Engine) Logger() core.ILogger {
+	return engine.logger
+}
+
+// SetLogger set the new logger
 func (engine *Engine) SetLogger(logger core.ILogger) {
 func (engine *Engine) SetLogger(logger core.ILogger) {
-	engine.Logger = logger
+	engine.logger = logger
 	engine.dialect.SetLogger(logger)
 	engine.dialect.SetLogger(logger)
 }
 }
 
 
+// SetDisableGlobalCache disable global cache or not
 func (engine *Engine) SetDisableGlobalCache(disable bool) {
 func (engine *Engine) SetDisableGlobalCache(disable bool) {
 	if engine.disableGlobalCache != disable {
 	if engine.disableGlobalCache != disable {
 		engine.disableGlobalCache = disable
 		engine.disableGlobalCache = disable
 	}
 	}
 }
 }
 
 
+// DriverName return the current sql driver's name
 func (engine *Engine) DriverName() string {
 func (engine *Engine) DriverName() string {
 	return engine.dialect.DriverName()
 	return engine.dialect.DriverName()
 }
 }
 
 
+// DataSourceName return the current connection string
 func (engine *Engine) DataSourceName() string {
 func (engine *Engine) DataSourceName() string {
 	return engine.dialect.DataSourceName()
 	return engine.dialect.DataSourceName()
 }
 }
 
 
+// SetMapper set the name mapping rules
 func (engine *Engine) SetMapper(mapper core.IMapper) {
 func (engine *Engine) SetMapper(mapper core.IMapper) {
 	engine.SetTableMapper(mapper)
 	engine.SetTableMapper(mapper)
 	engine.SetColumnMapper(mapper)
 	engine.SetColumnMapper(mapper)
 }
 }
 
 
+// SetTableMapper set the table name mapping rule
 func (engine *Engine) SetTableMapper(mapper core.IMapper) {
 func (engine *Engine) SetTableMapper(mapper core.IMapper) {
 	engine.TableMapper = mapper
 	engine.TableMapper = mapper
 }
 }
 
 
+// SetColumnMapper set the column name mapping rule
 func (engine *Engine) SetColumnMapper(mapper core.IMapper) {
 func (engine *Engine) SetColumnMapper(mapper core.IMapper) {
 	engine.ColumnMapper = mapper
 	engine.ColumnMapper = mapper
 }
 }
 
 
-// If engine's database support batch insert records like
+// SupportInsertMany If engine's database support batch insert records like
 // "insert into user values (name, age), (name, age)".
 // "insert into user values (name, age), (name, age)".
 // When the return is ture, then engine.Insert(&users) will
 // When the return is ture, then engine.Insert(&users) will
 // generate batch sql and exeute.
 // generate batch sql and exeute.
@@ -92,29 +117,57 @@ func (engine *Engine) SupportInsertMany() bool {
 	return engine.dialect.SupportInsertMany()
 	return engine.dialect.SupportInsertMany()
 }
 }
 
 
-// Engine's database use which charactor as quote.
+// QuoteStr Engine's database use which charactor as quote.
 // mysql, sqlite use ` and postgres use "
 // mysql, sqlite use ` and postgres use "
 func (engine *Engine) QuoteStr() string {
 func (engine *Engine) QuoteStr() string {
 	return engine.dialect.QuoteStr()
 	return engine.dialect.QuoteStr()
 }
 }
 
 
-// Use QuoteStr quote the string sql
+// Quote Use QuoteStr quote the string sql
 func (engine *Engine) Quote(sql string) string {
 func (engine *Engine) Quote(sql string) string {
-	if len(sql) == 0 {
-		return sql
+	return engine.quoteTable(sql)
+}
+
+func (engine *Engine) quote(sql string) string {
+	return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr()
+}
+
+func (engine *Engine) quoteColumn(keyName string) string {
+	if len(keyName) == 0 {
+		return keyName
+	}
+
+	keyName = strings.TrimSpace(keyName)
+	keyName = strings.Replace(keyName, "`", "", -1)
+	keyName = strings.Replace(keyName, engine.QuoteStr(), "", -1)
+
+	keyName = strings.Replace(keyName, ",", engine.dialect.QuoteStr()+","+engine.dialect.QuoteStr(), -1)
+	keyName = strings.Replace(keyName, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1)
+
+	return engine.dialect.QuoteStr() + keyName + engine.dialect.QuoteStr()
+}
+
+func (engine *Engine) quoteTable(keyName string) string {
+	keyName = strings.TrimSpace(keyName)
+	if len(keyName) == 0 {
+		return keyName
 	}
 	}
-	if string(sql[0]) == engine.dialect.QuoteStr() || sql[0] == '`' {
-		return sql
+
+	if string(keyName[0]) == engine.dialect.QuoteStr() || keyName[0] == '`' {
+		return keyName
 	}
 	}
-	return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr()
+
+	keyName = strings.Replace(keyName, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1)
+
+	return engine.dialect.QuoteStr() + keyName + engine.dialect.QuoteStr()
 }
 }
 
 
-// A simple wrapper to dialect's core.SqlType method
+// SqlType A simple wrapper to dialect's core.SqlType method
 func (engine *Engine) SqlType(c *core.Column) string {
 func (engine *Engine) SqlType(c *core.Column) string {
 	return engine.dialect.SqlType(c)
 	return engine.dialect.SqlType(c)
 }
 }
 
 
-// Database's autoincrement statement
+// AutoIncrStr Database's autoincrement statement
 func (engine *Engine) AutoIncrStr() string {
 func (engine *Engine) AutoIncrStr() string {
 	return engine.dialect.AutoIncrStr()
 	return engine.dialect.AutoIncrStr()
 }
 }
@@ -124,22 +177,17 @@ func (engine *Engine) SetMaxOpenConns(conns int) {
 	engine.db.SetMaxOpenConns(conns)
 	engine.db.SetMaxOpenConns(conns)
 }
 }
 
 
-// @Deprecated
-func (engine *Engine) SetMaxConns(conns int) {
-	engine.SetMaxOpenConns(conns)
-}
-
-// SetMaxIdleConns
+// SetMaxIdleConns set the max idle connections on pool, default is 2
 func (engine *Engine) SetMaxIdleConns(conns int) {
 func (engine *Engine) SetMaxIdleConns(conns int) {
 	engine.db.SetMaxIdleConns(conns)
 	engine.db.SetMaxIdleConns(conns)
 }
 }
 
 
-// SetDefaltCacher set the default cacher. Xorm's default not enable cacher.
+// SetDefaultCacher set the default cacher. Xorm's default not enable cacher.
 func (engine *Engine) SetDefaultCacher(cacher core.Cacher) {
 func (engine *Engine) SetDefaultCacher(cacher core.Cacher) {
 	engine.Cacher = cacher
 	engine.Cacher = cacher
 }
 }
 
 
-// If you has set default cacher, and you want temporilly stop use cache,
+// NoCache If you has set default cacher, and you want temporilly stop use cache,
 // you can use NoCache()
 // you can use NoCache()
 func (engine *Engine) NoCache() *Session {
 func (engine *Engine) NoCache() *Session {
 	session := engine.NewSession()
 	session := engine.NewSession()
@@ -147,13 +195,14 @@ func (engine *Engine) NoCache() *Session {
 	return session.NoCache()
 	return session.NoCache()
 }
 }
 
 
+// NoCascade If you do not want to auto cascade load object
 func (engine *Engine) NoCascade() *Session {
 func (engine *Engine) NoCascade() *Session {
 	session := engine.NewSession()
 	session := engine.NewSession()
 	session.IsAutoClose = true
 	session.IsAutoClose = true
 	return session.NoCascade()
 	return session.NoCascade()
 }
 }
 
 
-// Set a table use a special cacher
+// MapCacher Set a table use a special cacher
 func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) {
 func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) {
 	v := rValue(bean)
 	v := rValue(bean)
 	tb := engine.autoMapType(v)
 	tb := engine.autoMapType(v)
@@ -165,15 +214,17 @@ func (engine *Engine) NewDB() (*core.DB, error) {
 	return core.OpenDialect(engine.dialect)
 	return core.OpenDialect(engine.dialect)
 }
 }
 
 
+// DB return the wrapper of sql.DB
 func (engine *Engine) DB() *core.DB {
 func (engine *Engine) DB() *core.DB {
 	return engine.db
 	return engine.db
 }
 }
 
 
+// Dialect return database dialect
 func (engine *Engine) Dialect() core.Dialect {
 func (engine *Engine) Dialect() core.Dialect {
 	return engine.dialect
 	return engine.dialect
 }
 }
 
 
-// New a session
+// NewSession New a session
 func (engine *Engine) NewSession() *Session {
 func (engine *Engine) NewSession() *Session {
 	session := &Session{Engine: engine}
 	session := &Session{Engine: engine}
 	session.Init()
 	session.Init()
@@ -189,115 +240,92 @@ func (engine *Engine) Close() error {
 func (engine *Engine) Ping() error {
 func (engine *Engine) Ping() error {
 	session := engine.NewSession()
 	session := engine.NewSession()
 	defer session.Close()
 	defer session.Close()
-	engine.LogInfo("PING DATABASE", engine.DriverName)
+	engine.logger.Info("PING DATABASE", engine.DriverName)
 	return session.Ping()
 	return session.Ping()
 }
 }
 
 
 // logging sql
 // logging sql
 func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
 func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
-	if engine.ShowSQL {
-		engine.overrideLogLevel(core.LOG_INFO)
+	if engine.showSQL && !engine.showExecTime {
 		if len(sqlArgs) > 0 {
 		if len(sqlArgs) > 0 {
-			engine.Logger.Infof("[sql] %v [args] %v", sqlStr, sqlArgs)
+			engine.logger.Infof("[sql] %v [args] %v", sqlStr, sqlArgs)
 		} else {
 		} else {
-			engine.Logger.Infof("[sql] %v", sqlStr)
+			engine.logger.Infof("[sql] %v", sqlStr)
 		}
 		}
 	}
 	}
 }
 }
 
 
-func (engine *Engine) LogSQLQueryTime(sqlStr string, args interface{}, executionBlock func() (*core.Stmt, *core.Rows, error)) (*core.Stmt, *core.Rows, error) {
-	if engine.ShowDebug {
+func (engine *Engine) logSQLQueryTime(sqlStr string, args []interface{}, executionBlock func() (*core.Stmt, *core.Rows, error)) (*core.Stmt, *core.Rows, error) {
+	if engine.showSQL && engine.showExecTime {
 		b4ExecTime := time.Now()
 		b4ExecTime := time.Now()
 		stmt, res, err := executionBlock()
 		stmt, res, err := executionBlock()
 		execDuration := time.Since(b4ExecTime)
 		execDuration := time.Since(b4ExecTime)
-		engine.LogDebugf("[time] %s - args %v - query took: %vns", sqlStr, args, execDuration.Nanoseconds())
+		if len(args) > 0 {
+			engine.logger.Infof("[sql] %s [args] %v - took: %v", sqlStr, args, execDuration)
+		} else {
+			engine.logger.Infof("[sql] %s - took: %v", sqlStr, execDuration)
+		}
 		return stmt, res, err
 		return stmt, res, err
 	} else {
 	} else {
 		return executionBlock()
 		return executionBlock()
 	}
 	}
 }
 }
 
 
-func (engine *Engine) LogSQLExecutionTime(sqlStr string, args interface{}, executionBlock func() (sql.Result, error)) (sql.Result, error) {
-	if engine.ShowDebug {
+func (engine *Engine) logSQLExecutionTime(sqlStr string, args []interface{}, executionBlock func() (sql.Result, error)) (sql.Result, error) {
+	if engine.showSQL && engine.showExecTime {
 		b4ExecTime := time.Now()
 		b4ExecTime := time.Now()
 		res, err := executionBlock()
 		res, err := executionBlock()
 		execDuration := time.Since(b4ExecTime)
 		execDuration := time.Since(b4ExecTime)
-		engine.LogDebugf("[time] %s - args %v - execution took: %vns", sqlStr, args, execDuration.Nanoseconds())
+		if len(args) > 0 {
+			engine.logger.Infof("[sql] %s [args] %v - took: %v", sqlStr, args, execDuration)
+		} else {
+			engine.logger.Infof("[sql] %s - took: %v", sqlStr, execDuration)
+		}
 		return res, err
 		return res, err
 	} else {
 	} else {
 		return executionBlock()
 		return executionBlock()
 	}
 	}
 }
 }
 
 
-// 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 < overrideLevel { // TODO can remove if deprecated engine.ShowErr
-		engine.Logger.SetLevel(core.LOG_ERR) // try override logger's log level
-	}
-
-}
-
-func (engine *Engine) LogError(contents ...interface{}) {
-	if engine.ShowErr {
-		engine.overrideLogLevel(core.LOG_ERR)
-		engine.Logger.Err(contents...)
-	}
+// LogError logging error
+/*func (engine *Engine) LogError(contents ...interface{}) {
+	engine.logger.Err(contents...)
 }
 }
 
 
+// LogErrorf logging errorf
 func (engine *Engine) LogErrorf(format string, contents ...interface{}) {
 func (engine *Engine) LogErrorf(format string, contents ...interface{}) {
-	if engine.ShowErr {
-		engine.overrideLogLevel(core.LOG_ERR)
-		engine.Logger.Errf(format, contents...)
-	}
+	engine.logger.Errf(format, contents...)
 }
 }
 
 
-// logging info
+// LogInfo logging info
 func (engine *Engine) LogInfo(contents ...interface{}) {
 func (engine *Engine) LogInfo(contents ...interface{}) {
-	if engine.ShowInfo {
-		engine.overrideLogLevel(core.LOG_INFO)
-		engine.Logger.Info(contents...)
-	}
+	engine.logger.Info(contents...)
 }
 }
 
 
+// LogInfof logging infof
 func (engine *Engine) LogInfof(format string, contents ...interface{}) {
 func (engine *Engine) LogInfof(format string, contents ...interface{}) {
-	if engine.ShowErr {
-		engine.overrideLogLevel(core.LOG_INFO)
-		engine.Logger.Infof(format, contents...)
-	}
+	engine.logger.Infof(format, contents...)
 }
 }
 
 
-// logging debug
+// LogDebug logging debug
 func (engine *Engine) LogDebug(contents ...interface{}) {
 func (engine *Engine) LogDebug(contents ...interface{}) {
-	if engine.ShowDebug {
-		engine.overrideLogLevel(core.LOG_DEBUG)
-		engine.Logger.Debug(contents...)
-	}
+	engine.logger.Debug(contents...)
 }
 }
 
 
+// LogDebugf logging debugf
 func (engine *Engine) LogDebugf(format string, contents ...interface{}) {
 func (engine *Engine) LogDebugf(format string, contents ...interface{}) {
-	if engine.ShowDebug {
-		engine.overrideLogLevel(core.LOG_DEBUG)
-		engine.Logger.Debugf(format, contents...)
-	}
+	engine.logger.Debugf(format, contents...)
 }
 }
 
 
-// logging warn
+// LogWarn logging warn
 func (engine *Engine) LogWarn(contents ...interface{}) {
 func (engine *Engine) LogWarn(contents ...interface{}) {
-	if engine.ShowWarn {
-		engine.overrideLogLevel(core.LOG_WARNING)
-		engine.Logger.Warning(contents...)
-	}
+	engine.logger.Warning(contents...)
 }
 }
 
 
+// LogWarnf logging warnf
 func (engine *Engine) LogWarnf(format string, contents ...interface{}) {
 func (engine *Engine) LogWarnf(format string, contents ...interface{}) {
-	if engine.ShowWarn {
-		engine.overrideLogLevel(core.LOG_WARNING)
-		engine.Logger.Warningf(format, contents...)
-	}
-}
+	engine.logger.Warningf(format, contents...)
+}*/
 
 
 // Sql method let's you manualy write raw sql and operate
 // Sql method let's you manualy write raw sql and operate
 // For example:
 // For example:
@@ -312,7 +340,7 @@ func (engine *Engine) Sql(querystring string, args ...interface{}) *Session {
 	return session.Sql(querystring, args...)
 	return session.Sql(querystring, args...)
 }
 }
 
 
-// Default if your struct has "created" or "updated" filed tag, the fields
+// NoAutoTime Default if your struct has "created" or "updated" filed tag, the fields
 // will automatically be filled with current time when Insert or Update
 // will automatically be filled with current time when Insert or Update
 // invoked. Call NoAutoTime if you dont' want to fill automatically.
 // invoked. Call NoAutoTime if you dont' want to fill automatically.
 func (engine *Engine) NoAutoTime() *Session {
 func (engine *Engine) NoAutoTime() *Session {
@@ -321,7 +349,14 @@ func (engine *Engine) NoAutoTime() *Session {
 	return session.NoAutoTime()
 	return session.NoAutoTime()
 }
 }
 
 
-// Retrieve all tables, columns, indexes' informations from database.
+// NoAutoCondition disable auto generate Where condition from bean or not
+func (engine *Engine) NoAutoCondition(no ...bool) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.NoAutoCondition(no...)
+}
+
+// DBMetas Retrieve all tables, columns, indexes' informations from database.
 func (engine *Engine) DBMetas() ([]*core.Table, error) {
 func (engine *Engine) DBMetas() ([]*core.Table, error) {
 	tables, err := engine.dialect.GetTables()
 	tables, err := engine.dialect.GetTables()
 	if err != nil {
 	if err != nil {
@@ -357,9 +392,7 @@ func (engine *Engine) DBMetas() ([]*core.Table, error) {
 	return tables, nil
 	return tables, nil
 }
 }
 
 
-/*
-dump database all table structs and data to a file
-*/
+// DumpAllToFile dump database all table structs and data to a file
 func (engine *Engine) DumpAllToFile(fp string) error {
 func (engine *Engine) DumpAllToFile(fp string) error {
 	f, err := os.Create(fp)
 	f, err := os.Create(fp)
 	if err != nil {
 	if err != nil {
@@ -369,28 +402,73 @@ func (engine *Engine) DumpAllToFile(fp string) error {
 	return engine.DumpAll(f)
 	return engine.DumpAll(f)
 }
 }
 
 
-/*
-dump database all table structs and data to w
-*/
+// DumpAll dump database all table structs and data to w
 func (engine *Engine) DumpAll(w io.Writer) error {
 func (engine *Engine) DumpAll(w io.Writer) error {
+	return engine.dumpAll(w, engine.dialect.DBType())
+}
+
+// DumpTablesToFile dump specified tables to SQL file.
+func (engine *Engine) DumpTablesToFile(tables []*core.Table, fp string, tp ...core.DbType) error {
+	f, err := os.Create(fp)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return engine.DumpTables(tables, f, tp...)
+}
+
+// DumpTables dump specify tables to io.Writer
+func (engine *Engine) DumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error {
+	return engine.dumpTables(tables, w, tp...)
+}
+
+func (engine *Engine) tbName(tb *core.Table) string {
+	return tb.Name
+}
+
+// DumpAll dump database all table structs and data to w with specify db type
+func (engine *Engine) dumpAll(w io.Writer, tp ...core.DbType) error {
 	tables, err := engine.DBMetas()
 	tables, err := engine.DBMetas()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	for _, table := range tables {
-		_, err = io.WriteString(w, engine.dialect.CreateTableSql(table, "", table.StoreEngine, "")+"\n\n")
+	var dialect core.Dialect
+	if len(tp) == 0 {
+		dialect = engine.dialect
+	} else {
+		dialect = core.QueryDialect(tp[0])
+		if dialect == nil {
+			return errors.New("Unsupported database type.")
+		}
+		dialect.Init(nil, engine.dialect.URI(), "", "")
+	}
+
+	_, err = io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s*/\n\n",
+		Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05")))
+	if err != nil {
+		return err
+	}
+
+	for i, table := range tables {
+		if i > 0 {
+			_, err = io.WriteString(w, "\n")
+			if err != nil {
+				return err
+			}
+		}
+		_, err = io.WriteString(w, dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n")
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
 		for _, index := range table.Indexes {
 		for _, index := range table.Indexes {
-			_, err = io.WriteString(w, engine.dialect.CreateIndexSql(table.Name, index)+"\n\n")
+			_, err = io.WriteString(w, dialect.CreateIndexSql(engine.tbName(table), index)+";\n")
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
 		}
 		}
 
 
-		rows, err := engine.DB().Query("SELECT * FROM " + engine.Quote(table.Name))
+		rows, err := engine.DB().Query("SELECT * FROM " + engine.Quote(engine.tbName(table)))
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -409,7 +487,7 @@ func (engine *Engine) DumpAll(w io.Writer) error {
 				return err
 				return err
 			}
 			}
 
 
-			_, err = io.WriteString(w, "INSERT INTO "+engine.Quote(table.Name)+" ("+engine.Quote(strings.Join(cols, engine.Quote(", ")))+") VALUES (")
+			_, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(engine.tbName(table))+" ("+dialect.Quote(strings.Join(cols, dialect.Quote(", ")))+") VALUES (")
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
@@ -424,7 +502,7 @@ func (engine *Engine) DumpAll(w io.Writer) error {
 					temp += ", '" + strings.Replace(v, "'", "''", -1) + "'"
 					temp += ", '" + strings.Replace(v, "'", "''", -1) + "'"
 				} else if col.SQLType.IsBlob() {
 				} else if col.SQLType.IsBlob() {
 					if reflect.TypeOf(d).Kind() == reflect.Slice {
 					if reflect.TypeOf(d).Kind() == reflect.Slice {
-						temp += fmt.Sprintf(", %s", engine.dialect.FormatBytes(d.([]byte)))
+						temp += fmt.Sprintf(", %s", dialect.FormatBytes(d.([]byte)))
 					} else if reflect.TypeOf(d).Kind() == reflect.String {
 					} else if reflect.TypeOf(d).Kind() == reflect.String {
 						temp += fmt.Sprintf(", '%s'", d.(string))
 						temp += fmt.Sprintf(", '%s'", d.(string))
 					}
 					}
@@ -444,7 +522,115 @@ func (engine *Engine) DumpAll(w io.Writer) error {
 					}
 					}
 				}
 				}
 			}
 			}
-			_, err = io.WriteString(w, temp[2:]+");\n\n")
+			_, err = io.WriteString(w, temp[2:]+");\n")
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// DumpAll dump database all table structs and data to w with specify db type
+func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error {
+	var dialect core.Dialect
+	if len(tp) == 0 {
+		dialect = engine.dialect
+	} else {
+		dialect = core.QueryDialect(tp[0])
+		if dialect == nil {
+			return errors.New("Unsupported database type.")
+		}
+		dialect.Init(nil, engine.dialect.URI(), "", "")
+	}
+
+	_, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s, from %s to %s*/\n\n",
+		Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.DBType(), dialect.DBType()))
+	if err != nil {
+		return err
+	}
+
+	for i, table := range tables {
+		if i > 0 {
+			_, err = io.WriteString(w, "\n")
+			if err != nil {
+				return err
+			}
+		}
+		_, err = io.WriteString(w, dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n")
+		if err != nil {
+			return err
+		}
+		for _, index := range table.Indexes {
+			_, err = io.WriteString(w, dialect.CreateIndexSql(engine.tbName(table), index)+";\n")
+			if err != nil {
+				return err
+			}
+		}
+
+		rows, err := engine.DB().Query("SELECT * FROM " + engine.Quote(engine.tbName(table)))
+		if err != nil {
+			return err
+		}
+
+		cols, err := rows.Columns()
+		if err != nil {
+			return err
+		}
+		if len(cols) == 0 {
+			continue
+		}
+		for rows.Next() {
+			dest := make([]interface{}, len(cols))
+			err = rows.ScanSlice(&dest)
+			if err != nil {
+				return err
+			}
+
+			_, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(engine.tbName(table))+" ("+dialect.Quote(strings.Join(cols, dialect.Quote(", ")))+") VALUES (")
+			if err != nil {
+				return err
+			}
+
+			var temp string
+			for i, d := range dest {
+				col := table.GetColumn(cols[i])
+				if d == nil {
+					temp += ", NULL"
+				} else if col.SQLType.IsText() || col.SQLType.IsTime() {
+					var v = fmt.Sprintf("%s", d)
+					if strings.HasSuffix(v, " +0000 UTC") {
+						temp += fmt.Sprintf(", '%s'", v[0:len(v)-len(" +0000 UTC")])
+					} else {
+						temp += ", '" + strings.Replace(v, "'", "''", -1) + "'"
+					}
+				} else if col.SQLType.IsBlob() {
+					if reflect.TypeOf(d).Kind() == reflect.Slice {
+						temp += fmt.Sprintf(", %s", dialect.FormatBytes(d.([]byte)))
+					} else if reflect.TypeOf(d).Kind() == reflect.String {
+						temp += fmt.Sprintf(", '%s'", d.(string))
+					}
+				} else if col.SQLType.IsNumeric() {
+					switch reflect.TypeOf(d).Kind() {
+					case reflect.Slice:
+						temp += fmt.Sprintf(", %s", string(d.([]byte)))
+					default:
+						temp += fmt.Sprintf(", %v", d)
+					}
+				} else {
+					s := fmt.Sprintf("%v", d)
+					if strings.Contains(s, ":") || strings.Contains(s, "-") {
+						if strings.HasSuffix(s, " +0000 UTC") {
+							temp += fmt.Sprintf(", '%s'", s[0:len(s)-len(" +0000 UTC")])
+						} else {
+							temp += fmt.Sprintf(", '%s'", s)
+						}
+					} else {
+						temp += fmt.Sprintf(", %s", s)
+					}
+				}
+			}
+			_, err = io.WriteString(w, temp[2:]+");\n")
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
@@ -638,10 +824,10 @@ func (engine *Engine) OrderBy(order string) *Session {
 }
 }
 
 
 // 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 (engine *Engine) Join(join_operator string, tablename interface{}, condition string) *Session {
+func (engine *Engine) Join(join_operator string, tablename interface{}, condition string, args ...interface{}) *Session {
 	session := engine.NewSession()
 	session := engine.NewSession()
 	session.IsAutoClose = true
 	session.IsAutoClose = true
-	return session.Join(join_operator, tablename, condition)
+	return session.Join(join_operator, tablename, condition, args...)
 }
 }
 
 
 // Generate Group By statement
 // Generate Group By statement
@@ -665,10 +851,12 @@ func (engine *Engine) autoMapType(v reflect.Value) *core.Table {
 	if !ok {
 	if !ok {
 		table = engine.mapType(v)
 		table = engine.mapType(v)
 		engine.Tables[t] = table
 		engine.Tables[t] = table
-		if v.CanAddr() {
-			engine.GobRegister(v.Addr().Interface())
-		} else {
-			engine.GobRegister(v.Interface())
+		if engine.Cacher != nil {
+			if v.CanAddr() {
+				engine.GobRegister(v.Addr().Interface())
+			} else {
+				engine.GobRegister(v.Interface())
+			}
 		}
 		}
 	}
 	}
 	engine.mutex.Unlock()
 	engine.mutex.Unlock()
@@ -707,33 +895,31 @@ func (engine *Engine) newTable() *core.Table {
 	return table
 	return table
 }
 }
 
 
+type TableName interface {
+	TableName() string
+}
+
 func (engine *Engine) mapType(v reflect.Value) *core.Table {
 func (engine *Engine) mapType(v reflect.Value) *core.Table {
 	t := v.Type()
 	t := v.Type()
 	table := engine.newTable()
 	table := engine.newTable()
-	method := v.MethodByName("TableName")
-	if !method.IsValid() {
+	if tb, ok := v.Interface().(TableName); ok {
+		table.Name = tb.TableName()
+	} else {
 		if v.CanAddr() {
 		if v.CanAddr() {
-			method = v.Addr().MethodByName("TableName")
+			if tb, ok = v.Addr().Interface().(TableName); ok {
+				table.Name = tb.TableName()
+			}
 		}
 		}
-	}
-	if method.IsValid() {
-		params := []reflect.Value{}
-		results := method.Call(params)
-		if len(results) == 1 {
-			table.Name = results[0].Interface().(string)
+		if table.Name == "" {
+			table.Name = engine.TableMapper.Obj2Table(t.Name())
 		}
 		}
 	}
 	}
 
 
-	if table.Name == "" {
-		table.Name = engine.TableMapper.Obj2Table(t.Name())
-	}
 	table.Type = t
 	table.Type = t
 
 
 	var idFieldColName string
 	var idFieldColName string
 	var err error
 	var err error
-
-	hasCacheTag := false
-	hasNoCacheTag := false
+	var hasCacheTag, hasNoCacheTag bool
 
 
 	for i := 0; i < t.NumField(); i++ {
 	for i := 0; i < t.NumField(); i++ {
 		tag := t.Field(i).Tag
 		tag := t.Field(i).Tag
@@ -746,30 +932,25 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
 		if ormTagStr != "" {
 		if ormTagStr != "" {
 			col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
 			col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
 				IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]bool)}
 				IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]bool)}
-			tags := strings.Split(ormTagStr, " ")
+			tags := splitTag(ormTagStr)
 
 
 			if len(tags) > 0 {
 			if len(tags) > 0 {
 				if tags[0] == "-" {
 				if tags[0] == "-" {
 					continue
 					continue
 				}
 				}
 				if strings.ToUpper(tags[0]) == "EXTENDS" {
 				if strings.ToUpper(tags[0]) == "EXTENDS" {
-					if fieldValue.Kind() == reflect.Struct {
-						parentTable := engine.mapType(fieldValue)
-						for _, col := range parentTable.Columns() {
-							col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName)
-							table.AddColumn(col)
-						}
-
-						continue
-					} else if fieldValue.Kind() == reflect.Ptr {
+					switch fieldValue.Kind() {
+					case reflect.Ptr:
 						f := fieldValue.Type().Elem()
 						f := fieldValue.Type().Elem()
 						if f.Kind() == reflect.Struct {
 						if f.Kind() == reflect.Struct {
+							fieldPtr := fieldValue
 							fieldValue = fieldValue.Elem()
 							fieldValue = fieldValue.Elem()
-							if !fieldValue.IsValid() || fieldValue.IsNil() {
+							if !fieldValue.IsValid() || fieldPtr.IsNil() {
 								fieldValue = reflect.New(f).Elem()
 								fieldValue = reflect.New(f).Elem()
 							}
 							}
 						}
 						}
-
+						fallthrough
+					case reflect.Struct:
 						parentTable := engine.mapType(fieldValue)
 						parentTable := engine.mapType(fieldValue)
 						for _, col := range parentTable.Columns() {
 						for _, col := range parentTable.Columns() {
 							col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName)
 							col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName)
@@ -777,8 +958,9 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
 						}
 						}
 
 
 						continue
 						continue
+					default:
+						//TODO: warning
 					}
 					}
-					//TODO: warning
 				}
 				}
 
 
 				indexNames := make(map[string]int)
 				indexNames := make(map[string]int)
@@ -820,6 +1002,16 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
 					case k == "VERSION":
 					case k == "VERSION":
 						col.IsVersion = true
 						col.IsVersion = true
 						col.Default = "1"
 						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.logger.Error(err)
+						}
 					case k == "UPDATED":
 					case k == "UPDATED":
 						col.IsUpdated = true
 						col.IsUpdated = true
 					case k == "DELETED":
 					case k == "DELETED":
@@ -879,16 +1071,16 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
 								if len(fs2) == 2 {
 								if len(fs2) == 2 {
 									col.Length, err = strconv.Atoi(fs2[0])
 									col.Length, err = strconv.Atoi(fs2[0])
 									if err != nil {
 									if err != nil {
-										engine.LogError(err)
+										engine.logger.Error(err)
 									}
 									}
 									col.Length2, err = strconv.Atoi(fs2[1])
 									col.Length2, err = strconv.Atoi(fs2[1])
 									if err != nil {
 									if err != nil {
-										engine.LogError(err)
+										engine.logger.Error(err)
 									}
 									}
 								} else if len(fs2) == 1 {
 								} else if len(fs2) == 1 {
 									col.Length, err = strconv.Atoi(fs2[0])
 									col.Length, err = strconv.Atoi(fs2[0])
 									if err != nil {
 									if err != nil {
-										engine.LogError(err)
+										engine.logger.Error(err)
 									}
 									}
 								}
 								}
 							}
 							}
@@ -965,15 +1157,15 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
 
 
 	if hasCacheTag {
 	if hasCacheTag {
 		if engine.Cacher != nil { // !nash! use engine's cacher if provided
 		if engine.Cacher != nil { // !nash! use engine's cacher if provided
-			engine.Logger.Info("enable cache on table:", table.Name)
+			engine.logger.Info("enable cache on table:", table.Name)
 			table.Cacher = engine.Cacher
 			table.Cacher = engine.Cacher
 		} else {
 		} else {
-			engine.Logger.Info("enable LRU cache on table:", table.Name)
+			engine.logger.Info("enable LRU cache on table:", table.Name)
 			table.Cacher = NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) // !nashtsai! HACK use LRU cacher for now
 			table.Cacher = NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) // !nashtsai! HACK use LRU cacher for now
 		}
 		}
 	}
 	}
 	if hasNoCacheTag {
 	if hasNoCacheTag {
-		engine.Logger.Info("no cache on table:", table.Name)
+		engine.logger.Info("no cache on table:", table.Name)
 		table.Cacher = nil
 		table.Cacher = nil
 	}
 	}
 
 
@@ -1157,7 +1349,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 						session := engine.NewSession()
 						session := engine.NewSession()
 						session.Statement.RefTable = table
 						session.Statement.RefTable = table
 						defer session.Close()
 						defer session.Close()
-						err = session.addUnique(table.Name, name)
+						err = session.addUnique(engine.tbName(table), name)
 						if err != nil {
 						if err != nil {
 							return err
 							return err
 						}
 						}
@@ -1171,7 +1363,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
 						session := engine.NewSession()
 						session := engine.NewSession()
 						session.Statement.RefTable = table
 						session.Statement.RefTable = table
 						defer session.Close()
 						defer session.Close()
-						err = session.addIndex(table.Name, name)
+						err = session.addIndex(engine.tbName(table), name)
 						if err != nil {
 						if err != nil {
 							return err
 							return err
 						}
 						}
@@ -1407,16 +1599,18 @@ func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
 	scanner.Split(semiColSpliter)
 	scanner.Split(semiColSpliter)
 
 
 	for scanner.Scan() {
 	for scanner.Scan() {
-		query := scanner.Text()
-		query = strings.Trim(query, " \t")
+		query := strings.Trim(scanner.Text(), " \t\n\r")
 		if len(query) > 0 {
 		if len(query) > 0 {
+			engine.logSQL(query)
 			result, err := engine.DB().Exec(query)
 			result, err := engine.DB().Exec(query)
 			results = append(results, result)
 			results = append(results, result)
 			if err != nil {
 			if err != nil {
+				return nil, err
 				lastError = err
 				lastError = err
 			}
 			}
 		}
 		}
 	}
 	}
+
 	return results, lastError
 	return results, lastError
 }
 }
 
 
@@ -1425,7 +1619,6 @@ var (
 )
 )
 
 
 func (engine *Engine) TZTime(t time.Time) time.Time {
 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()
 	if NULL_TIME != t { // if time is not initialized it's not suitable for Time.In()
 		return t.In(engine.TZLocation)
 		return t.In(engine.TZLocation)
 	}
 	}
@@ -1443,35 +1636,51 @@ func (engine *Engine) NowTime2(sqlTypeName string) (interface{}, time.Time) {
 }
 }
 
 
 func (engine *Engine) FormatTime(sqlTypeName string, t time.Time) (v interface{}) {
 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 {
 	if engine.dialect.DBType() == core.ORACLE {
 		return t
 		return t
 	}
 	}
+	if tz != nil {
+		t = engine.TZTime(t)
+	}
 	switch sqlTypeName {
 	switch sqlTypeName {
 	case core.Time:
 	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]
 		v = s[11:19]
 	case core.Date:
 	case core.Date:
-		v = engine.TZTime(t).Format("2006-01-02")
+		v = t.Format("2006-01-02")
 	case core.DateTime, core.TimeStamp:
 	case core.DateTime, core.TimeStamp:
 		if engine.dialect.DBType() == "ql" {
 		if engine.dialect.DBType() == "ql" {
-			v = engine.TZTime(t)
+			v = t
 		} else if engine.dialect.DBType() == "sqlite3" {
 		} 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 {
 		} else {
-			v = engine.TZTime(t).Format("2006-01-02 15:04:05")
+			v = t.Format("2006-01-02 15:04:05")
 		}
 		}
 	case core.TimeStampz:
 	case core.TimeStampz:
 		if engine.dialect.DBType() == core.MSSQL {
 		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" {
 		} else if engine.DriverName() == "mssql" {
-			v = engine.TZTime(t)
+			v = t
 		} else {
 		} else {
-			v = engine.TZTime(t).Format(time.RFC3339Nano)
+			v = t.Format(time.RFC3339Nano)
 		}
 		}
 	case core.BigInt, core.Int:
 	case core.BigInt, core.Int:
-		v = engine.TZTime(t).Unix()
+		v = t.Unix()
 	default:
 	default:
-		v = engine.TZTime(t)
+		v = t
 	}
 	}
 	return
 	return
 }
 }

+ 1 - 1
engineplus.go

@@ -21,7 +21,7 @@ func (engine *Engine) SqlTemplateClient(sqlTagName string, args ...interface{})
 	}
 	}
 	sql, err := engine.SqlTemplate.Template[sqlTagName].Execute(map1)
 	sql, err := engine.SqlTemplate.Template[sqlTagName].Execute(map1)
 	if err != nil {
 	if err != nil {
-		engine.Logger.Err(err)
+		engine.logger.Error(err)
 	}
 	}
 
 
 	return session.Sql(sql, &map1)
 	return session.Sql(sql, &map1)

+ 54 - 6
helpers.go

@@ -15,6 +15,30 @@ import (
 	"github.com/xormplus/core"
 	"github.com/xormplus/core"
 )
 )
 
 
+func splitTag(tag string) (tags []string) {
+	tag = strings.TrimSpace(tag)
+	var hasQuote = false
+	var lastIdx = 0
+	for i, t := range tag {
+		if t == '\'' {
+			hasQuote = !hasQuote
+		} else if t == ' ' {
+			if lastIdx < i && !hasQuote {
+				tags = append(tags, strings.TrimSpace(tag[lastIdx:i]))
+				lastIdx = i + 1
+			}
+		}
+	}
+	if lastIdx < len(tag) {
+		tags = append(tags, strings.TrimSpace(tag[lastIdx:len(tag)]))
+	}
+	return
+}
+
+type zeroable interface {
+	IsZero() bool
+}
+
 func isZero(k interface{}) bool {
 func isZero(k interface{}) bool {
 	switch k.(type) {
 	switch k.(type) {
 	case int:
 	case int:
@@ -45,12 +69,33 @@ func isZero(k interface{}) bool {
 		return k.(bool) == false
 		return k.(bool) == false
 	case string:
 	case string:
 		return k.(string) == ""
 		return k.(string) == ""
-	case time.Time:
-		return k.(time.Time).IsZero()
+	case zeroable:
+		return k.(zeroable).IsZero()
 	}
 	}
 	return false
 	return false
 }
 }
 
 
+func int64ToInt(id int64, k reflect.Kind) interface{} {
+	var v interface{} = id
+	switch k {
+	case reflect.Int16:
+		v = int16(id)
+	case reflect.Int32:
+		v = int32(id)
+	case reflect.Int:
+		v = int(id)
+	case reflect.Uint16:
+		v = uint16(id)
+	case reflect.Uint32:
+		v = uint32(id)
+	case reflect.Uint64:
+		v = uint64(id)
+	case reflect.Uint:
+		v = uint(id)
+	}
+	return v
+}
+
 func isPKZero(pk core.PK) bool {
 func isPKZero(pk core.PK) bool {
 	for _, k := range pk {
 	for _, k := range pk {
 		if isZero(k) {
 		if isZero(k) {
@@ -60,6 +105,10 @@ func isPKZero(pk core.PK) bool {
 	return false
 	return false
 }
 }
 
 
+func equalNoCase(s1, s2 string) bool {
+	return strings.ToLower(s1) == strings.ToLower(s2)
+}
+
 func indexNoCase(s, sep string) int {
 func indexNoCase(s, sep string) int {
 	return strings.Index(strings.ToLower(s), strings.ToLower(sep))
 	return strings.Index(strings.ToLower(s), strings.ToLower(sep))
 }
 }
@@ -311,8 +360,8 @@ func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
 }
 }
 
 
 func genCols(table *core.Table, session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
 func genCols(table *core.Table, session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
-	colNames := make([]string, 0)
-	args := make([]interface{}, 0)
+	colNames := make([]string, 0, len(table.ColumnsSeq()))
+	args := make([]interface{}, 0, len(table.ColumnsSeq()))
 
 
 	for _, col := range table.Columns() {
 	for _, col := range table.Columns() {
 		lColName := strings.ToLower(col.Name)
 		lColName := strings.ToLower(col.Name)
@@ -327,8 +376,7 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
 
 
 		fieldValuePtr, err := col.ValueOf(bean)
 		fieldValuePtr, err := col.ValueOf(bean)
 		if err != nil {
 		if err != nil {
-			session.Engine.LogError(err)
-			continue
+			return nil, nil, err
 		}
 		}
 		fieldValue := *fieldValuePtr
 		fieldValue := *fieldValuePtr
 
 

+ 2 - 4
helpersplus.go

@@ -31,9 +31,7 @@ func reflect2objectWithDateFormat(rawValue *reflect.Value, dateFormat string) (v
 	//时间类型
 	//时间类型
 	case reflect.Struct:
 	case reflect.Struct:
 		if aa.ConvertibleTo(core.TimeType) {
 		if aa.ConvertibleTo(core.TimeType) {
-			//			loc, _ := time.LoadLocation("Local")                            //重要:获取时区
-			//			value, _ = time.ParseInLocation(dateFormat, rawValue.Interface().(time.Time).Format(dateFormat), loc)
-			value = rawValue.Interface().(time.Time).Format(dateFormat)
+			value = vv.Convert(core.TimeType).Interface().(time.Time).Format(dateFormat)
 		} else {
 		} else {
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 		}
 		}
@@ -180,7 +178,7 @@ func reflect2object(rawValue *reflect.Value) (value interface{}, err error) {
 	//时间类型
 	//时间类型
 	case reflect.Struct:
 	case reflect.Struct:
 		if aa.ConvertibleTo(core.TimeType) {
 		if aa.ConvertibleTo(core.TimeType) {
-			value = rawValue.Interface().(time.Time)
+			value = vv.Convert(core.TimeType).Interface().(time.Time)
 		} else {
 		} else {
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 		}
 		}

+ 82 - 30
logger.go

@@ -18,22 +18,50 @@ const (
 	DEFAULT_LOG_LEVEL  = core.LOG_DEBUG
 	DEFAULT_LOG_LEVEL  = core.LOG_DEBUG
 )
 )
 
 
+var _ core.ILogger = DiscardLogger{}
+
+type DiscardLogger struct{}
+
+func (DiscardLogger) Debug(v ...interface{})                 {}
+func (DiscardLogger) Debugf(format string, v ...interface{}) {}
+func (DiscardLogger) Error(v ...interface{})                 {}
+func (DiscardLogger) Errorf(format string, v ...interface{}) {}
+func (DiscardLogger) Info(v ...interface{})                  {}
+func (DiscardLogger) Infof(format string, v ...interface{})  {}
+func (DiscardLogger) Warn(v ...interface{})                  {}
+func (DiscardLogger) Warnf(format string, v ...interface{})  {}
+func (DiscardLogger) Level() core.LogLevel {
+	return core.LOG_UNKNOWN
+}
+func (DiscardLogger) SetLevel(l core.LogLevel) {}
+func (DiscardLogger) ShowSQL(show ...bool)     {}
+func (DiscardLogger) IsShowSQL() bool {
+	return false
+}
+
+// SimpleLogger is the default implment of core.ILogger
 type SimpleLogger struct {
 type SimpleLogger struct {
-	DEBUG *log.Logger
-	ERR   *log.Logger
-	INFO  *log.Logger
-	WARN  *log.Logger
-	level core.LogLevel
+	DEBUG   *log.Logger
+	ERR     *log.Logger
+	INFO    *log.Logger
+	WARN    *log.Logger
+	level   core.LogLevel
+	showSQL bool
 }
 }
 
 
+var _ core.ILogger = &SimpleLogger{}
+
+// NewSimpleLogger use a special io.Writer as logger output
 func NewSimpleLogger(out io.Writer) *SimpleLogger {
 func NewSimpleLogger(out io.Writer) *SimpleLogger {
 	return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
 	return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
 }
 }
 
 
+// NewSimpleLogger2 let you customrize your logger prefix and flag
 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)
 	return NewSimpleLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL)
 }
 }
 
 
+// NewSimpleLogger3 let you customrize your logger prefix and flag and logLevel
 func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *SimpleLogger {
 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), flag),
 		DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), flag),
@@ -44,67 +72,91 @@ func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *
 	}
 	}
 }
 }
 
 
-func (s *SimpleLogger) Err(v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level <= core.LOG_ERR {
-		s.ERR.Println(v...)
+// Error implement core.ILogger
+func (s *SimpleLogger) Error(v ...interface{}) {
+	if s.level <= core.LOG_ERR {
+		s.ERR.Output(2, fmt.Sprint(v...))
 	}
 	}
 	return
 	return
 }
 }
 
 
-func (s *SimpleLogger) Errf(format string, v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level <= core.LOG_ERR {
-		s.ERR.Printf(format, v...)
+// Errorf implement core.ILogger
+func (s *SimpleLogger) Errorf(format string, v ...interface{}) {
+	if s.level <= core.LOG_ERR {
+		s.ERR.Output(2, fmt.Sprintf(format, v...))
 	}
 	}
 	return
 	return
 }
 }
 
 
-func (s *SimpleLogger) Debug(v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level <= core.LOG_DEBUG {
-		s.DEBUG.Println(v...)
+// Debug implement core.ILogger
+func (s *SimpleLogger) Debug(v ...interface{}) {
+	if s.level <= core.LOG_DEBUG {
+		s.DEBUG.Output(2, fmt.Sprint(v...))
 	}
 	}
 	return
 	return
 }
 }
 
 
-func (s *SimpleLogger) Debugf(format string, v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level >= core.LOG_DEBUG {
-		s.DEBUG.Printf(format, v...)
+// Debugf implement core.ILogger
+func (s *SimpleLogger) Debugf(format string, v ...interface{}) {
+	if s.level <= core.LOG_DEBUG {
+		s.DEBUG.Output(2, fmt.Sprintf(format, v...))
 	}
 	}
 	return
 	return
 }
 }
 
 
-func (s *SimpleLogger) Info(v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level >= core.LOG_INFO {
-		s.INFO.Println(v...)
+// Info implement core.ILogger
+func (s *SimpleLogger) Info(v ...interface{}) {
+	if s.level <= core.LOG_INFO {
+		s.INFO.Output(2, fmt.Sprint(v...))
 	}
 	}
 	return
 	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...)
+// Infof implement core.ILogger
+func (s *SimpleLogger) Infof(format string, v ...interface{}) {
+	if s.level <= core.LOG_INFO {
+		s.INFO.Output(2, fmt.Sprintf(format, v...))
 	}
 	}
 	return
 	return
 }
 }
 
 
-func (s *SimpleLogger) Warning(v ...interface{}) (err error) {
-	if s.level > core.LOG_OFF && s.level >= core.LOG_WARNING {
-		s.WARN.Println(v...)
+// Warn implement core.ILogger
+func (s *SimpleLogger) Warn(v ...interface{}) {
+	if s.level <= core.LOG_WARNING {
+		s.WARN.Output(2, fmt.Sprint(v...))
 	}
 	}
 	return
 	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...)
+// Warnf implement core.ILogger
+func (s *SimpleLogger) Warnf(format string, v ...interface{}) {
+	if s.level <= core.LOG_WARNING {
+		s.WARN.Output(2, fmt.Sprintf(format, v...))
 	}
 	}
 	return
 	return
 }
 }
 
 
+// Level implement core.ILogger
 func (s *SimpleLogger) Level() core.LogLevel {
 func (s *SimpleLogger) Level() core.LogLevel {
 	return s.level
 	return s.level
 }
 }
 
 
-func (s *SimpleLogger) SetLevel(l core.LogLevel) (err error) {
+// SetLevel implement core.ILogger
+func (s *SimpleLogger) SetLevel(l core.LogLevel) {
 	s.level = l
 	s.level = l
 	return
 	return
 }
 }
+
+// ShowSQL implement core.ILogger
+func (s *SimpleLogger) ShowSQL(show ...bool) {
+	if len(show) == 0 {
+		s.showSQL = true
+		return
+	}
+	s.showSQL = show[0]
+}
+
+// IsShowSQL implement core.ILogger
+func (s *SimpleLogger) IsShowSQL() bool {
+	return s.showSQL
+}

+ 3 - 0
mssql_dialect.go

@@ -337,6 +337,7 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
 	s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale
 	s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale
 from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
 from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
 where a.object_id=object_id('` + tableName + `')`
 where a.object_id=object_id('` + tableName + `')`
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
 	if err != nil {
@@ -394,6 +395,7 @@ where a.object_id=object_id('` + tableName + `')`
 func (db *mssql) GetTables() ([]*core.Table, error) {
 func (db *mssql) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	args := []interface{}{}
 	s := `select name from sysobjects where xtype ='U'`
 	s := `select name from sysobjects where xtype ='U'`
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
 	if err != nil {
@@ -428,6 +430,7 @@ INNER   JOIN SYS.COLUMNS C  ON IXS.OBJECT_ID=C.OBJECT_ID
 AND IXCS.COLUMN_ID=C.COLUMN_ID
 AND IXCS.COLUMN_ID=C.COLUMN_ID
 WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
 WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
 `
 `
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
 	if err != nil {
 	if err != nil {

+ 4 - 11
mysql_dialect.go

@@ -303,12 +303,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
 	args := []interface{}{db.DbName, tableName}
 	args := []interface{}{db.DbName, tableName}
 	s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
 	s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
 		" `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
 		" `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
-
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
@@ -414,12 +411,10 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
 func (db *mysql) GetTables() ([]*core.Table, error) {
 func (db *mysql) GetTables() ([]*core.Table, error) {
 	args := []interface{}{db.DbName}
 	args := []interface{}{db.DbName}
 	s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " +
 	s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " +
-		"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB')"
+		"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -445,11 +440,9 @@ func (db *mysql) GetTables() ([]*core.Table, error) {
 func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
 func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{db.DbName, tableName}
 	args := []interface{}{db.DbName, tableName}
 	s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
 	s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 8 - 18
oracle_dialect.go

@@ -637,9 +637,7 @@ func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
 
 
 func (db *oracle) MustDropTable(tableName string) error {
 func (db *oracle) MustDropTable(tableName string) error {
 	sql, args := db.TableCheckSql(tableName)
 	sql, args := db.TableCheckSql(tableName)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", sql, args)
-	}
+	db.LogSQL(sql, args)
 
 
 	rows, err := db.DB().Query(sql, args...)
 	rows, err := db.DB().Query(sql, args...)
 	if err != nil {
 	if err != nil {
@@ -652,9 +650,8 @@ func (db *oracle) MustDropTable(tableName string) error {
 	}
 	}
 
 
 	sql = "Drop Table \"" + tableName + "\""
 	sql = "Drop Table \"" + tableName + "\""
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", sql)
-	}
+	db.LogSQL(sql, args)
+
 	_, err = db.DB().Exec(sql)
 	_, err = db.DB().Exec(sql)
 	return err
 	return err
 }
 }
@@ -669,10 +666,9 @@ func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName, colName}
 	args := []interface{}{tableName, colName}
 	query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
 	query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
 		" AND column_name = :2"
 		" AND column_name = :2"
+	db.LogSQL(query, args)
+
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
@@ -688,11 +684,9 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
 	s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
 		"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
 		"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
@@ -787,11 +781,9 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 func (db *oracle) GetTables() ([]*core.Table, error) {
 func (db *oracle) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	args := []interface{}{}
 	s := "SELECT table_name FROM user_tables"
 	s := "SELECT table_name FROM user_tables"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -814,11 +806,9 @@ func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
 	s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
 		"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
 		"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 9 - 16
postgres_dialect.go

@@ -836,6 +836,7 @@ func (db *postgres) IsReserved(name string) bool {
 }
 }
 
 
 func (db *postgres) Quote(name string) string {
 func (db *postgres) Quote(name string) string {
+	name = strings.Replace(name, ".", `"."`, -1)
 	return "\"" + name + "\""
 	return "\"" + name + "\""
 }
 }
 
 
@@ -900,10 +901,9 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName, colName}
 	args := []interface{}{tableName, colName}
 	query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
 	query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
 		" AND column_name = $2"
 		" AND column_name = $2"
+	db.LogSQL(query, args)
+
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
@@ -913,8 +913,7 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
 }
 }
 
 
 func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
-	pgSchema := "public"
-	args := []interface{}{tableName,pgSchema}
+	args := []interface{}{tableName, db.URI().Schema}
 	s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
 	s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
     CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
     CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
     CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
     CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
@@ -926,11 +925,9 @@ FROM pg_attribute f
     LEFT JOIN pg_class AS g ON p.confrelid = g.oid
     LEFT JOIN pg_class AS g ON p.confrelid = g.oid
     LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
     LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
 WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;`
 WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;`
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
@@ -1016,12 +1013,10 @@ WHERE c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.att
 
 
 func (db *postgres) GetTables() ([]*core.Table, error) {
 func (db *postgres) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	args := []interface{}{}
-	s := "SELECT tablename FROM pg_tables where schemaname = 'public'"
+	s := fmt.Sprintf("SELECT tablename FROM pg_tables where schemaname = '%s'", db.Uri.Schema)
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -1043,12 +1038,10 @@ func (db *postgres) GetTables() ([]*core.Table, error) {
 
 
 func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
 func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
-	s := "SELECT indexname, indexdef FROM pg_indexes WHERE schemaname='public' AND tablename=$1"
+	s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE schemaname='%s' AND tablename=$1", db.URI().Schema)
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 6 - 2
pq_driver.go

@@ -41,7 +41,7 @@ func parseURL(connstr string) (string, error) {
 		return "", err
 		return "", err
 	}
 	}
 
 
-	if u.Scheme != "postgres" {
+	if u.Scheme != "postgresql" && u.Scheme != "postgres" {
 		return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
 		return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
 	}
 	}
 
 
@@ -103,7 +103,7 @@ func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 	db := &core.Uri{DbType: core.POSTGRES}
 	db := &core.Uri{DbType: core.POSTGRES}
 	o := make(values)
 	o := make(values)
 	var err error
 	var err error
-	if strings.HasPrefix(dataSourceName, "postgres://") {
+	if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
 		dataSourceName, err = parseURL(dataSourceName)
 		dataSourceName, err = parseURL(dataSourceName)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
@@ -115,5 +115,9 @@ func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 	if db.DbName == "" {
 	if db.DbName == "" {
 		return nil, errors.New("dbname is empty")
 		return nil, errors.New("dbname is empty")
 	}
 	}
+	db.Schema = o.Get("schema")
+	if len(db.Schema) == 0 {
+		db.Schema = "public"
+	}
 	return db, nil
 	return db, nil
 }
 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 231 - 169
session.go


+ 112 - 44
sessionplus.go

@@ -8,10 +8,11 @@ import (
 	"database/sql"
 	"database/sql"
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
-	//	"fmt"
+	"fmt"
 	"reflect"
 	"reflect"
 	"regexp"
 	"regexp"
 	"strings"
 	"strings"
+	"strconv"
 	"time"
 	"time"
 
 
 	"github.com/Chronokeeper/anyxml"
 	"github.com/Chronokeeper/anyxml"
@@ -398,12 +399,13 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 	for ii, key := range fields {
 	for ii, key := range fields {
 		var idx int
 		var idx int
 		var ok bool
 		var ok bool
-		if idx, ok = tempMap[strings.ToLower(key)]; !ok {
+		var lKey = strings.ToLower(key)
+		if idx, ok = tempMap[lKey]; !ok {
 			idx = 0
 			idx = 0
 		} else {
 		} else {
 			idx = idx + 1
 			idx = idx + 1
 		}
 		}
-		tempMap[strings.ToLower(key)] = idx
+		tempMap[lKey] = 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]))
@@ -418,7 +420,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 					if data, err := value2Bytes(&rawValue); err == nil {
 					if data, err := value2Bytes(&rawValue); err == nil {
 						structConvert.FromDB(data)
 						structConvert.FromDB(data)
 					} else {
 					} else {
-						session.Engine.LogError(err)
+						session.Engine.logger.Error(err)
 					}
 					}
 					continue
 					continue
 				}
 				}
@@ -431,7 +433,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 					}
 					}
 					fieldValue.Interface().(core.Conversion).FromDB(data)
 					fieldValue.Interface().(core.Conversion).FromDB(data)
 				} else {
 				} else {
-					session.Engine.LogError(err)
+					session.Engine.logger.Error(err)
 				}
 				}
 				continue
 				continue
 			}
 			}
@@ -441,24 +443,61 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 
 
 			fieldType := fieldValue.Type()
 			fieldType := fieldValue.Type()
 			hasAssigned := false
 			hasAssigned := false
+			col := table.GetColumnIdx(key, idx)
 
 
-			switch fieldType.Kind() {
-			case reflect.Complex64, reflect.Complex128:
+			if col.SQLType.IsJson() {
+				var bs []byte
 				if rawValueType.Kind() == reflect.String {
 				if rawValueType.Kind() == reflect.String {
-					hasAssigned = true
+					bs = []byte(vv.String())
+				} else if rawValueType.ConvertibleTo(reflect.SliceOf(reflect.TypeOf(uint8(1)))) {
+					bs = vv.Bytes()
+				} else {
+					return errors.New("unsupported database data type")
+				}
+
+				hasAssigned = true
+
+				if fieldValue.CanAddr() {
+					err := json.Unmarshal(bs, fieldValue.Addr().Interface())
+					if err != nil {
+						session.Engine.logger.Error(err)
+						return err
+					}
+				} else {
 					x := reflect.New(fieldType)
 					x := reflect.New(fieldType)
-					err := json.Unmarshal([]byte(vv.String()), x.Interface())
+					err := json.Unmarshal(bs, x.Interface())
 					if err != nil {
 					if err != nil {
-						session.Engine.LogError(err)
+						session.Engine.logger.Error(err)
 						return err
 						return err
 					}
 					}
 					fieldValue.Set(x.Elem())
 					fieldValue.Set(x.Elem())
+				}
+
+				continue
+			}
+
+			switch fieldType.Kind() {
+			case reflect.Complex64, reflect.Complex128:
+				// TODO: reimplement this
+				var bs []byte
+				if rawValueType.Kind() == reflect.String {
+					bs = []byte(vv.String())
 				} else if rawValueType.Kind() == reflect.Slice {
 				} else if rawValueType.Kind() == reflect.Slice {
-					hasAssigned = true
+					bs = vv.Bytes()
+				}
+
+				hasAssigned = true
+				if fieldValue.CanAddr() {
+					err := json.Unmarshal(bs, fieldValue.Addr().Interface())
+					if err != nil {
+						session.Engine.logger.Error(err)
+						return err
+					}
+				} else {
 					x := reflect.New(fieldType)
 					x := reflect.New(fieldType)
-					err := json.Unmarshal(vv.Bytes(), x.Interface())
+					err := json.Unmarshal(bs, x.Interface())
 					if err != nil {
 					if err != nil {
-						session.Engine.LogError(err)
+						session.Engine.logger.Error(err)
 						return err
 						return err
 					}
 					}
 					fieldValue.Set(x.Elem())
 					fieldValue.Set(x.Elem())
@@ -506,7 +545,6 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 					fieldValue.SetUint(uint64(vv.Int()))
 					fieldValue.SetUint(uint64(vv.Int()))
 				}
 				}
 			case reflect.Struct:
 			case reflect.Struct:
-				col := table.GetColumn(key)
 				if fieldType.ConvertibleTo(core.TimeType) {
 				if fieldType.ConvertibleTo(core.TimeType) {
 					if rawValueType == core.TimeType {
 					if rawValueType == core.TimeType {
 						hasAssigned = true
 						hasAssigned = true
@@ -514,34 +552,62 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 						t := vv.Convert(core.TimeType).Interface().(time.Time)
 						t := vv.Convert(core.TimeType).Interface().(time.Time)
 						z, _ := t.Zone()
 						z, _ := t.Zone()
 						if len(z) == 0 || t.Year() == 0 { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
 						if len(z) == 0 || t.Year() == 0 { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
-							session.Engine.LogDebugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
+							session.Engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
 							t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
 							t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
 								t.Minute(), t.Second(), t.Nanosecond(), time.Local)
 								t.Minute(), t.Second(), t.Nanosecond(), time.Local)
 						}
 						}
 						// !nashtsai! convert to engine location
 						// !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)
+						}
 						// dateFormat to string
 						// dateFormat to string
 						loc, _ := time.LoadLocation("Local") //重要:获取时区  rawValue.Interface().(time.Time).Format(dateFormat)
 						loc, _ := time.LoadLocation("Local") //重要:获取时区  rawValue.Interface().(time.Time).Format(dateFormat)
 						t, _ = time.ParseInLocation(dateFormat, t.Format(dateFormat), loc)
 						t, _ = time.ParseInLocation(dateFormat, t.Format(dateFormat), loc)
-						//						fieldValue.Set(reflect.ValueOf(t).Convert(core.StringType))
-						fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 
 
-						// t = fieldValue.Interface().(time.Time)
-						// z, _ = t.Zone()
-						// session.Engine.LogDebug("fieldValue key[%v]: %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
+						fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 					} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
 					} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
 						rawValueType == core.Int32Type {
 						rawValueType == core.Int32Type {
 						hasAssigned = true
 						hasAssigned = true
-						t := time.Unix(vv.Int(), 0).In(session.Engine.TZLocation)
-						vv = reflect.ValueOf(t)
-						fieldValue.Set(vv)
+						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 {
+						if d, ok := vv.Interface().([]uint8); ok {
+							hasAssigned = true
+							t, err := session.byte2Time(col, d)
+							if err != nil {
+								session.Engine.logger.Error("byte2Time error:", err.Error())
+								hasAssigned = false
+							} else {
+								fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+							}
+						} else if d, ok := vv.Interface().(string); ok {
+							hasAssigned = true
+							t, err := session.str2Time(col, d)
+							if err != nil {
+								session.Engine.logger.Error("byte2Time error:", err.Error())
+								hasAssigned = false
+							} else {
+								fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+							}
+						} else {
+							panic(fmt.Sprintf("rawValueType is %v, value is %v", rawValueType, vv.Interface()))
+						}
 					}
 					}
 				} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
 				} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
 					// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
 					// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
 					hasAssigned = true
 					hasAssigned = true
 					if err := nulVal.Scan(vv.Interface()); err != nil {
 					if err := nulVal.Scan(vv.Interface()); err != nil {
 						//fmt.Println("sql.Sanner error:", err.Error())
 						//fmt.Println("sql.Sanner error:", err.Error())
-						session.Engine.LogError("sql.Sanner error:", err.Error())
+						session.Engine.logger.Error("sql.Sanner error:", err.Error())
 						hasAssigned = false
 						hasAssigned = false
 					}
 					}
 				} else if col.SQLType.IsJson() {
 				} else if col.SQLType.IsJson() {
@@ -550,7 +616,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 						x := reflect.New(fieldType)
 						x := reflect.New(fieldType)
 						err := json.Unmarshal([]byte(vv.String()), x.Interface())
 						err := json.Unmarshal([]byte(vv.String()), x.Interface())
 						if err != nil {
 						if err != nil {
-							session.Engine.LogError(err)
+							session.Engine.logger.Error(err)
 							return err
 							return err
 						}
 						}
 						fieldValue.Set(x.Elem())
 						fieldValue.Set(x.Elem())
@@ -559,7 +625,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 						x := reflect.New(fieldType)
 						x := reflect.New(fieldType)
 						err := json.Unmarshal(vv.Bytes(), x.Interface())
 						err := json.Unmarshal(vv.Bytes(), x.Interface())
 						if err != nil {
 						if err != nil {
-							session.Engine.LogError(err)
+							session.Engine.logger.Error(err)
 							return err
 							return err
 						}
 						}
 						fieldValue.Set(x.Elem())
 						fieldValue.Set(x.Elem())
@@ -595,8 +661,10 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 							pk[0] = uint8(vv.Uint())
 							pk[0] = uint8(vv.Uint())
 						case reflect.String:
 						case reflect.String:
 							pk[0] = vv.String()
 							pk[0] = vv.String()
+						case reflect.Slice:
+							pk[0], _ = strconv.ParseInt(string(rawValue.Interface().([]byte)), 10, 64)
 						default:
 						default:
-							panic("unsupported primary key type cascade")
+							panic(fmt.Sprintf("unsupported primary key type: %v, %v", rawValueType, fieldValue))
 						}
 						}
 
 
 						if !isPKZero(pk) {
 						if !isPKZero(pk) {
@@ -618,7 +686,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 							}
 							}
 						}
 						}
 					} else {
 					} else {
-						session.Engine.LogError("unsupported struct type in Scan: ", fieldValue.Type().String())
+						session.Engine.logger.Error("unsupported struct type in Scan: ", fieldValue.Type().String())
 					}
 					}
 				}
 				}
 			case reflect.Ptr:
 			case reflect.Ptr:
@@ -641,7 +709,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 				case core.PtrTimeType:
 				case core.PtrTimeType:
 					if rawValueType == core.PtrTimeType {
 					if rawValueType == core.PtrTimeType {
 						hasAssigned = true
 						hasAssigned = true
-						var x time.Time = rawValue.Interface().(time.Time)
+						var x = rawValue.Interface().(time.Time)
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.PtrFloat64Type:
 				case core.PtrFloat64Type:
@@ -652,7 +720,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 					}
 					}
 				case core.PtrUint64Type:
 				case core.PtrUint64Type:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x uint64 = uint64(vv.Int())
+						var x = uint64(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
@@ -664,55 +732,55 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 					}
 					}
 				case core.PtrFloat32Type:
 				case core.PtrFloat32Type:
 					if rawValueType.Kind() == reflect.Float64 {
 					if rawValueType.Kind() == reflect.Float64 {
-						var x float32 = float32(vv.Float())
+						var x = float32(vv.Float())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.PtrIntType:
 				case core.PtrIntType:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x int = int(vv.Int())
+						var x = int(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.PtrInt32Type:
 				case core.PtrInt32Type:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x int32 = int32(vv.Int())
+						var x = int32(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.PtrInt8Type:
 				case core.PtrInt8Type:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x int8 = int8(vv.Int())
+						var x = int8(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.PtrInt16Type:
 				case core.PtrInt16Type:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x int16 = int16(vv.Int())
+						var x = int16(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.PtrUintType:
 				case core.PtrUintType:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x uint = uint(vv.Int())
+						var x = uint(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.PtrUint32Type:
 				case core.PtrUint32Type:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x uint32 = uint32(vv.Int())
+						var x = uint32(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.Uint8Type:
 				case core.Uint8Type:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x uint8 = uint8(vv.Int())
+						var x = uint8(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
 				case core.Uint16Type:
 				case core.Uint16Type:
 					if rawValueType.Kind() == reflect.Int64 {
 					if rawValueType.Kind() == reflect.Int64 {
-						var x uint16 = uint16(vv.Int())
+						var x = uint16(vv.Int())
 						hasAssigned = true
 						hasAssigned = true
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
@@ -720,7 +788,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 					var x complex64
 					var x complex64
 					err := json.Unmarshal([]byte(vv.String()), &x)
 					err := json.Unmarshal([]byte(vv.String()), &x)
 					if err != nil {
 					if err != nil {
-						session.Engine.LogError(err)
+						session.Engine.logger.Error(err)
 					} else {
 					} else {
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
@@ -729,7 +797,7 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 					var x complex128
 					var x complex128
 					err := json.Unmarshal([]byte(vv.String()), &x)
 					err := json.Unmarshal([]byte(vv.String()), &x)
 					if err != nil {
 					if err != nil {
-						session.Engine.LogError(err)
+						session.Engine.logger.Error(err)
 					} else {
 					} else {
 						fieldValue.Set(reflect.ValueOf(&x))
 						fieldValue.Set(reflect.ValueOf(&x))
 					}
 					}
@@ -743,9 +811,9 @@ func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Ro
 			if !hasAssigned {
 			if !hasAssigned {
 				data, err := value2Bytes(&rawValue)
 				data, err := value2Bytes(&rawValue)
 				if err == nil {
 				if err == nil {
-					session.bytes2Value(table.GetColumn(key), fieldValue, data)
+					session.bytes2Value(col, fieldValue, data)
 				} else {
 				} else {
-					session.Engine.LogError(err.Error())
+					session.Engine.logger.Error(err.Error())
 				}
 				}
 			}
 			}
 		}
 		}

+ 9 - 14
sqlite3_dialect.go

@@ -8,6 +8,7 @@ import (
 	"database/sql"
 	"database/sql"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"regexp"
 	"strings"
 	"strings"
 
 
 	"github.com/xormplus/core"
 	"github.com/xormplus/core"
@@ -263,10 +264,8 @@ func (db *sqlite3) ForUpdateSql(query string) string {
 func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
 func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
 	query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
+	db.LogSQL(query, args)
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", query, args)
-	}
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
@@ -281,11 +280,8 @@ func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
 func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
 	s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
-
+	db.LogSQL(s, args)
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
@@ -306,10 +302,13 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
 
 
 	nStart := strings.Index(name, "(")
 	nStart := strings.Index(name, "(")
 	nEnd := strings.LastIndex(name, ")")
 	nEnd := strings.LastIndex(name, ")")
-	colCreates := strings.Split(name[nStart+1:nEnd], ",")
+	reg := regexp.MustCompile(`[^\(,\)]*(\([^\(]*\))?`)
+	colCreates := reg.FindAllString(name[nStart+1:nEnd], -1)
 	cols := make(map[string]*core.Column)
 	cols := make(map[string]*core.Column)
 	colSeq := make([]string, 0)
 	colSeq := make([]string, 0)
 	for _, colStr := range colCreates {
 	for _, colStr := range colCreates {
+		reg = regexp.MustCompile(`,\s`)
+		colStr = reg.ReplaceAllString(colStr, ",")
 		fields := strings.Fields(strings.TrimSpace(colStr))
 		fields := strings.Fields(strings.TrimSpace(colStr))
 		col := new(core.Column)
 		col := new(core.Column)
 		col.Indexes = make(map[string]bool)
 		col.Indexes = make(map[string]bool)
@@ -350,11 +349,9 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
 func (db *sqlite3) GetTables() ([]*core.Table, error) {
 func (db *sqlite3) GetTables() ([]*core.Table, error) {
 	args := []interface{}{}
 	args := []interface{}{}
 	s := "SELECT name FROM sqlite_master WHERE type='table'"
 	s := "SELECT name FROM sqlite_master WHERE type='table'"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -378,11 +375,9 @@ func (db *sqlite3) GetTables() ([]*core.Table, error) {
 func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
 func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
 	s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
+	db.LogSQL(s, args)
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
-	if db.Logger != nil {
-		db.Logger.Info("[sql]", s, args)
-	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 258 - 210
statement.go

@@ -5,6 +5,7 @@
 package xorm
 package xorm
 
 
 import (
 import (
+	"bytes"
 	"database/sql/driver"
 	"database/sql/driver"
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
@@ -36,47 +37,49 @@ type exprParam struct {
 	expr    string
 	expr    string
 }
 }
 
 
-// statement save all the sql info for executing SQL
+// Statement save all the sql info for executing SQL
 type Statement struct {
 type Statement struct {
-	RefTable      *core.Table
-	Engine        *Engine
-	Start         int
-	LimitN        int
-	WhereStr      string
-	IdParam       *core.PK
-	Params        []interface{}
-	OrderStr      string
-	JoinStr       string
-	GroupByStr    string
-	HavingStr     string
-	ColumnStr     string
-	selectStr     string
-	columnMap     map[string]bool
-	useAllCols    bool
-	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
-	IsForUpdate   bool
-	TableAlias    string
-	allUseBool    bool
-	checkVersion  bool
-	unscoped      bool
-	mustColumnMap map[string]bool
-	nullableMap   map[string]bool
-	inColumns     map[string]*inParam
-	incrColumns   map[string]incrParam
-	decrColumns   map[string]decrParam
-	exprColumns   map[string]exprParam
+	RefTable        *core.Table
+	Engine          *Engine
+	Start           int
+	LimitN          int
+	WhereStr        string
+	IdParam         *core.PK
+	Params          []interface{}
+	OrderStr        string
+	JoinStr         string
+	joinArgs        []interface{}
+	GroupByStr      string
+	HavingStr       string
+	ColumnStr       string
+	selectStr       string
+	columnMap       map[string]bool
+	useAllCols      bool
+	OmitStr         string
+	ConditionStr    string
+	AltTableName    string
+	RawSQL          string
+	RawParams       []interface{}
+	UseCascade      bool
+	UseAutoJoin     bool
+	StoreEngine     string
+	Charset         string
+	BeanArgs        []interface{}
+	UseCache        bool
+	UseAutoTime     bool
+	noAutoCondition bool
+	IsDistinct      bool
+	IsForUpdate     bool
+	TableAlias      string
+	allUseBool      bool
+	checkVersion    bool
+	unscoped        bool
+	mustColumnMap   map[string]bool
+	nullableMap     map[string]bool
+	inColumns       map[string]*inParam
+	incrColumns     map[string]incrParam
+	decrColumns     map[string]decrParam
+	exprColumns     map[string]exprParam
 }
 }
 
 
 // init
 // init
@@ -89,6 +92,7 @@ func (statement *Statement) Init() {
 	statement.OrderStr = ""
 	statement.OrderStr = ""
 	statement.UseCascade = true
 	statement.UseCascade = true
 	statement.JoinStr = ""
 	statement.JoinStr = ""
+	statement.joinArgs = make([]interface{}, 0)
 	statement.GroupByStr = ""
 	statement.GroupByStr = ""
 	statement.HavingStr = ""
 	statement.HavingStr = ""
 	statement.ColumnStr = ""
 	statement.ColumnStr = ""
@@ -102,6 +106,7 @@ func (statement *Statement) Init() {
 	statement.BeanArgs = make([]interface{}, 0)
 	statement.BeanArgs = make([]interface{}, 0)
 	statement.UseCache = true
 	statement.UseCache = true
 	statement.UseAutoTime = true
 	statement.UseAutoTime = true
+	statement.noAutoCondition = false
 	statement.IsDistinct = false
 	statement.IsDistinct = false
 	statement.IsForUpdate = false
 	statement.IsForUpdate = false
 	statement.TableAlias = ""
 	statement.TableAlias = ""
@@ -118,21 +123,35 @@ func (statement *Statement) Init() {
 	statement.exprColumns = make(map[string]exprParam)
 	statement.exprColumns = make(map[string]exprParam)
 }
 }
 
 
-// add the raw sql statement
+// 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 {
+		statement.noAutoCondition = no[0]
+	}
+	return statement
+}
+
+// Sql add the raw sql statement
 func (statement *Statement) Sql(querystring string, args ...interface{}) *Statement {
 func (statement *Statement) Sql(querystring string, args ...interface{}) *Statement {
 	statement.RawSQL = querystring
 	statement.RawSQL = querystring
 	statement.RawParams = args
 	statement.RawParams = args
 	return statement
 	return statement
 }
 }
 
 
-// set the table alias
+// Alias set the table alias
 func (statement *Statement) Alias(alias string) *Statement {
 func (statement *Statement) Alias(alias string) *Statement {
 	statement.TableAlias = alias
 	statement.TableAlias = alias
 	return statement
 	return statement
 }
 }
 
 
-// add Where statment
+// Where add Where statment
 func (statement *Statement) Where(querystring string, args ...interface{}) *Statement {
 func (statement *Statement) Where(querystring string, args ...interface{}) *Statement {
+	// The second where will be triggered as And
+	if len(statement.WhereStr) > 0 {
+		return statement.And(querystring, args...)
+	}
+
 	if !strings.Contains(querystring, statement.Engine.dialect.EqStr()) {
 	if !strings.Contains(querystring, statement.Engine.dialect.EqStr()) {
 		querystring = strings.Replace(querystring, "=", statement.Engine.dialect.EqStr(), -1)
 		querystring = strings.Replace(querystring, "=", statement.Engine.dialect.EqStr(), -1)
 	}
 	}
@@ -141,11 +160,13 @@ func (statement *Statement) Where(querystring string, args ...interface{}) *Stat
 	return statement
 	return statement
 }
 }
 
 
-// add Where & and statment
+// And add Where & and statment
 func (statement *Statement) And(querystring string, args ...interface{}) *Statement {
 func (statement *Statement) And(querystring string, args ...interface{}) *Statement {
-	if statement.WhereStr != "" {
-		statement.WhereStr = fmt.Sprintf("(%v) %s (%v)", statement.WhereStr,
+	if len(statement.WhereStr) > 0 {
+		var buf bytes.Buffer
+		fmt.Fprintf(&buf, "(%v) %s (%v)", statement.WhereStr,
 			statement.Engine.dialect.AndStr(), querystring)
 			statement.Engine.dialect.AndStr(), querystring)
+		statement.WhereStr = buf.String()
 	} else {
 	} else {
 		statement.WhereStr = querystring
 		statement.WhereStr = querystring
 	}
 	}
@@ -153,11 +174,13 @@ func (statement *Statement) And(querystring string, args ...interface{}) *Statem
 	return statement
 	return statement
 }
 }
 
 
-// add Where & Or statment
+// Or add Where & Or statment
 func (statement *Statement) Or(querystring string, args ...interface{}) *Statement {
 func (statement *Statement) Or(querystring string, args ...interface{}) *Statement {
-	if statement.WhereStr != "" {
-		statement.WhereStr = fmt.Sprintf("(%v) %s (%v)", statement.WhereStr,
+	if len(statement.WhereStr) > 0 {
+		var buf bytes.Buffer
+		fmt.Fprintf(&buf, "(%v) %s (%v)", statement.WhereStr,
 			statement.Engine.dialect.OrStr(), querystring)
 			statement.Engine.dialect.OrStr(), querystring)
+		statement.WhereStr = buf.String()
 	} else {
 	} else {
 		statement.WhereStr = querystring
 		statement.WhereStr = querystring
 	}
 	}
@@ -165,7 +188,7 @@ func (statement *Statement) Or(querystring string, args ...interface{}) *Stateme
 	return statement
 	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 {
 func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
 	v := rValue(tableNameOrBean)
 	v := rValue(tableNameOrBean)
 	t := v.Type()
 	t := v.Type()
@@ -177,12 +200,12 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
 	return statement
 	return statement
 }
 }
 
 
-// Auto generating conditions according a struct
+// Auto generating update columnes and values according a struct
 func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 	includeVersion bool, includeUpdated bool, includeNil bool,
 	includeVersion bool, includeUpdated bool, includeNil bool,
 	includeAutoIncr bool, allUseBool bool, useAllCols bool,
 	includeAutoIncr bool, allUseBool bool, useAllCols bool,
 	mustColumnMap map[string]bool, nullableMap map[string]bool,
 	mustColumnMap map[string]bool, nullableMap map[string]bool,
-	columnMap map[string]bool, update bool) ([]string, []interface{}) {
+	columnMap map[string]bool, update, unscoped bool) ([]string, []interface{}) {
 
 
 	colNames := make([]string, 0)
 	colNames := make([]string, 0)
 	var args = make([]interface{}, 0)
 	var args = make([]interface{}, 0)
@@ -199,20 +222,16 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 		if !includeAutoIncr && col.IsAutoIncrement {
 		if !includeAutoIncr && col.IsAutoIncrement {
 			continue
 			continue
 		}
 		}
-		if col.IsDeleted {
+		if col.IsDeleted && !unscoped {
 			continue
 			continue
 		}
 		}
 		if use, ok := columnMap[col.Name]; ok && !use {
 		if use, ok := columnMap[col.Name]; ok && !use {
 			continue
 			continue
 		}
 		}
 
 
-		if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
-			continue
-		}
-
 		fieldValuePtr, err := col.ValueOf(bean)
 		fieldValuePtr, err := col.ValueOf(bean)
 		if err != nil {
 		if err != nil {
-			engine.LogError(err)
+			engine.logger.Error(err)
 			continue
 			continue
 		}
 		}
 
 
@@ -247,7 +266,7 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 			if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
 			if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
 				data, err := structConvert.ToDB()
 				data, err := structConvert.ToDB()
 				if err != nil {
 				if err != nil {
-					engine.LogError(err)
+					engine.logger.Error(err)
 				} else {
 				} else {
 					val = data
 					val = data
 				}
 				}
@@ -258,7 +277,7 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 		if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
 		if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
 			data, err := structConvert.ToDB()
 			data, err := structConvert.ToDB()
 			if err != nil {
 			if err != nil {
-				engine.LogError(err)
+				engine.logger.Error(err)
 			} else {
 			} else {
 				val = data
 				val = data
 			}
 			}
@@ -327,37 +346,50 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 			} else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok {
 			} else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok {
 				val, _ = nulType.Value()
 				val, _ = nulType.Value()
 			} else {
 			} else {
-				engine.autoMapType(fieldValue)
-				if table, ok := engine.Tables[fieldValue.Type()]; ok {
-					if len(table.PrimaryKeys) == 1 {
-						pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
-						// fix non-int pk issues
-						//if pkField.Int() != 0 {
-						if pkField.IsValid() && !isZero(pkField.Interface()) {
-							val = pkField.Interface()
+				if !col.SQLType.IsJson() {
+					engine.autoMapType(fieldValue)
+					if table, ok := engine.Tables[fieldValue.Type()]; ok {
+						if len(table.PrimaryKeys) == 1 {
+							pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
+							// fix non-int pk issues
+							if pkField.IsValid() && !isZero(pkField.Interface()) {
+								val = pkField.Interface()
+							} else {
+								continue
+							}
 						} else {
 						} else {
-							continue
+							//TODO: how to handler?
+							panic("not supported")
 						}
 						}
 					} else {
 					} else {
-						//TODO: how to handler?
-						panic("not supported")
+						val = fieldValue.Interface()
 					}
 					}
 				} else {
 				} else {
-					val = fieldValue.Interface()
+					bytes, err := json.Marshal(fieldValue.Interface())
+					if err != nil {
+						panic(fmt.Sprintf("mashal %v failed", fieldValue.Interface()))
+					}
+					if col.SQLType.IsText() {
+						val = string(bytes)
+					} else if col.SQLType.IsBlob() {
+						val = bytes
+					}
 				}
 				}
 			}
 			}
 		case reflect.Array, reflect.Slice, reflect.Map:
 		case reflect.Array, reflect.Slice, reflect.Map:
-			if fieldValue == reflect.Zero(fieldType) {
-				continue
-			}
-			if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
-				continue
+			if !requiredField {
+				if fieldValue == reflect.Zero(fieldType) {
+					continue
+				}
+				if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
+					continue
+				}
 			}
 			}
 
 
 			if col.SQLType.IsText() {
 			if col.SQLType.IsText() {
 				bytes, err := json.Marshal(fieldValue.Interface())
 				bytes, err := json.Marshal(fieldValue.Interface())
 				if err != nil {
 				if err != nil {
-					engine.LogError(err)
+					engine.logger.Error(err)
 					continue
 					continue
 				}
 				}
 				val = string(bytes)
 				val = string(bytes)
@@ -374,7 +406,7 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 				} else {
 				} else {
 					bytes, err = json.Marshal(fieldValue.Interface())
 					bytes, err = json.Marshal(fieldValue.Interface())
 					if err != nil {
 					if err != nil {
-						engine.LogError(err)
+						engine.logger.Error(err)
 						continue
 						continue
 					}
 					}
 					val = bytes
 					val = bytes
@@ -398,12 +430,27 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 	return colNames, args
 	return colNames, args
 }
 }
 
 
+func (statement *Statement) needTableName() bool {
+	return len(statement.JoinStr) > 0
+}
+
+func (statement *Statement) colName(col *core.Column, tableName string) string {
+	if statement.needTableName() {
+		var nm = tableName
+		if len(statement.TableAlias) > 0 {
+			nm = statement.TableAlias
+		}
+		return statement.Engine.Quote(nm) + "." + statement.Engine.Quote(col.Name)
+	}
+	return statement.Engine.Quote(col.Name)
+}
+
 // Auto generating conditions according a struct
 // Auto generating conditions according a struct
 func buildConditions(engine *Engine, table *core.Table, bean interface{},
 func buildConditions(engine *Engine, table *core.Table, bean interface{},
 	includeVersion bool, includeUpdated bool, includeNil bool,
 	includeVersion bool, includeUpdated bool, includeNil bool,
 	includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
 	includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
-	mustColumnMap map[string]bool, tableName string, addedTableName bool) ([]string, []interface{}) {
-	colNames := make([]string, 0)
+	mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) ([]string, []interface{}) {
+	var colNames []string
 	var args = make([]interface{}, 0)
 	var args = make([]interface{}, 0)
 	for _, col := range table.Columns() {
 	for _, col := range table.Columns() {
 		if !includeVersion && col.IsVersion {
 		if !includeVersion && col.IsVersion {
@@ -425,19 +472,23 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 
 
 		var colName string
 		var colName string
 		if addedTableName {
 		if addedTableName {
-			colName = engine.Quote(tableName) + "." + engine.Quote(col.Name)
+			var nm = tableName
+			if len(aliasName) > 0 {
+				nm = aliasName
+			}
+			colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
 		} else {
 		} else {
 			colName = engine.Quote(col.Name)
 			colName = engine.Quote(col.Name)
 		}
 		}
 
 
 		fieldValuePtr, err := col.ValueOf(bean)
 		fieldValuePtr, err := col.ValueOf(bean)
 		if err != nil {
 		if err != nil {
-			engine.LogError(err)
+			engine.logger.Error(err)
 			continue
 			continue
 		}
 		}
 
 
 		if col.IsDeleted && !unscoped { // tag "deleted" is enabled
 		if col.IsDeleted && !unscoped { // tag "deleted" is enabled
-			colNames = append(colNames, fmt.Sprintf("(%v IS NULL or %v = '0001-01-01 00:00:00')",
+			colNames = append(colNames, fmt.Sprintf("(%v IS NULL OR %v = '0001-01-01 00:00:00')",
 				colName, colName))
 				colName, colName))
 		}
 		}
 
 
@@ -528,7 +579,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 					if col.SQLType.IsText() {
 					if col.SQLType.IsText() {
 						bytes, err := json.Marshal(fieldValue.Interface())
 						bytes, err := json.Marshal(fieldValue.Interface())
 						if err != nil {
 						if err != nil {
-							engine.LogError(err)
+							engine.logger.Error(err)
 							continue
 							continue
 						}
 						}
 						val = string(bytes)
 						val = string(bytes)
@@ -537,7 +588,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 						var err error
 						var err error
 						bytes, err = json.Marshal(fieldValue.Interface())
 						bytes, err = json.Marshal(fieldValue.Interface())
 						if err != nil {
 						if err != nil {
-							engine.LogError(err)
+							engine.logger.Error(err)
 							continue
 							continue
 						}
 						}
 						val = bytes
 						val = bytes
@@ -574,7 +625,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 			if col.SQLType.IsText() {
 			if col.SQLType.IsText() {
 				bytes, err := json.Marshal(fieldValue.Interface())
 				bytes, err := json.Marshal(fieldValue.Interface())
 				if err != nil {
 				if err != nil {
-					engine.LogError(err)
+					engine.logger.Error(err)
 					continue
 					continue
 				}
 				}
 				val = string(bytes)
 				val = string(bytes)
@@ -591,7 +642,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 				} else {
 				} else {
 					bytes, err = json.Marshal(fieldValue.Interface())
 					bytes, err = json.Marshal(fieldValue.Interface())
 					if err != nil {
 					if err != nil {
-						engine.LogError(err)
+						engine.logger.Error(err)
 						continue
 						continue
 					}
 					}
 					val = bytes
 					val = bytes
@@ -623,6 +674,10 @@ func (statement *Statement) TableName() string {
 	}
 	}
 
 
 	if statement.RefTable != nil {
 	if statement.RefTable != nil {
+		schema := statement.Engine.dialect.URI().Schema
+		if len(schema) > 0 {
+			return schema + "." + statement.RefTable.Name
+		}
 		return statement.RefTable.Name
 		return statement.RefTable.Name
 	}
 	}
 	return ""
 	return ""
@@ -655,7 +710,7 @@ func (statement *Statement) Id(id interface{}) *Statement {
 	return 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 {
 func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
 	k := strings.ToLower(column)
 	k := strings.ToLower(column)
 	if len(arg) > 0 {
 	if len(arg) > 0 {
@@ -666,7 +721,7 @@ func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
 	return 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 {
 func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
 	k := strings.ToLower(column)
 	k := strings.ToLower(column)
 	if len(arg) > 0 {
 	if len(arg) > 0 {
@@ -677,7 +732,7 @@ func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
 	return 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 {
 func (statement *Statement) SetExpr(column string, expression string) *Statement {
 	k := strings.ToLower(column)
 	k := strings.ToLower(column)
 	statement.exprColumns[k] = exprParam{column, expression}
 	statement.exprColumns[k] = exprParam{column, expression}
@@ -701,9 +756,14 @@ func (statement *Statement) getExpr() map[string]exprParam {
 
 
 // Generate "Where column IN (?) " statment
 // Generate "Where column IN (?) " statment
 func (statement *Statement) In(column string, args ...interface{}) *Statement {
 func (statement *Statement) In(column string, args ...interface{}) *Statement {
+	length := len(args)
+	if length == 0 {
+		return statement
+	}
+
 	k := strings.ToLower(column)
 	k := strings.ToLower(column)
 	var newargs []interface{}
 	var newargs []interface{}
-	if len(args) == 1 &&
+	if length == 1 &&
 		reflect.TypeOf(args[0]).Kind() == reflect.Slice {
 		reflect.TypeOf(args[0]).Kind() == reflect.Slice {
 		newargs = make([]interface{}, 0)
 		newargs = make([]interface{}, 0)
 		v := reflect.ValueOf(args[0])
 		v := reflect.ValueOf(args[0])
@@ -727,12 +787,17 @@ func (statement *Statement) genInSql() (string, []interface{}) {
 		return "", []interface{}{}
 		return "", []interface{}{}
 	}
 	}
 
 
-	inStrs := make([]string, 0, len(statement.inColumns))
+	inStrs := make([]string, len(statement.inColumns), len(statement.inColumns))
 	args := make([]interface{}, 0)
 	args := make([]interface{}, 0)
+	var buf bytes.Buffer
+	var i int
 	for _, params := range statement.inColumns {
 	for _, params := range statement.inColumns {
-		inStrs = append(inStrs, fmt.Sprintf("(%v IN (%v))",
-			statement.Engine.autoQuote(params.colName),
-			strings.Join(makeArray("?", len(params.args)), ",")))
+		buf.Reset()
+		fmt.Fprintf(&buf, "(%v IN (%v))",
+			statement.Engine.quoteColumn(params.colName),
+			strings.Join(makeArray("?", len(params.args)), ","))
+		inStrs[i] = buf.String()
+		i++
 		args = append(args, params.args...)
 		args = append(args, params.args...)
 	}
 	}
 
 
@@ -745,7 +810,7 @@ func (statement *Statement) genInSql() (string, []interface{}) {
 func (statement *Statement) attachInSql() {
 func (statement *Statement) attachInSql() {
 	inSql, inArgs := statement.genInSql()
 	inSql, inArgs := statement.genInSql()
 	if len(inSql) > 0 {
 	if len(inSql) > 0 {
-		if statement.ConditionStr != "" {
+		if len(statement.ConditionStr) > 0 {
 			statement.ConditionStr += " " + statement.Engine.dialect.AndStr() + " "
 			statement.ConditionStr += " " + statement.Engine.dialect.AndStr() + " "
 		}
 		}
 		statement.ConditionStr += inSql
 		statement.ConditionStr += inSql
@@ -766,16 +831,6 @@ func col2NewCols(columns ...string) []string {
 	return newColumns
 	return newColumns
 }
 }
 
 
-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, ".")
-}
-
 func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
 func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
 	newColumns := make([]string, 0)
 	newColumns := make([]string, 0)
 	for _, col := range columns {
 	for _, col := range columns {
@@ -785,10 +840,10 @@ func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
 		for _, c := range ccols {
 		for _, c := range ccols {
 			fields := strings.Split(strings.TrimSpace(c), ".")
 			fields := strings.Split(strings.TrimSpace(c), ".")
 			if len(fields) == 1 {
 			if len(fields) == 1 {
-				newColumns = append(newColumns, statement.Engine.Quote(fields[0]))
+				newColumns = append(newColumns, statement.Engine.quote(fields[0]))
 			} else if len(fields) == 2 {
 			} else if len(fields) == 2 {
-				newColumns = append(newColumns, statement.Engine.Quote(fields[0])+"."+
-					statement.Engine.Quote(fields[1]))
+				newColumns = append(newColumns, statement.Engine.quote(fields[0])+"."+
+					statement.Engine.quote(fields[1]))
 			} else {
 			} else {
 				panic(errors.New("unwanted colnames"))
 				panic(errors.New("unwanted colnames"))
 			}
 			}
@@ -818,15 +873,15 @@ func (s *Statement) Select(str string) *Statement {
 
 
 // Generate "col1, col2" statement
 // Generate "col1, col2" statement
 func (statement *Statement) Cols(columns ...string) *Statement {
 func (statement *Statement) Cols(columns ...string) *Statement {
-	newColumns := col2NewCols(columns...)
-	for _, nc := range newColumns {
+	cols := col2NewCols(columns...)
+	for _, nc := range cols {
 		statement.columnMap[strings.ToLower(nc)] = true
 		statement.columnMap[strings.ToLower(nc)] = true
 	}
 	}
-	statement.ColumnStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
-	if strings.Contains(statement.ColumnStr, ".") {
-		statement.ColumnStr = strings.Replace(statement.ColumnStr, ".", statement.Engine.Quote("."), -1)
-	}
-	statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.Quote("*"), "*", -1)
+
+	newColumns := statement.col2NewColsWithQuote(columns...)
+	//fmt.Println("=====", columns, newColumns, cols)
+	statement.ColumnStr = strings.Join(newColumns, ", ")
+	statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.quote("*"), "*", -1)
 	return statement
 	return statement
 }
 }
 
 
@@ -845,15 +900,6 @@ func (statement *Statement) MustCols(columns ...string) *Statement {
 	return statement
 	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
-}*/
-
 // indicates that use bool fields as update contents and query contiditions
 // indicates that use bool fields as update contents and query contiditions
 func (statement *Statement) UseBool(columns ...string) *Statement {
 func (statement *Statement) UseBool(columns ...string) *Statement {
 	if len(columns) > 0 {
 	if len(columns) > 0 {
@@ -898,7 +944,7 @@ 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 != "" {
+	if len(statement.OrderStr) > 0 {
 		statement.OrderStr += ", "
 		statement.OrderStr += ", "
 	}
 	}
 	statement.OrderStr += order
 	statement.OrderStr += order
@@ -906,44 +952,51 @@ func (statement *Statement) OrderBy(order string) *Statement {
 }
 }
 
 
 func (statement *Statement) Desc(colNames ...string) *Statement {
 func (statement *Statement) Desc(colNames ...string) *Statement {
-	if statement.OrderStr != "" {
-		statement.OrderStr += ", "
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, statement.OrderStr)
+	if len(statement.OrderStr) > 0 {
+		fmt.Fprint(&buf, ", ")
 	}
 	}
 	newColNames := statement.col2NewColsWithQuote(colNames...)
 	newColNames := statement.col2NewColsWithQuote(colNames...)
-	sqlStr := strings.Join(newColNames, " DESC, ")
-	statement.OrderStr += sqlStr + " DESC"
+	fmt.Fprintf(&buf, "%v DESC", strings.Join(newColNames, " DESC, "))
+	statement.OrderStr = buf.String()
 	return statement
 	return statement
 }
 }
 
 
 // Method Asc provide asc order by query condition, the input parameters are columns.
 // Method Asc provide asc order by query condition, the input parameters are columns.
 func (statement *Statement) Asc(colNames ...string) *Statement {
 func (statement *Statement) Asc(colNames ...string) *Statement {
-	if statement.OrderStr != "" {
-		statement.OrderStr += ", "
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, statement.OrderStr)
+	if len(statement.OrderStr) > 0 {
+		fmt.Fprint(&buf, ", ")
 	}
 	}
 	newColNames := statement.col2NewColsWithQuote(colNames...)
 	newColNames := statement.col2NewColsWithQuote(colNames...)
-	sqlStr := strings.Join(newColNames, " ASC, ")
-	statement.OrderStr += sqlStr + " ASC"
+	fmt.Fprintf(&buf, "%v ASC", strings.Join(newColNames, " ASC, "))
+	statement.OrderStr = buf.String()
 	return statement
 	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 string, tablename interface{}, condition string) *Statement {
-	var joinTable string
+func (statement *Statement) Join(join_operator string, tablename interface{}, condition string, args ...interface{}) *Statement {
+	var buf bytes.Buffer
+	if len(statement.JoinStr) > 0 {
+		fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, join_operator)
+	} else {
+		fmt.Fprintf(&buf, "%v JOIN ", join_operator)
+	}
+
 	switch tablename.(type) {
 	switch tablename.(type) {
 	case []string:
 	case []string:
 		t := tablename.([]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)
+		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{}:
 	case []interface{}:
 		t := tablename.([]interface{})
 		t := tablename.([]interface{})
 		l := len(t)
 		l := len(t)
-		table := ""
+		var table string
 		if l > 0 {
 		if l > 0 {
 			f := t[0]
 			f := t[0]
 			v := rValue(f)
 			v := rValue(f)
@@ -956,21 +1009,18 @@ func (statement *Statement) Join(join_operator string, tablename interface{}, co
 			}
 			}
 		}
 		}
 		if l > 1 {
 		if l > 1 {
-			joinTable = statement.Engine.Quote(table) + " AS " + statement.Engine.Quote(fmt.Sprintf("%v", t[1]))
+			fmt.Fprintf(&buf, "%v AS %v", statement.Engine.Quote(table),
+				statement.Engine.Quote(fmt.Sprintf("%v", t[1])))
 		} else if l == 1 {
 		} else if l == 1 {
-			joinTable = statement.Engine.Quote(table)
+			fmt.Fprintf(&buf, statement.Engine.Quote(table))
 		}
 		}
 	default:
 	default:
-		t := fmt.Sprintf("%v", tablename)
-		joinTable = statement.Engine.Quote(t)
-	}
-	if statement.JoinStr != "" {
-		statement.JoinStr = statement.JoinStr + fmt.Sprintf(" %v JOIN %v ON %v", join_operator,
-			joinTable, condition)
-	} else {
-		statement.JoinStr = fmt.Sprintf("%v JOIN %v ON %v", join_operator,
-			joinTable, condition)
+		fmt.Fprintf(&buf, statement.Engine.Quote(fmt.Sprintf("%v", tablename)))
 	}
 	}
+
+	fmt.Fprintf(&buf, " ON %v", condition)
+	statement.JoinStr = buf.String()
+	statement.joinArgs = args
 	return statement
 	return statement
 }
 }
 
 
@@ -1045,7 +1095,7 @@ func (s *Statement) genIndexSQL() []string {
 	quote := s.Engine.Quote
 	quote := s.Engine.Quote
 	for idxName, index := range s.RefTable.Indexes {
 	for idxName, index := range s.RefTable.Indexes {
 		if index.Type == core.IndexType {
 		if index.Type == core.IndexType {
-			sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(tbName, idxName)),
+			sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(s.RefTable.Name, idxName)),
 				quote(tbName), quote(strings.Join(index.Cols, quote(","))))
 				quote(tbName), quote(strings.Join(index.Cols, quote(","))))
 			sqls = append(sqls, sql)
 			sqls = append(sqls, sql)
 		}
 		}
@@ -1059,10 +1109,9 @@ func uniqueName(tableName, uqeName string) string {
 
 
 func (s *Statement) genUniqueSQL() []string {
 func (s *Statement) genUniqueSQL() []string {
 	var sqls []string = make([]string, 0)
 	var sqls []string = make([]string, 0)
-	tbName := s.TableName()
 	for _, index := range s.RefTable.Indexes {
 	for _, index := range s.RefTable.Indexes {
 		if index.Type == core.UniqueType {
 		if index.Type == core.UniqueType {
-			sql := s.Engine.dialect.CreateIndexSql(tbName, index)
+			sql := s.Engine.dialect.CreateIndexSql(s.RefTable.Name, index)
 			sqls = append(sqls, sql)
 			sqls = append(sqls, sql)
 		}
 		}
 	}
 	}
@@ -1074,9 +1123,9 @@ func (s *Statement) genDelIndexSQL() []string {
 	for idxName, index := range s.RefTable.Indexes {
 	for idxName, index := range s.RefTable.Indexes {
 		var rIdxName string
 		var rIdxName string
 		if index.Type == core.UniqueType {
 		if index.Type == core.UniqueType {
-			rIdxName = uniqueName(s.TableName(), idxName)
+			rIdxName = uniqueName(s.RefTable.Name, idxName)
 		} else if index.Type == core.IndexType {
 		} else if index.Type == core.IndexType {
-			rIdxName = indexName(s.TableName(), idxName)
+			rIdxName = indexName(s.RefTable.Name, idxName)
 		}
 		}
 		sql := fmt.Sprintf("DROP INDEX %v", s.Engine.Quote(rIdxName))
 		sql := fmt.Sprintf("DROP INDEX %v", s.Engine.Quote(rIdxName))
 		if s.Engine.dialect.IndexOnTable() {
 		if s.Engine.dialect.IndexOnTable() {
@@ -1087,11 +1136,6 @@ func (s *Statement) genDelIndexSQL() []string {
 	return sqls
 	return sqls
 }
 }
 
 
-/*
-func (s *Statement) genDropSQL() string {
-	return s.Engine.dialect.MustDropTa(s.TableName()) + ";"
-}*/
-
 func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) {
 func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) {
 	var table *core.Table
 	var table *core.Table
 	if statement.RefTable == nil {
 	if statement.RefTable == nil {
@@ -1103,20 +1147,21 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
 
 
 	var addedTableName = (len(statement.JoinStr) > 0)
 	var addedTableName = (len(statement.JoinStr) > 0)
 
 
-	colNames, args := buildConditions(statement.Engine, table, bean, true, true,
-		false, true, statement.allUseBool, statement.useAllCols,
-		statement.unscoped, statement.mustColumnMap, statement.TableName(), addedTableName)
+	if !statement.noAutoCondition {
+		colNames, args := statement.buildConditions(table, bean, true, true, false, true, addedTableName)
 
 
-	statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.dialect.AndStr()+" ")
-	statement.BeanArgs = args
+		statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.dialect.AndStr()+" ")
+		statement.BeanArgs = args
+	}
 
 
 	var columnStr string = statement.ColumnStr
 	var columnStr string = statement.ColumnStr
 	if len(statement.selectStr) > 0 {
 	if len(statement.selectStr) > 0 {
 		columnStr = statement.selectStr
 		columnStr = statement.selectStr
 	} else {
 	} else {
+		// TODO: always generate column names, not use * even if join
 		if len(statement.JoinStr) == 0 {
 		if len(statement.JoinStr) == 0 {
 			if len(columnStr) == 0 {
 			if len(columnStr) == 0 {
-				if statement.GroupByStr != "" {
+				if len(statement.GroupByStr) > 0 {
 					columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
 					columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
 				} else {
 				} else {
 					columnStr = statement.genColumnStr()
 					columnStr = statement.genColumnStr()
@@ -1124,7 +1169,7 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
 			}
 			}
 		} else {
 		} else {
 			if len(columnStr) == 0 {
 			if len(columnStr) == 0 {
-				if statement.GroupByStr != "" {
+				if len(statement.GroupByStr) > 0 {
 					columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
 					columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
 				} else {
 				} else {
 					columnStr = "*"
 					columnStr = "*"
@@ -1134,7 +1179,7 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
 	}
 	}
 
 
 	statement.attachInSql() // !admpub!  fix bug:Iterate func missing "... IN (...)"
 	statement.attachInSql() // !admpub!  fix bug:Iterate func missing "... IN (...)"
-	return statement.genSelectSql(columnStr), append(statement.Params, statement.BeanArgs...)
+	return statement.genSelectSQL(columnStr), append(append(statement.joinArgs, statement.Params...), statement.BeanArgs...)
 }
 }
 
 
 func (s *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) {
 func (s *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) {
@@ -1158,64 +1203,67 @@ func (s *Statement) genAddUniqueStr(uqeName string, cols []string) (string, []in
 	return sql, []interface{}{}
 	return sql, []interface{}{}
 }*/
 }*/
 
 
+func (statement *Statement) buildConditions(table *core.Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, addedTableName bool) ([]string, []interface{}) {
+	return buildConditions(statement.Engine, table, bean, includeVersion, includeUpdated, includeNil, includeAutoIncr, statement.allUseBool, statement.useAllCols,
+		statement.unscoped, statement.mustColumnMap, statement.TableName(), statement.TableAlias, addedTableName)
+}
+
 func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}) {
 func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}) {
 	table := statement.Engine.TableInfo(bean)
 	table := statement.Engine.TableInfo(bean)
 	statement.RefTable = table
 	statement.RefTable = table
 
 
 	var addedTableName = (len(statement.JoinStr) > 0)
 	var addedTableName = (len(statement.JoinStr) > 0)
 
 
-	colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
-		true, statement.allUseBool, statement.useAllCols,
-		statement.unscoped, statement.mustColumnMap, statement.TableName(), addedTableName)
+	if !statement.noAutoCondition {
+		colNames, args := statement.buildConditions(table, bean, true, true, false, true, addedTableName)
 
 
-	statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.Dialect().AndStr()+" ")
-	statement.BeanArgs = args
+		statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.Dialect().AndStr()+" ")
+		statement.BeanArgs = args
+	}
 
 
 	// count(index fieldname) > count(0) > count(*)
 	// count(index fieldname) > count(0) > count(*)
-	var id string = "*"
+	var id = "*"
 	if statement.Engine.Dialect().DBType() == "ql" {
 	if statement.Engine.Dialect().DBType() == "ql" {
 		id = ""
 		id = ""
 	}
 	}
 	statement.attachInSql()
 	statement.attachInSql()
-	return statement.genSelectSql(fmt.Sprintf("count(%v)", id)), append(statement.Params, statement.BeanArgs...)
+	return statement.genSelectSQL(fmt.Sprintf("count(%v)", id)), append(append(statement.joinArgs, statement.Params...), statement.BeanArgs...)
 }
 }
 
 
-func (statement *Statement) genSelectSql(columnStr string) (a string) {
-	/*if statement.GroupByStr != "" {
-		if columnStr == "" {
-			columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
-		}
-		//statement.GroupByStr = columnStr
-	}*/
+func (statement *Statement) genSelectSQL(columnStr string) (a string) {
 	var distinct string
 	var distinct string
 	if statement.IsDistinct {
 	if statement.IsDistinct {
 		distinct = "DISTINCT "
 		distinct = "DISTINCT "
 	}
 	}
 
 
-	var dialect core.Dialect = statement.Engine.Dialect()
+	var dialect = statement.Engine.Dialect()
+	var quote = statement.Engine.Quote
 	var top string
 	var top string
 	var mssqlCondi string
 	var mssqlCondi string
-	/*var orderBy string
-	if statement.OrderStr != "" {
-		orderBy = fmt.Sprintf(" ORDER BY %v", statement.OrderStr)
-	}*/
+
 	statement.processIdParam()
 	statement.processIdParam()
-	var whereStr string
-	if statement.WhereStr != "" {
-		whereStr = fmt.Sprintf(" WHERE %v", statement.WhereStr)
+
+	var buf bytes.Buffer
+	if len(statement.WhereStr) > 0 {
+		if len(statement.ConditionStr) > 0 {
+			fmt.Fprintf(&buf, " WHERE (%v)", statement.WhereStr)
+		} else {
+			fmt.Fprintf(&buf, " WHERE %v", statement.WhereStr)
+		}
 		if statement.ConditionStr != "" {
 		if statement.ConditionStr != "" {
-			whereStr = fmt.Sprintf("%v %s %v", whereStr, dialect.AndStr(),
-				statement.ConditionStr)
+			fmt.Fprintf(&buf, " %s (%v)", dialect.AndStr(), statement.ConditionStr)
 		}
 		}
-	} else if statement.ConditionStr != "" {
-		whereStr = fmt.Sprintf(" WHERE %v", statement.ConditionStr)
+	} else if len(statement.ConditionStr) > 0 {
+		fmt.Fprintf(&buf, " WHERE %v", statement.ConditionStr)
 	}
 	}
-	var fromStr string = " FROM " + statement.Engine.Quote(statement.TableName())
+	var whereStr = buf.String()
+
+	var fromStr string = " FROM " + quote(statement.TableName())
 	if statement.TableAlias != "" {
 	if statement.TableAlias != "" {
 		if dialect.DBType() == core.ORACLE {
 		if dialect.DBType() == core.ORACLE {
-			fromStr += " " + statement.Engine.Quote(statement.TableAlias)
+			fromStr += " " + quote(statement.TableAlias)
 		} else {
 		} else {
-			fromStr += " AS " + statement.Engine.Quote(statement.TableAlias)
+			fromStr += " AS " + quote(statement.TableAlias)
 		}
 		}
 	}
 	}
 	if statement.JoinStr != "" {
 	if statement.JoinStr != "" {
@@ -1253,10 +1301,9 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
 	}
 	}
 
 
 	// !nashtsai! REVIEW Sprintf is considered slowest mean of string concatnation, better to work with builder pattern
 	// !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 != "" {
-		if whereStr != "" {
+	a = fmt.Sprintf("SELECT %v%v%v%v%v", top, distinct, columnStr, fromStr, whereStr)
+	if len(mssqlCondi) > 0 {
+		if len(whereStr) > 0 {
 			a += " AND " + mssqlCondi
 			a += " AND " + mssqlCondi
 		} else {
 		} else {
 			a += " WHERE " + mssqlCondi
 			a += " WHERE " + mssqlCondi
@@ -1284,7 +1331,7 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
 		}
 		}
 	}
 	}
 	if statement.IsForUpdate {
 	if statement.IsForUpdate {
-			a = dialect.ForUpdateSql(a)
+		a = dialect.ForUpdateSql(a)
 	}
 	}
 
 
 	return
 	return
@@ -1294,11 +1341,12 @@ func (statement *Statement) processIdParam() {
 	if statement.IdParam != nil {
 	if statement.IdParam != nil {
 		if statement.Engine.dialect.DBType() != "ql" {
 		if statement.Engine.dialect.DBType() != "ql" {
 			for i, col := range statement.RefTable.PKColumns() {
 			for i, col := range statement.RefTable.PKColumns() {
+				var colName = statement.colName(col, statement.TableName())
 				if i < len(*(statement.IdParam)) {
 				if i < len(*(statement.IdParam)) {
-					statement.And(fmt.Sprintf("%v %s ?", statement.Engine.Quote(col.Name),
+					statement.And(fmt.Sprintf("%v %s ?", colName,
 						statement.Engine.dialect.EqStr()), (*(statement.IdParam))[i])
 						statement.Engine.dialect.EqStr()), (*(statement.IdParam))[i])
 				} else {
 				} else {
-					statement.And(fmt.Sprintf("%v %s ?", statement.Engine.Quote(col.Name),
+					statement.And(fmt.Sprintf("%v %s ?", colName,
 						statement.Engine.dialect.EqStr()), "")
 						statement.Engine.dialect.EqStr()), "")
 				}
 				}
 			}
 			}

+ 33 - 19
syslogger.go

@@ -13,44 +13,48 @@ import (
 	"github.com/xormplus/core"
 	"github.com/xormplus/core"
 )
 )
 
 
+var _ core.ILogger = &SyslogLogger{}
+
+// SyslogLogger will be depricated
 type SyslogLogger struct {
 type SyslogLogger struct {
-	w *syslog.Writer
+	w       *syslog.Writer
+	showSQL bool
 }
 }
 
 
 func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
 func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
 	return &SyslogLogger{w: w}
 	return &SyslogLogger{w: w}
 }
 }
 
 
-func (s *SyslogLogger) Debug(v ...interface{}) (err error) {
-	return s.w.Debug(fmt.Sprint(v...))
+func (s *SyslogLogger) Debug(v ...interface{}) {
+	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) Debugf(format string, v ...interface{}) {
+	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) Error(v ...interface{}) {
+	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) Errorf(format string, v ...interface{}) {
+	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) Info(v ...interface{}) {
+	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) Infof(format string, v ...interface{}) {
+	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) Warn(v ...interface{}) {
+	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) Warnf(format string, v ...interface{}) {
+	s.w.Warning(fmt.Sprintf(format, v...))
 }
 }
 
 
 func (s *SyslogLogger) Level() core.LogLevel {
 func (s *SyslogLogger) Level() core.LogLevel {
@@ -58,6 +62,16 @@ func (s *SyslogLogger) Level() core.LogLevel {
 }
 }
 
 
 // SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
 // 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")
+func (s *SyslogLogger) SetLevel(l core.LogLevel) {}
+
+func (s *SyslogLogger) ShowSQL(show ...bool) {
+	if len(show) == 0 {
+		s.showSQL = true
+		return
+	}
+	s.showSQL = show[0]
+}
+
+func (s *SyslogLogger) IsShowSQL() bool {
+	return s.showSQL
 }
 }

+ 8 - 9
xorm.go

@@ -5,7 +5,6 @@
 package xorm
 package xorm
 
 
 import (
 import (
-	"errors"
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 	"reflect"
 	"reflect"
@@ -17,7 +16,7 @@ import (
 )
 )
 
 
 const (
 const (
-	Version string = "0.4.3.0824"
+	Version string = "0.5.3.0331"
 )
 )
 
 
 func regDrvsNDialects() bool {
 func regDrvsNDialects() bool {
@@ -49,13 +48,13 @@ func close(engine *Engine) {
 	engine.Close()
 	engine.Close()
 }
 }
 
 
-// new a db manager according to the parameter. Currently support four
+// NewEngine new a db manager according to the parameter. Currently support four
 // drivers
 // drivers
 func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 	regDrvsNDialects()
 	regDrvsNDialects()
 	driver := core.QueryDriver(driverName)
 	driver := core.QueryDriver(driverName)
 	if driver == nil {
 	if driver == nil {
-		return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
+		return nil, fmt.Errorf("Unsupported driver name: %v", driverName)
 	}
 	}
 
 
 	uri, err := driver.Parse(driverName, dataSourceName)
 	uri, err := driver.Parse(driverName, dataSourceName)
@@ -65,7 +64,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 
 
 	dialect := core.QueryDialect(uri.DbType)
 	dialect := core.QueryDialect(uri.DbType)
 	if dialect == nil {
 	if dialect == nil {
-		return nil, errors.New(fmt.Sprintf("Unsupported dialect type: %v", uri.DbType))
+		return nil, fmt.Errorf("Unsupported dialect type: %v", uri.DbType)
 	}
 	}
 
 
 	db, err := core.Open(driverName, dataSourceName)
 	db, err := core.Open(driverName, dataSourceName)
@@ -84,12 +83,12 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 		Tables:        make(map[reflect.Type]*core.Table),
 		Tables:        make(map[reflect.Type]*core.Table),
 		mutex:         &sync.RWMutex{},
 		mutex:         &sync.RWMutex{},
 		TagIdentifier: "xorm",
 		TagIdentifier: "xorm",
-		Logger:        NewSimpleLogger(os.Stdout),
 		TZLocation:    time.Local,
 		TZLocation:    time.Local,
 	}
 	}
 
 
-	engine.dialect.SetLogger(engine.Logger)
-
+	logger := NewSimpleLogger(os.Stdout)
+	logger.SetLevel(core.LOG_INFO)
+	engine.SetLogger(logger)
 	engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
 	engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
 
 
 	runtime.SetFinalizer(engine, close)
 	runtime.SetFinalizer(engine, close)
@@ -97,7 +96,7 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 	return engine, nil
 	return engine, nil
 }
 }
 
 
-// clone an engine
+// Clone clone an engine
 func (engine *Engine) Clone() (*Engine, error) {
 func (engine *Engine) Clone() (*Engine, error) {
 	return NewEngine(engine.DriverName(), engine.DataSourceName())
 	return NewEngine(engine.DriverName(), engine.DataSourceName())
 }
 }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است