Преглед на файлове

dependency(): updated go lib go-xorm

Torkel Ödegaard преди 10 години
родител
ревизия
9dac382fbf
променени са 42 файла, в които са добавени 1635 реда и са изтрити 719 реда
  1. 5 4
      Godeps/Godeps.json
  2. 27 0
      Godeps/_workspace/src/github.com/go-xorm/core/LICENSE
  3. 12 7
      Godeps/_workspace/src/github.com/go-xorm/core/cache.go
  4. 21 35
      Godeps/_workspace/src/github.com/go-xorm/core/column.go
  5. 106 19
      Godeps/_workspace/src/github.com/go-xorm/core/db.go
  6. 4 4
      Godeps/_workspace/src/github.com/go-xorm/core/db_test.go
  7. 37 26
      Godeps/_workspace/src/github.com/go-xorm/core/dialect.go
  8. 1 1
      Godeps/_workspace/src/github.com/go-xorm/core/error.go
  9. 52 0
      Godeps/_workspace/src/github.com/go-xorm/core/scan.go
  10. 8 2
      Godeps/_workspace/src/github.com/go-xorm/core/type.go
  11. 1 1
      Godeps/_workspace/src/github.com/go-xorm/xorm/LICENSE
  12. 169 17
      Godeps/_workspace/src/github.com/go-xorm/xorm/README.md
  13. 169 11
      Godeps/_workspace/src/github.com/go-xorm/xorm/README_CN.md
  14. 1 1
      Godeps/_workspace/src/github.com/go-xorm/xorm/VERSION
  15. 1 1
      Godeps/_workspace/src/github.com/go-xorm/xorm/doc.go
  16. 94 43
      Godeps/_workspace/src/github.com/go-xorm/xorm/engine.go
  17. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/error.go
  18. BIN
      Godeps/_workspace/src/github.com/go-xorm/xorm/examples/goroutine.db-journal
  19. 2 2
      Godeps/_workspace/src/github.com/go-xorm/xorm/examples/goroutine.go
  20. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/goracle_driver.go
  21. 71 2
      Godeps/_workspace/src/github.com/go-xorm/xorm/helpers.go
  22. 22 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/helpers_test.go
  23. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/logger.go
  24. 4 1
      Godeps/_workspace/src/github.com/go-xorm/xorm/lru_cacher.go
  25. 4 1
      Godeps/_workspace/src/github.com/go-xorm/xorm/memory_store.go
  26. 16 3
      Godeps/_workspace/src/github.com/go-xorm/xorm/mssql_dialect.go
  27. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/mymysql_driver.go
  28. 6 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/mysql_dialect.go
  29. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/mysql_driver.go
  30. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/oci8_driver.go
  31. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/odbc_driver.go
  32. 9 3
      Godeps/_workspace/src/github.com/go-xorm/xorm/oracle_dialect.go
  33. 9 4
      Godeps/_workspace/src/github.com/go-xorm/xorm/postgres_dialect.go
  34. 6 2
      Godeps/_workspace/src/github.com/go-xorm/xorm/pq_driver.go
  35. 8 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/processors.go
  36. 5 1
      Godeps/_workspace/src/github.com/go-xorm/xorm/rows.go
  37. 380 212
      Godeps/_workspace/src/github.com/go-xorm/xorm/session.go
  38. 25 5
      Godeps/_workspace/src/github.com/go-xorm/xorm/sqlite3_dialect.go
  39. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/sqlite3_driver.go
  40. 318 309
      Godeps/_workspace/src/github.com/go-xorm/xorm/statement.go
  41. 4 0
      Godeps/_workspace/src/github.com/go-xorm/xorm/syslogger.go
  42. 6 2
      Godeps/_workspace/src/github.com/go-xorm/xorm/xorm.go

+ 5 - 4
Godeps/Godeps.json

@@ -1,6 +1,6 @@
 {
 {
 	"ImportPath": "github.com/grafana/grafana",
 	"ImportPath": "github.com/grafana/grafana",
-	"GoVersion": "go1.5",
+	"GoVersion": "go1.5.1",
 	"Packages": [
 	"Packages": [
 		"./pkg/..."
 		"./pkg/..."
 	],
 	],
@@ -106,12 +106,13 @@
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/go-xorm/core",
 			"ImportPath": "github.com/go-xorm/core",
-			"Rev": "be6e7ac47dc57bd0ada25322fa526944f66ccaa6"
+			"Comment": "v0.4.4-7-g9e608f7",
+			"Rev": "9e608f7330b9d16fe2818cfe731128b3f156cb9a"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/go-xorm/xorm",
 			"ImportPath": "github.com/go-xorm/xorm",
-			"Comment": "v0.4.2-58-ge2889e5",
-			"Rev": "e2889e5517600b82905f1d2ba8b70deb71823ffe"
+			"Comment": "v0.4.4-44-gf561133",
+			"Rev": "f56113384f2c63dfe4cd8e768e349f1c35122b58"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/gosimple/slug",
 			"ImportPath": "github.com/gosimple/slug",

+ 27 - 0
Godeps/_workspace/src/github.com/go-xorm/core/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2013 - 2015 Lunny Xiao <xiaolunwen@gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of the {organization} nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 12 - 7
Godeps/_workspace/src/github.com/go-xorm/core/cache.go

@@ -1,10 +1,11 @@
 package core
 package core
 
 
 import (
 import (
-	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"time"
 	"time"
+	"bytes"
+	"encoding/gob"
 )
 )
 
 
 const (
 const (
@@ -47,16 +48,20 @@ type Cacher interface {
 }
 }
 
 
 func encodeIds(ids []PK) (string, error) {
 func encodeIds(ids []PK) (string, error) {
-	b, err := json.Marshal(ids)
-	if err != nil {
-		return "", err
-	}
-	return string(b), nil
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	err := enc.Encode(ids)
+
+	return buf.String(), err
 }
 }
 
 
+
 func decodeIds(s string) ([]PK, error) {
 func decodeIds(s string) ([]PK, error) {
 	pks := make([]PK, 0)
 	pks := make([]PK, 0)
-	err := json.Unmarshal([]byte(s), &pks)
+
+	dec := gob.NewDecoder(bytes.NewBufferString(s))
+	err := dec.Decode(&pks)
+
 	return pks, err
 	return pks, err
 }
 }
 
 

+ 21 - 35
Godeps/_workspace/src/github.com/go-xorm/core/column.go

@@ -1,10 +1,10 @@
 package core
 package core
 
 
 import (
 import (
-	"errors"
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
 	"strings"
 	"strings"
+	"time"
 )
 )
 
 
 const (
 const (
@@ -35,6 +35,8 @@ type Column struct {
 	DefaultIsEmpty  bool
 	DefaultIsEmpty  bool
 	EnumOptions     map[string]int
 	EnumOptions     map[string]int
 	SetOptions      map[string]int
 	SetOptions      map[string]int
+	DisableTimeZone bool
+	TimeZone        *time.Location // column specified time zone
 }
 }
 
 
 func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
 func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
@@ -122,50 +124,34 @@ func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
 	}
 	}
 
 
 	if dataStruct.Type().Kind() == reflect.Map {
 	if dataStruct.Type().Kind() == reflect.Map {
-		var keyValue reflect.Value
-
-		if len(col.fieldPath) == 1 {
-			keyValue = reflect.ValueOf(col.FieldName)
-		} else if len(col.fieldPath) == 2 {
-			keyValue = reflect.ValueOf(col.fieldPath[1])
-		} else {
-			return nil, fmt.Errorf("Unsupported mutliderive %v", col.FieldName)
-		}
-
+		keyValue := reflect.ValueOf(col.fieldPath[len(col.fieldPath)-1])
 		fieldValue = dataStruct.MapIndex(keyValue)
 		fieldValue = dataStruct.MapIndex(keyValue)
 		return &fieldValue, nil
 		return &fieldValue, nil
+	} else if dataStruct.Type().Kind() == reflect.Interface {
+		structValue := reflect.ValueOf(dataStruct.Interface())
+		dataStruct = &structValue
 	}
 	}
 
 
-	if len(col.fieldPath) == 1 {
-		fieldValue = dataStruct.FieldByName(col.FieldName)
-	} else if len(col.fieldPath) == 2 {
-		parentField := dataStruct.FieldByName(col.fieldPath[0])
-		if parentField.IsValid() {
-			if parentField.Kind() == reflect.Struct {
-				fieldValue = parentField.FieldByName(col.fieldPath[1])
-			} else if parentField.Kind() == reflect.Ptr {
-				if parentField.IsNil() {
-					parentField.Set(reflect.New(parentField.Type().Elem()))
-					fieldValue = parentField.Elem().FieldByName(col.fieldPath[1])
-				} else {
-					parentField = parentField.Elem()
-					if parentField.IsValid() {
-						fieldValue = parentField.FieldByName(col.fieldPath[1])
-					} else {
-						return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
-					}
-				}
+	level := len(col.fieldPath)
+	fieldValue = dataStruct.FieldByName(col.fieldPath[0])
+	for i := 0; i < level-1; i++ {
+		if !fieldValue.IsValid() {
+			break
+		}
+		if fieldValue.Kind() == reflect.Struct {
+			fieldValue = fieldValue.FieldByName(col.fieldPath[i+1])
+		} else if fieldValue.Kind() == reflect.Ptr {
+			if fieldValue.IsNil() {
+				fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
 			}
 			}
+			fieldValue = fieldValue.Elem().FieldByName(col.fieldPath[i+1])
 		} else {
 		} else {
-			// so we can use a different struct as conditions
-			fieldValue = dataStruct.FieldByName(col.fieldPath[1])
+			return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
 		}
 		}
-	} else {
-		return nil, fmt.Errorf("Unsupported mutliderive %v", col.FieldName)
 	}
 	}
 
 
 	if !fieldValue.IsValid() {
 	if !fieldValue.IsValid() {
-		return nil, errors.New("no find field matched")
+		return nil, fmt.Errorf("field  %v is not valid", col.FieldName)
 	}
 	}
 
 
 	return &fieldValue, nil
 	return &fieldValue, nil

+ 106 - 19
Godeps/_workspace/src/github.com/go-xorm/core/db.go

@@ -2,6 +2,7 @@ package core
 
 
 import (
 import (
 	"database/sql"
 	"database/sql"
+	"database/sql/driver"
 	"errors"
 	"errors"
 	"reflect"
 	"reflect"
 	"regexp"
 	"regexp"
@@ -29,10 +30,24 @@ func StructToSlice(query string, st interface{}) (string, []interface{}, error)
 	}
 	}
 
 
 	args := make([]interface{}, 0)
 	args := make([]interface{}, 0)
+	var err error
 	query = re.ReplaceAllStringFunc(query, func(src string) string {
 	query = re.ReplaceAllStringFunc(query, func(src string) string {
-		args = append(args, vv.Elem().FieldByName(src[1:]).Interface())
+		fv := vv.Elem().FieldByName(src[1:]).Interface()
+		if v, ok := fv.(driver.Valuer); ok {
+			var value driver.Value
+			value, err = v.Value()
+			if err != nil {
+				return "?"
+			}
+			args = append(args, value)
+		} else {
+			args = append(args, fv)
+		}
 		return "?"
 		return "?"
 	})
 	})
+	if err != nil {
+		return "", []interface{}{}, err
+	}
 	return query, args, nil
 	return query, args, nil
 }
 }
 
 
@@ -43,12 +58,25 @@ type DB struct {
 
 
 func Open(driverName, dataSourceName string) (*DB, error) {
 func Open(driverName, dataSourceName string) (*DB, error) {
 	db, err := sql.Open(driverName, dataSourceName)
 	db, err := sql.Open(driverName, dataSourceName)
-	return &DB{db, NewCacheMapper(&SnakeMapper{})}, err
+	if err != nil {
+		return nil, err
+	}
+	return &DB{db, NewCacheMapper(&SnakeMapper{})}, nil
+}
+
+func FromDB(db *sql.DB) *DB {
+	return &DB{db, NewCacheMapper(&SnakeMapper{})}
 }
 }
 
 
 func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
 func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
 	rows, err := db.DB.Query(query, args...)
 	rows, err := db.DB.Query(query, args...)
-	return &Rows{rows, db.Mapper}, err
+	if err != nil {
+		if rows != nil {
+			rows.Close()
+		}
+		return nil, err
+	}
+	return &Rows{rows, db.Mapper}, nil
 }
 }
 
 
 func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
 func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
@@ -68,28 +96,87 @@ func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) {
 }
 }
 
 
 type Row struct {
 type Row struct {
-	*sql.Row
+	rows *Rows
 	// One of these two will be non-nil:
 	// One of these two will be non-nil:
-	err    error // deferred error for easy chaining
-	Mapper IMapper
+	err error // deferred error for easy chaining
+}
+
+func (row *Row) Columns() ([]string, error) {
+	if row.err != nil {
+		return nil, row.err
+	}
+	return row.rows.Columns()
 }
 }
 
 
 func (row *Row) Scan(dest ...interface{}) error {
 func (row *Row) Scan(dest ...interface{}) error {
 	if row.err != nil {
 	if row.err != nil {
 		return row.err
 		return row.err
 	}
 	}
-	return row.Row.Scan(dest...)
+	defer row.rows.Close()
+
+	for _, dp := range dest {
+		if _, ok := dp.(*sql.RawBytes); ok {
+			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
+		}
+	}
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.Scan(dest...)
+	if err != nil {
+		return err
+	}
+	// Make sure the query can be processed to completion with no errors.
+	if err := row.rows.Close(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (row *Row) ScanStructByName(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	return row.rows.ScanStructByName(dest)
+}
+
+func (row *Row) ScanStructByIndex(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	return row.rows.ScanStructByIndex(dest)
+}
+
+// scan data to a slice's pointer, slice's length should equal to columns' number
+func (row *Row) ScanSlice(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	return row.rows.ScanSlice(dest)
+}
+
+// scan data to a map's pointer
+func (row *Row) ScanMap(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	return row.rows.ScanMap(dest)
 }
 }
 
 
 func (db *DB) QueryRow(query string, args ...interface{}) *Row {
 func (db *DB) QueryRow(query string, args ...interface{}) *Row {
-	row := db.DB.QueryRow(query, args...)
-	return &Row{row, nil, db.Mapper}
+	rows, err := db.Query(query, args...)
+	return &Row{rows, err}
 }
 }
 
 
 func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
 func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
 	query, args, err := MapToSlice(query, mp)
 	query, args, err := MapToSlice(query, mp)
 	if err != nil {
 	if err != nil {
-		return &Row{nil, err, db.Mapper}
+		return &Row{nil, err}
 	}
 	}
 	return db.QueryRow(query, args...)
 	return db.QueryRow(query, args...)
 }
 }
@@ -97,7 +184,7 @@ func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
 func (db *DB) QueryRowStruct(query string, st interface{}) *Row {
 func (db *DB) QueryRowStruct(query string, st interface{}) *Row {
 	query, args, err := StructToSlice(query, st)
 	query, args, err := StructToSlice(query, st)
 	if err != nil {
 	if err != nil {
-		return &Row{nil, err, db.Mapper}
+		return &Row{nil, err}
 	}
 	}
 	return db.QueryRow(query, args...)
 	return db.QueryRow(query, args...)
 }
 }
@@ -187,14 +274,14 @@ func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) {
 }
 }
 
 
 func (s *Stmt) QueryRow(args ...interface{}) *Row {
 func (s *Stmt) QueryRow(args ...interface{}) *Row {
-	row := s.Stmt.QueryRow(args...)
-	return &Row{row, nil, s.Mapper}
+	rows, err := s.Query(args...)
+	return &Row{rows, err}
 }
 }
 
 
 func (s *Stmt) QueryRowMap(mp interface{}) *Row {
 func (s *Stmt) QueryRowMap(mp interface{}) *Row {
 	vv := reflect.ValueOf(mp)
 	vv := reflect.ValueOf(mp)
 	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
 	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
-		return &Row{nil, errors.New("mp should be a map's pointer"), s.Mapper}
+		return &Row{nil, errors.New("mp should be a map's pointer")}
 	}
 	}
 
 
 	args := make([]interface{}, len(s.names))
 	args := make([]interface{}, len(s.names))
@@ -208,7 +295,7 @@ func (s *Stmt) QueryRowMap(mp interface{}) *Row {
 func (s *Stmt) QueryRowStruct(st interface{}) *Row {
 func (s *Stmt) QueryRowStruct(st interface{}) *Row {
 	vv := reflect.ValueOf(st)
 	vv := reflect.ValueOf(st)
 	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
 	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
-		return &Row{nil, errors.New("st should be a struct's pointer"), s.Mapper}
+		return &Row{nil, errors.New("st should be a struct's pointer")}
 	}
 	}
 
 
 	args := make([]interface{}, len(s.names))
 	args := make([]interface{}, len(s.names))
@@ -540,14 +627,14 @@ func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) {
 }
 }
 
 
 func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
 func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
-	row := tx.Tx.QueryRow(query, args...)
-	return &Row{row, nil, tx.Mapper}
+	rows, err := tx.Query(query, args...)
+	return &Row{rows, err}
 }
 }
 
 
 func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row {
 func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row {
 	query, args, err := MapToSlice(query, mp)
 	query, args, err := MapToSlice(query, mp)
 	if err != nil {
 	if err != nil {
-		return &Row{nil, err, tx.Mapper}
+		return &Row{nil, err}
 	}
 	}
 	return tx.QueryRow(query, args...)
 	return tx.QueryRow(query, args...)
 }
 }
@@ -555,7 +642,7 @@ func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row {
 func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row {
 func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row {
 	query, args, err := StructToSlice(query, st)
 	query, args, err := StructToSlice(query, st)
 	if err != nil {
 	if err != nil {
-		return &Row{nil, err, tx.Mapper}
+		return &Row{nil, err}
 	}
 	}
 	return tx.QueryRow(query, args...)
 	return tx.QueryRow(query, args...)
 }
 }

+ 4 - 4
Godeps/_workspace/src/github.com/go-xorm/core/db_test.go

@@ -24,7 +24,7 @@ type User struct {
 	Age      float32
 	Age      float32
 	Alias    string
 	Alias    string
 	NickName string
 	NickName string
-	Created  time.Time
+	Created  NullTime
 }
 }
 
 
 func init() {
 func init() {
@@ -85,7 +85,7 @@ func BenchmarkOriQuery(b *testing.B) {
 			var Id int64
 			var Id int64
 			var Name, Title, Alias, NickName string
 			var Name, Title, Alias, NickName string
 			var Age float32
 			var Age float32
-			var Created time.Time
+			var Created NullTime
 			err = rows.Scan(&Id, &Name, &Title, &Age, &Alias, &NickName, &Created)
 			err = rows.Scan(&Id, &Name, &Title, &Age, &Alias, &NickName, &Created)
 			if err != nil {
 			if err != nil {
 				b.Error(err)
 				b.Error(err)
@@ -600,7 +600,7 @@ func TestExecStruct(t *testing.T) {
 		Age:      1.2,
 		Age:      1.2,
 		Alias:    "lunny",
 		Alias:    "lunny",
 		NickName: "lunny xiao",
 		NickName: "lunny xiao",
-		Created:  time.Now(),
+		Created:  NullTime(time.Now()),
 	}
 	}
 
 
 	_, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) "+
 	_, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) "+
@@ -645,7 +645,7 @@ func BenchmarkExecStruct(b *testing.B) {
 		Age:      1.2,
 		Age:      1.2,
 		Alias:    "lunny",
 		Alias:    "lunny",
 		NickName: "lunny xiao",
 		NickName: "lunny xiao",
-		Created:  time.Now(),
+		Created:  NullTime(time.Now()),
 	}
 	}
 
 
 	for i := 0; i < b.N; i++ {
 	for i := 0; i < b.N; i++ {

+ 37 - 26
Godeps/_workspace/src/github.com/go-xorm/core/dialect.go

@@ -54,7 +54,7 @@ type Dialect interface {
 	IndexCheckSql(tableName, idxName string) (string, []interface{})
 	IndexCheckSql(tableName, idxName string) (string, []interface{})
 	TableCheckSql(tableName string) (string, []interface{})
 	TableCheckSql(tableName string) (string, []interface{})
 
 
-	IsColumnExist(tableName string, col *Column) (bool, error)
+	IsColumnExist(tableName string, colName string) (bool, error)
 
 
 	CreateTableSql(table *Table, tableName, storeEngine, charset string) string
 	CreateTableSql(table *Table, tableName, storeEngine, charset string) string
 	DropTableSql(tableName string) string
 	DropTableSql(tableName string) string
@@ -63,6 +63,8 @@ type Dialect interface {
 
 
 	ModifyColumnSql(tableName string, col *Column) string
 	ModifyColumnSql(tableName string, col *Column) string
 
 
+	ForUpdateSql(query string) string
+
 	//CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error
 	//CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error
 	//MustDropTable(tableName string) error
 	//MustDropTable(tableName string) error
 
 
@@ -164,10 +166,10 @@ func (db *Base) HasRecords(query string, args ...interface{}) (bool, error) {
 	return false, nil
 	return false, nil
 }
 }
 
 
-func (db *Base) IsColumnExist(tableName string, col *Column) (bool, error) {
+func (db *Base) IsColumnExist(tableName, colName string) (bool, error) {
 	query := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
 	query := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
 	query = strings.Replace(query, "`", db.dialect.QuoteStr(), -1)
 	query = strings.Replace(query, "`", db.dialect.QuoteStr(), -1)
-	return db.HasRecords(query, db.DbName, tableName, col.Name)
+	return db.HasRecords(query, db.DbName, tableName, colName)
 }
 }
 
 
 /*
 /*
@@ -229,28 +231,33 @@ func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset stri
 		tableName = table.Name
 		tableName = table.Name
 	}
 	}
 
 
-	sql += b.dialect.Quote(tableName) + " ("
-
-	pkList := table.PrimaryKeys
+	sql += b.dialect.Quote(tableName)
+	sql += " ("
+
+	if len(table.ColumnsSeq()) > 0 {
+		pkList := table.PrimaryKeys
+
+		for _, colName := range table.ColumnsSeq() {
+			col := table.GetColumn(colName)
+			if col.IsPrimaryKey && len(pkList) == 1 {
+				sql += col.String(b.dialect)
+			} else {
+				sql += col.StringNoPk(b.dialect)
+			}
+			sql = strings.TrimSpace(sql)
+			sql += ", "
+		}
 
 
-	for _, colName := range table.ColumnsSeq() {
-		col := table.GetColumn(colName)
-		if col.IsPrimaryKey && len(pkList) == 1 {
-			sql += col.String(b.dialect)
-		} else {
-			sql += col.StringNoPk(b.dialect)
+		if len(pkList) > 1 {
+			sql += "PRIMARY KEY ( "
+			sql += b.dialect.Quote(strings.Join(pkList, b.dialect.Quote(",")))
+			sql += " ), "
 		}
 		}
-		sql = strings.TrimSpace(sql)
-		sql += ", "
-	}
 
 
-	if len(pkList) > 1 {
-		sql += "PRIMARY KEY ( "
-		sql += b.dialect.Quote(strings.Join(pkList, b.dialect.Quote(",")))
-		sql += " ), "
+		sql = sql[:len(sql)-2]
 	}
 	}
+	sql += ")"
 
 
-	sql = sql[:len(sql)-2] + ")"
 	if b.dialect.SupportEngine() && storeEngine != "" {
 	if b.dialect.SupportEngine() && storeEngine != "" {
 		sql += " ENGINE=" + storeEngine
 		sql += " ENGINE=" + storeEngine
 	}
 	}
@@ -262,21 +269,25 @@ func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset stri
 			sql += " DEFAULT CHARSET " + charset
 			sql += " DEFAULT CHARSET " + charset
 		}
 		}
 	}
 	}
-	sql += ";"
+
 	return sql
 	return sql
 }
 }
 
 
+func (b *Base) ForUpdateSql(query string) string {
+	return query + " FOR UPDATE"
+}
+
 var (
 var (
-	dialects = map[DbType]Dialect{}
+	dialects = map[DbType]func() Dialect{}
 )
 )
 
 
-func RegisterDialect(dbName DbType, dialect Dialect) {
-	if dialect == nil {
+func RegisterDialect(dbName DbType, dialectFunc func() Dialect) {
+	if dialectFunc == nil {
 		panic("core: Register dialect is nil")
 		panic("core: Register dialect is nil")
 	}
 	}
-	dialects[dbName] = dialect // !nashtsai! allow override dialect
+	dialects[dbName] = dialectFunc // !nashtsai! allow override dialect
 }
 }
 
 
 func QueryDialect(dbName DbType) Dialect {
 func QueryDialect(dbName DbType) Dialect {
-	return dialects[dbName]
+	return dialects[dbName]()
 }
 }

+ 1 - 1
Godeps/_workspace/src/github.com/go-xorm/core/error.go

@@ -4,7 +4,7 @@ import "errors"
 
 
 var (
 var (
 	ErrNoMapPointer    = errors.New("mp should be a map's pointer")
 	ErrNoMapPointer    = errors.New("mp should be a map's pointer")
-	ErrNoStructPointer = errors.New("mp should be a map's pointer")
+	ErrNoStructPointer = errors.New("mp should be a struct's pointer")
 	//ErrNotExist        = errors.New("Not exist")
 	//ErrNotExist        = errors.New("Not exist")
 	//ErrIgnore = errors.New("Ignore")
 	//ErrIgnore = errors.New("Ignore")
 )
 )

+ 52 - 0
Godeps/_workspace/src/github.com/go-xorm/core/scan.go

@@ -0,0 +1,52 @@
+package core
+
+import (
+	"database/sql/driver"
+	"fmt"
+	"time"
+)
+
+type NullTime time.Time
+
+var (
+	_ driver.Valuer = NullTime{}
+)
+
+func (ns *NullTime) Scan(value interface{}) error {
+	if value == nil {
+		return nil
+	}
+	return convertTime(ns, value)
+}
+
+// Value implements the driver Valuer interface.
+func (ns NullTime) Value() (driver.Value, error) {
+	if (time.Time)(ns).IsZero() {
+		return nil, nil
+	}
+	return (time.Time)(ns).Format("2006-01-02 15:04:05"), nil
+}
+
+func convertTime(dest *NullTime, src interface{}) error {
+	// Common cases, without reflect.
+	switch s := src.(type) {
+	case string:
+		t, err := time.Parse("2006-01-02 15:04:05", s)
+		if err != nil {
+			return err
+		}
+		*dest = NullTime(t)
+		return nil
+	case []uint8:
+		t, err := time.Parse("2006-01-02 15:04:05", string(s))
+		if err != nil {
+			return err
+		}
+		*dest = NullTime(t)
+		return nil
+	case nil:
+	default:
+		return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
+	}
+	return nil
+}

+ 8 - 2
Godeps/_workspace/src/github.com/go-xorm/core/type.go

@@ -53,6 +53,10 @@ func (s *SQLType) IsNumeric() bool {
 	return s.IsType(NUMERIC_TYPE)
 	return s.IsType(NUMERIC_TYPE)
 }
 }
 
 
+func (s *SQLType) IsJson() bool {
+	return s.Name == Json
+}
+
 var (
 var (
 	Bit       = "BIT"
 	Bit       = "BIT"
 	TinyInt   = "TINYINT"
 	TinyInt   = "TINYINT"
@@ -101,6 +105,8 @@ var (
 	Serial    = "SERIAL"
 	Serial    = "SERIAL"
 	BigSerial = "BIGSERIAL"
 	BigSerial = "BIGSERIAL"
 
 
+	Json = "JSON"
+
 	SqlTypes = map[string]int{
 	SqlTypes = map[string]int{
 		Bit:       NUMERIC_TYPE,
 		Bit:       NUMERIC_TYPE,
 		TinyInt:   NUMERIC_TYPE,
 		TinyInt:   NUMERIC_TYPE,
@@ -112,6 +118,7 @@ var (
 
 
 		Enum: TEXT_TYPE,
 		Enum: TEXT_TYPE,
 		Set:  TEXT_TYPE,
 		Set:  TEXT_TYPE,
+		Json: TEXT_TYPE,
 
 
 		Char:       TEXT_TYPE,
 		Char:       TEXT_TYPE,
 		Varchar:    TEXT_TYPE,
 		Varchar:    TEXT_TYPE,
@@ -229,7 +236,6 @@ var (
 )
 )
 
 
 func Type2SQLType(t reflect.Type) (st SQLType) {
 func Type2SQLType(t reflect.Type) (st SQLType) {
-
 	switch k := t.Kind(); k {
 	switch k := t.Kind(); k {
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
 		st = SQLType{Int, 0, 0}
 		st = SQLType{Int, 0, 0}
@@ -252,7 +258,7 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
 	case reflect.String:
 	case reflect.String:
 		st = SQLType{Varchar, 255, 0}
 		st = SQLType{Varchar, 255, 0}
 	case reflect.Struct:
 	case reflect.Struct:
-		if t.ConvertibleTo(reflect.TypeOf(c_TIME_DEFAULT)) {
+		if t.ConvertibleTo(TimeType) {
 			st = SQLType{DateTime, 0, 0}
 			st = SQLType{DateTime, 0, 0}
 		} else {
 		} else {
 			// TODO need to handle association struct
 			// TODO need to handle association struct

+ 1 - 1
Godeps/_workspace/src/github.com/go-xorm/xorm/LICENSE

@@ -1,4 +1,4 @@
-Copyright (c) 2013 - 2014
+Copyright (c) 2013 - 2015 The Xorm Authors
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use in source and binary forms, with or without
 Redistribution and use in source and binary forms, with or without

+ 169 - 17
Godeps/_workspace/src/github.com/go-xorm/xorm/README.md

@@ -2,6 +2,8 @@
 
 
 Xorm is a simple and powerful ORM for Go.
 Xorm is a simple and powerful ORM for Go.
 
 
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
 [![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest)  [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lunny/xorm/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
 [![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest)  [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lunny/xorm/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
 
 
 # Features
 # Features
@@ -9,7 +11,7 @@ Xorm is a simple and powerful ORM for Go.
 * Struct <-> Table Mapping Support
 * Struct <-> Table Mapping Support
 
 
 * Chainable APIs
 * Chainable APIs
- 
+
 * Transaction Support
 * Transaction Support
 
 
 * Both ORM and raw SQL operation Support
 * Both ORM and raw SQL operation Support
@@ -33,38 +35,44 @@ Drivers for Go's sql package which currently support database/sql includes:
 
 
 * MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
 * MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
 
 
-* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
-
 * Postgres: [github.com/lib/pq](https://github.com/lib/pq)
 * Postgres: [github.com/lib/pq](https://github.com/lib/pq)
 
 
+* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
+
+* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
+
 * MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
 * MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
 
 
 * MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
 * MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
 
 
+* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
 
 
+* ql: [github.com/cznic/ql](https://github.com/cznic/ql) (experiment)
 
 
 # Changelog
 # Changelog
 
 
-* **v0.4.1**
-	Features:
-	* Add deleted xorm tag for soft delete and add unscoped
+* **v0.4.4**
+    * ql database expriment support
+    * tidb database expriment support
+    * sql.NullString and etc. field support
+    * select ForUpdate support
+    * many bugs fixed
 
 
-* **v0.4.0 RC1** 
-	Changes:
-	* moved xorm cmd to [github.com/go-xorm/cmd](github.com/go-xorm/cmd)
-	* refactored general DB operation a core lib at [github.com/go-xorm/core](https://github.com/go-xorm/core)
-	* moved tests to github.com/go-xorm/tests [github.com/go-xorm/tests](github.com/go-xorm/tests)
+* **v0.4.3**
+    * Json column type support
+    * oracle expirement support
+    * bug fixed
 
 
-	Improvements:
-	* Prepared statement cache
-	* Add Incr API
-	* Specify Timezone Location
+* **v0.4.2**
+	* Transaction will auto rollback if not Rollback or Commit be called.
+    * Gonic Mapper support
+    * bug fixed
 
 
-[More changelogs ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-15)
+[More changelogs ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
 
 
 # Installation
 # Installation
 
 
-If you have [gopm](https://github.com/gpmgo/gopm) installed, 
+If you have [gopm](https://github.com/gpmgo/gopm) installed,
 
 
 	gopm get github.com/go-xorm/xorm
 	gopm get github.com/go-xorm/xorm
 
 
@@ -80,8 +88,152 @@ Or
 
 
 * [GoWalker](http://gowalker.org/github.com/go-xorm/xorm)
 * [GoWalker](http://gowalker.org/github.com/go-xorm/xorm)
 
 
+# Quick Start
+
+* Create Engine
+
+```Go
+engine, err := xorm.NewEngine(driverName, dataSourceName)
+```
+
+* Define a struct and Sync2 table struct to database
+
+```Go
+type User struct {
+    Id int64
+    Name string
+    Salt string
+    Age int
+    Passwd string `xorm:"varchar(200)"`
+    Created time.Time `xorm:"created"`
+    Updated time.Time `xorm:"updated"`
+}
+
+err := engine.Sync2(new(User))
+```
+
+* Query a SQL string, the returned results is []map[string][]byte
+
+```Go
+results, err := engine.Query("select * from user")
+```
+
+* Execute a SQL string, the returned results
+
+```Go
+affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
+```
+
+* Insert one or multipe records to database
+
+```Go
+affected, err := engine.Insert(&user)
+// INSERT INTO struct () values ()
+affected, err := engine.Insert(&user1, &user2)
+// INSERT INTO struct1 () values ()
+// INSERT INTO struct2 () values ()
+affected, err := engine.Insert(&users)
+// INSERT INTO struct () values (),(),()
+affected, err := engine.Insert(&user1, &users)
+// INSERT INTO struct1 () values ()
+// INSERT INTO struct2 () values (),(),()
+```
+
+* Query one record from database
+
+```Go
+has, err := engine.Get(&user)
+// SELECT * FROM user LIMIT 1
+has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
+// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
+```
+
+* Query multiple records from database, also you can use join and extends
+
+```Go
+var users []User
+err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
+// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10
+
+type Detail struct {
+    Id int64
+    UserId int64 `xorm:"index"`
+}
+
+type UserDetail struct {
+    User `xorm:"extends"`
+    Detail `xorm:"extends"`
+}
+
+var users []UserDetail
+err := engine.Table("user").Select("user.*, detail.*")
+    Join("INNER", "detail", "detail.user_id = user.id").
+    Where("user.name = ?", name).Limit(10, 0).
+    Find(&users)
+// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10
+```
+
+* Query multiple records and record by record handle, there two methods Iterate and Rows
+
+```Go
+err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
+    user := bean.(*User)
+    return nil
+})
+// SELECT * FROM user
+
+rows, err := engine.Rows(&User{Name:name})
+// SELECT * FROM user
+defer rows.Close()
+bean := new(Struct)
+for rows.Next() {
+    err = rows.Scan(bean)
+}
+```
+
+* Update one or more records, default will update non-empty and non-zero fields except to use Cols, AllCols and etc.
+
+```Go
+affected, err := engine.Id(1).Update(&user)
+// UPDATE user SET ... Where id = ?
+
+affected, err := engine.Update(&user, &User{Name:name})
+// UPDATE user SET ... Where name = ?
+
+var ids = []int64{1, 2, 3}
+affected, err := engine.In(ids).Update(&user)
+// UPDATE user SET ... Where id IN (?, ?, ?)
+
+// force update indicated columns by Cols
+affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12})
+// UPDATE user SET age = ?, updated=? Where id = ?
+
+// force NOT update indicated columns by Omit
+affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12})
+// UPDATE user SET age = ?, updated=? Where id = ?
+
+affected, err := engine.Id(1).AllCols().Update(&user)
+// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
+```
+
+* Delete one or more records, Delete MUST has conditon
+
+```Go
+affected, err := engine.Where(...).Delete(&user)
+// DELETE FROM user Where ...
+```
+
+* Count records
+
+```Go
+counts, err := engine.Count(&user)
+// SELECT count(*) AS total FROM user
+```
+
 # Cases
 # Cases
 
 
+* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
+
 * [Wego](http://github.com/go-tango/wego)
 * [Wego](http://github.com/go-tango/wego)
 
 
 * [Docker.cn](https://docker.cn/)
 * [Docker.cn](https://docker.cn/)

+ 169 - 11
Godeps/_workspace/src/github.com/go-xorm/xorm/README_CN.md

@@ -4,6 +4,8 @@
 
 
 xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
 xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
 
 
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
 [![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest)  [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm)
 [![Build Status](https://drone.io/github.com/go-xorm/tests/status.png)](https://drone.io/github.com/go-xorm/tests/latest)  [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/go-xorm/xorm)
 
 
 ## 特性
 ## 特性
@@ -18,7 +20,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
 
 
 * 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件
 * 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件
 
 
-* 支持级联加载Struct 
+* 支持级联加载Struct
 
 
 * 支持缓存
 * 支持缓存
 
 
@@ -34,29 +36,42 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
 
 
 * MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
 * MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
 
 
-* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
-
 * Postgres: [github.com/lib/pq](https://github.com/lib/pq)
 * Postgres: [github.com/lib/pq](https://github.com/lib/pq)
 
 
+* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
+
+* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
+
 * MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
 * MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
 
 
 * MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
 * MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
 
 
+* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
+
+* ql: [github.com/cznic/ql](https://github.com/cznic/ql) (试验性支持)
+
 ## 更新日志
 ## 更新日志
 
 
-* **v0.4.2**
-	新特性:
-	* deleted标记
-	* bug fixed
+* **v0.4.4**
+    * Tidb 数据库支持
+    * QL 试验性支持
+    * sql.NullString支持
+    * ForUpdate 支持
+    * bug修正
+
+* **v0.4.3**
+    * Json 字段类型支持
+    * oracle实验性支持
+    * bug修正
 
 
 [更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
 [更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
 
 
 ## 安装
 ## 安装
 
 
-推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装: 
+推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
 
 
 	gopm get github.com/go-xorm/xorm
 	gopm get github.com/go-xorm/xorm
-	
+
 或者您也可以使用go工具进行安装:
 或者您也可以使用go工具进行安装:
 
 
 	go get github.com/go-xorm/xorm
 	go get github.com/go-xorm/xorm
@@ -69,8 +84,151 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
 
 
 * [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm)
 * [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm)
 
 
-
-## 案例
+# 快速开始
+
+* 第一步创建引擎,driverName, dataSourceName和database/sql接口相同
+
+```Go
+engine, err := xorm.NewEngine(driverName, dataSourceName)
+```
+
+* 定义一个和表同步的结构体,并且自动同步结构体到数据库
+
+```Go
+type User struct {
+    Id int64
+    Name string
+    Salt string
+    Age int
+    Passwd string `xorm:"varchar(200)"`
+    Created time.Time `xorm:"created"`
+    Updated time.Time `xorm:"updated"`
+}
+
+err := engine.Sync2(new(User))
+```
+
+* 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte
+
+```Go
+results, err := engine.Query("select * from user")
+```
+
+* 执行一个SQL语句
+
+```Go
+affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
+```
+
+* 插入一条或者多条记录
+
+```Go
+affected, err := engine.Insert(&user)
+// INSERT INTO struct () values ()
+affected, err := engine.Insert(&user1, &user2)
+// INSERT INTO struct1 () values ()
+// INSERT INTO struct2 () values ()
+affected, err := engine.Insert(&users)
+// INSERT INTO struct () values (),(),()
+affected, err := engine.Insert(&user1, &users)
+// INSERT INTO struct1 () values ()
+// INSERT INTO struct2 () values (),(),()
+```
+
+* 查询单条记录
+
+```Go
+has, err := engine.Get(&user)
+// SELECT * FROM user LIMIT 1
+has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
+// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
+```
+
+* 查询多条记录,当然可以使用Join和extends来组合使用
+
+```Go
+var users []User
+err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
+// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10
+
+type Detail struct {
+    Id int64
+    UserId int64 `xorm:"index"`
+}
+
+type UserDetail struct {
+    User `xorm:"extends"`
+    Detail `xorm:"extends"`
+}
+
+var users []UserDetail
+err := engine.Table("user").Select("user.*, detail.*")
+    Join("INNER", "detail", "detail.user_id = user.id").
+    Where("user.name = ?", name).Limit(10, 0).
+    Find(&users)
+// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10
+```
+
+* 根据条件遍历数据库,可以有两种方式: Iterate and Rows
+
+```Go
+err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
+    user := bean.(*User)
+    return nil
+})
+// SELECT * FROM user
+
+rows, err := engine.Rows(&User{Name:name})
+// SELECT * FROM user
+defer rows.Close()
+bean := new(Struct)
+for rows.Next() {
+    err = rows.Scan(bean)
+}
+```
+
+* 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段
+
+```Go
+affected, err := engine.Id(1).Update(&user)
+// UPDATE user SET ... Where id = ?
+
+affected, err := engine.Update(&user, &User{Name:name})
+// UPDATE user SET ... Where name = ?
+
+var ids = []int64{1, 2, 3}
+affected, err := engine.In(ids).Update(&user)
+// UPDATE user SET ... Where id IN (?, ?, ?)
+
+// force update indicated columns by Cols
+affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12})
+// UPDATE user SET age = ?, updated=? Where id = ?
+
+// force NOT update indicated columns by Omit
+affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12})
+// UPDATE user SET age = ?, updated=? Where id = ?
+
+affected, err := engine.Id(1).AllCols().Update(&user)
+// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
+```
+
+* 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable
+
+```Go
+affected, err := engine.Where(...).Delete(&user)
+// DELETE FROM user Where ...
+```
+
+* 获取记录条数
+
+```Go
+counts, err := engine.Count(&user)
+// SELECT count(*) AS total FROM user
+```
+
+# 案例
+
+* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
 
 
 * [Wego](http://github.com/go-tango/wego)
 * [Wego](http://github.com/go-tango/wego)
 
 

+ 1 - 1
Godeps/_workspace/src/github.com/go-xorm/xorm/VERSION

@@ -1 +1 @@
-xorm v0.4.2.0225
+xorm v0.4.5.0204

+ 1 - 1
Godeps/_workspace/src/github.com/go-xorm/xorm/doc.go

@@ -1,4 +1,4 @@
-// Copyright 2013 - 2014 The XORM Authors. All rights reserved.
+// Copyright 2013 - 2015 The Xorm Authors. All rights reserved.
 // Use of this source code is governed by a BSD
 // Use of this source code is governed by a BSD
 // license that can be found in the LICENSE file.
 // license that can be found in the LICENSE file.
 
 

+ 94 - 43
Godeps/_workspace/src/github.com/go-xorm/xorm/engine.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -316,6 +320,12 @@ func (engine *Engine) NoAutoTime() *Session {
 	return session.NoAutoTime()
 	return session.NoAutoTime()
 }
 }
 
 
+func (engine *Engine) NoAutoCondition(no ...bool) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.NoAutoCondition(no...)
+}
+
 // Retrieve all tables, columns, indexes' informations from database.
 // 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()
@@ -373,13 +383,25 @@ func (engine *Engine) DumpAll(w io.Writer) error {
 		return err
 		return err
 	}
 	}
 
 
-	for _, table := range tables {
-		_, err = io.WriteString(w, engine.dialect.CreateTableSql(table, "", table.StoreEngine, "")+"\n\n")
+	_, 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, engine.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, engine.dialect.CreateIndexSql(table.Name, index)+";\n")
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
@@ -439,7 +461,7 @@ 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 {
 			if err != nil {
 				return err
 				return err
 			}
 			}
@@ -506,6 +528,12 @@ func (engine *Engine) Distinct(columns ...string) *Session {
 	return session.Distinct(columns...)
 	return session.Distinct(columns...)
 }
 }
 
 
+func (engine *Engine) Select(str string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Select(str)
+}
+
 // only use the paramters as select or update columns
 // only use the paramters as select or update columns
 func (engine *Engine) Cols(columns ...string) *Session {
 func (engine *Engine) Cols(columns ...string) *Session {
 	session := engine.NewSession()
 	session := engine.NewSession()
@@ -543,6 +571,13 @@ func (engine *Engine) Omit(columns ...string) *Session {
 	return session.Omit(columns...)
 	return session.Omit(columns...)
 }
 }
 
 
+// Set null when column is zero-value and nullable for update
+func (engine *Engine) Nullable(columns ...string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Nullable(columns...)
+}
+
 // This method will generate "column IN (?, ?)"
 // This method will generate "column IN (?, ?)"
 func (engine *Engine) In(column string, args ...interface{}) *Session {
 func (engine *Engine) In(column string, args ...interface{}) *Session {
 	session := engine.NewSession()
 	session := engine.NewSession()
@@ -642,20 +677,20 @@ func (engine *Engine) Having(conditions string) *Session {
 
 
 func (engine *Engine) autoMapType(v reflect.Value) *core.Table {
 func (engine *Engine) autoMapType(v reflect.Value) *core.Table {
 	t := v.Type()
 	t := v.Type()
-	engine.mutex.RLock()
+	engine.mutex.Lock()
 	table, ok := engine.Tables[t]
 	table, ok := engine.Tables[t]
-	engine.mutex.RUnlock()
 	if !ok {
 	if !ok {
 		table = engine.mapType(v)
 		table = engine.mapType(v)
-		engine.mutex.Lock()
 		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()
 	return table
 	return table
 }
 }
 
 
@@ -691,33 +726,24 @@ 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 v.CanAddr() {
-			method = v.Addr().MethodByName("TableName")
-		}
-	}
-	if method.IsValid() {
-		params := []reflect.Value{}
-		results := method.Call(params)
-		if len(results) == 1 {
-			table.Name = results[0].Interface().(string)
-		}
-	}
-
-	if table.Name == "" {
+	if tb, ok := v.Interface().(TableName); ok {
+		table.Name = tb.TableName()
+	} else {
 		table.Name = engine.TableMapper.Obj2Table(t.Name())
 		table.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
@@ -730,7 +756,7 @@ 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] == "-" {
@@ -804,6 +830,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.LogError(err)
+						}
 					case k == "UPDATED":
 					case k == "UPDATED":
 						col.IsUpdated = true
 						col.IsUpdated = true
 					case k == "DELETED":
 					case k == "DELETED":
@@ -1112,7 +1148,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()
-				isExist, err := session.Engine.dialect.IsColumnExist(table.Name, col)
+				isExist, err := session.Engine.dialect.IsColumnExist(table.Name, col.Name)
 				if err != nil {
 				if err != nil {
 					return err
 					return err
 				}
 				}
@@ -1387,7 +1423,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)
 	}
 	}
@@ -1405,35 +1440,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
 }
 }

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/error.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

BIN
Godeps/_workspace/src/github.com/go-xorm/xorm/examples/goroutine.db-journal


+ 2 - 2
Godeps/_workspace/src/github.com/go-xorm/xorm/examples/goroutine.go

@@ -33,7 +33,7 @@ func test(engine *xorm.Engine) {
 		return
 		return
 	}
 	}
 
 
-	size := 500
+	size := 100
 	queue := make(chan int, size)
 	queue := make(chan int, size)
 
 
 	for i := 0; i < size; i++ {
 	for i := 0; i < size; i++ {
@@ -83,7 +83,7 @@ func test(engine *xorm.Engine) {
 }
 }
 
 
 func main() {
 func main() {
-	runtime.GOMAXPROCS(1)
+	runtime.GOMAXPROCS(2)
 	fmt.Println("-----start sqlite go routines-----")
 	fmt.Println("-----start sqlite go routines-----")
 	engine, err := sqliteEngine()
 	engine, err := sqliteEngine()
 	if err != nil {
 	if err != nil {

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/goracle_driver.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 71 - 2
Godeps/_workspace/src/github.com/go-xorm/xorm/helpers.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -11,6 +15,30 @@ import (
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/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:
@@ -33,12 +61,41 @@ func isZero(k interface{}) bool {
 		return k.(uint32) == 0
 		return k.(uint32) == 0
 	case uint64:
 	case uint64:
 		return k.(uint64) == 0
 		return k.(uint64) == 0
+	case float32:
+		return k.(float32) == 0
+	case float64:
+		return k.(float64) == 0
+	case bool:
+		return k.(bool) == false
 	case string:
 	case string:
 		return k.(string) == ""
 		return k.(string) == ""
+	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) {
@@ -48,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))
 }
 }
@@ -129,8 +190,8 @@ func reflect2value(rawValue *reflect.Value) (str string, err error) {
 		}
 		}
 	//时间类型
 	//时间类型
 	case reflect.Struct:
 	case reflect.Struct:
-		if aa == core.TimeType {
-			str = rawValue.Interface().(time.Time).Format(time.RFC3339Nano)
+		if aa.ConvertibleTo(core.TimeType) {
+			str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
 		} else {
 		} else {
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 		}
 		}
@@ -352,6 +413,14 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
 			}
 			}
 		}
 		}
 
 
+		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
+		if _, ok := session.Statement.nullableMap[lColName]; ok {
+			if col.Nullable && isZero(fieldValue.Interface()) {
+				var nilValue *int
+				fieldValue = reflect.ValueOf(nilValue)
+			}
+		}
+
 		if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
 		if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
 			val, t := session.Engine.NowTime2(col.SQLType.Name)
 			val, t := session.Engine.NowTime2(col.SQLType.Name)
 			args = append(args, val)
 			args = append(args, val)

+ 22 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/helpers_test.go

@@ -0,0 +1,22 @@
+package xorm
+
+import "testing"
+
+func TestSplitTag(t *testing.T) {
+	var cases = []struct {
+		tag  string
+		tags []string
+	}{
+		{"not null default '2000-01-01 00:00:00' TIMESTAMP", []string{"not", "null", "default", "'2000-01-01 00:00:00'", "TIMESTAMP"}},
+		{"TEXT", []string{"TEXT"}},
+		{"default('2000-01-01 00:00:00')", []string{"default('2000-01-01 00:00:00')"}},
+		{"json  binary", []string{"json", "binary"}},
+	}
+
+	for _, kase := range cases {
+		tags := splitTag(kase.tag)
+		if !sliceEq(tags, kase.tags) {
+			t.Fatalf("[%d]%v is not equal [%d]%v", len(tags), tags, len(kase.tags), kase.tags)
+		}
+	}
+}

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/logger.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 4 - 1
Godeps/_workspace/src/github.com/go-xorm/xorm/lru_cacher.go

@@ -1,4 +1,7 @@
-//LRUCacher implements Cacher according to LRU algorithm
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 4 - 1
Godeps/_workspace/src/github.com/go-xorm/xorm/memroy_store.go → Godeps/_workspace/src/github.com/go-xorm/xorm/memory_store.go

@@ -1,4 +1,7 @@
-// MemoryStore implements CacheStore provide local machine
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 16 - 3
Godeps/_workspace/src/github.com/go-xorm/xorm/mssql_dialect.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -216,6 +220,11 @@ func (db *mssql) SqlType(c *core.Column) string {
 	switch t := c.SQLType.Name; t {
 	switch t := c.SQLType.Name; t {
 	case core.Bool:
 	case core.Bool:
 		res = core.TinyInt
 		res = core.TinyInt
+		if c.Default == "true" {
+			c.Default = "1"
+		} else if c.Default == "false" {
+			c.Default = "0"
+		}
 	case core.Serial:
 	case core.Serial:
 		c.IsAutoIncrement = true
 		c.IsAutoIncrement = true
 		c.IsPrimaryKey = true
 		c.IsPrimaryKey = true
@@ -238,7 +247,7 @@ func (db *mssql) SqlType(c *core.Column) string {
 		c.Length = 7
 		c.Length = 7
 	case core.MediumInt:
 	case core.MediumInt:
 		res = core.Int
 		res = core.Int
-	case core.MediumText, core.TinyText, core.LongText:
+	case core.MediumText, core.TinyText, core.LongText, core.Json:
 		res = core.Text
 		res = core.Text
 	case core.Double:
 	case core.Double:
 		res = core.Real
 		res = core.Real
@@ -311,10 +320,10 @@ func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}
 	return sql, args
 	return sql, args
 }*/
 }*/
 
 
-func (db *mssql) IsColumnExist(tableName string, col *core.Column) (bool, error) {
+func (db *mssql) IsColumnExist(tableName, colName string) (bool, error) {
 	query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
 	query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
 
 
-	return db.HasRecords(query, tableName, col.Name)
+	return db.HasRecords(query, tableName, colName)
 }
 }
 
 
 func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
 func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
@@ -500,6 +509,10 @@ func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
 	return sql
 	return sql
 }
 }
 
 
+func (db *mssql) ForUpdateSql(query string) string {
+	return query
+}
+
 func (db *mssql) Filters() []core.Filter {
 func (db *mssql) Filters() []core.Filter {
 	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
 	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
 }
 }

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/mymysql_driver.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 6 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/mysql_dialect.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -221,6 +225,8 @@ func (db *mysql) SqlType(c *core.Column) string {
 	case core.Uuid:
 	case core.Uuid:
 		res = core.Varchar
 		res = core.Varchar
 		c.Length = 40
 		c.Length = 40
+	case core.Json:
+		res = core.Text
 	default:
 	default:
 		res = t
 		res = t
 	}
 	}

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/mysql_driver.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/oci8_driver.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/odbc_driver.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 9 - 3
Godeps/_workspace/src/github.com/go-xorm/xorm/oracle_dialect.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -518,7 +522,7 @@ func (db *oracle) SqlType(c *core.Column) string {
 		res = "TIMESTAMP WITH TIME ZONE"
 		res = "TIMESTAMP WITH TIME ZONE"
 	case core.Float, core.Double, core.Numeric, core.Decimal:
 	case core.Float, core.Double, core.Numeric, core.Decimal:
 		res = "NUMBER"
 		res = "NUMBER"
-	case core.Text, core.MediumText, core.LongText:
+	case core.Text, core.MediumText, core.LongText, core.Json:
 		res = "CLOB"
 		res = "CLOB"
 	case core.Char, core.Varchar, core.TinyText:
 	case core.Char, core.Varchar, core.TinyText:
 		res = "VARCHAR2"
 		res = "VARCHAR2"
@@ -661,8 +665,8 @@ func (db *oracle) MustDropTable(tableName string) error {
 		" AND column_name = ?", args
 		" AND column_name = ?", args
 }*/
 }*/
 
 
-func (db *oracle) IsColumnExist(tableName string, col *core.Column) (bool, error) {
-	args := []interface{}{tableName, col.Name}
+func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
+	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"
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
@@ -740,6 +744,8 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Colum
 		switch dt {
 		switch dt {
 		case "VARCHAR2":
 		case "VARCHAR2":
 			col.SQLType = core.SQLType{core.Varchar, len1, len2}
 			col.SQLType = core.SQLType{core.Varchar, len1, len2}
+		case "NVARCHAR2":
+			col.SQLType = core.SQLType{core.NVarchar, len1, len2}
 		case "TIMESTAMP WITH TIME ZONE":
 		case "TIMESTAMP WITH TIME ZONE":
 			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
 			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
 		case "NUMBER":
 		case "NUMBER":

+ 9 - 4
Godeps/_workspace/src/github.com/go-xorm/xorm/postgres_dialect.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -892,8 +896,8 @@ func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
 	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
 	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
 }
 }
 
 
-func (db *postgres) IsColumnExist(tableName string, col *core.Column) (bool, error) {
-	args := []interface{}{tableName, col.Name}
+func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
+	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"
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
@@ -909,7 +913,8 @@ func (db *postgres) IsColumnExist(tableName string, col *core.Column) (bool, err
 }
 }
 
 
 func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
-	args := []interface{}{tableName}
+	pgSchema := "public"
+	args := []interface{}{tableName,pgSchema}
 	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
@@ -920,7 +925,7 @@ FROM pg_attribute f
     LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
     LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
     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 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;`
 
 
 	rows, err := db.DB().Query(s, args...)
 	rows, err := db.DB().Query(s, args...)
 	if db.Logger != nil {
 	if db.Logger != nil {

+ 6 - 2
Godeps/_workspace/src/github.com/go-xorm/xorm/pq_driver.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -37,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)
 	}
 	}
 
 
@@ -99,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

+ 8 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/processors.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 // Executed before an object is initially persisted to the database
 // Executed before an object is initially persisted to the database
@@ -19,6 +23,10 @@ type BeforeSetProcessor interface {
 	BeforeSet(string, Cell)
 	BeforeSet(string, Cell)
 }
 }
 
 
+type AfterSetProcessor interface {
+	AfterSet(string, Cell)
+}
+
 // !nashtsai! TODO enable BeforeValidateProcessor when xorm start to support validations
 // !nashtsai! TODO enable BeforeValidateProcessor when xorm start to support validations
 //// Executed before an object is validated
 //// Executed before an object is validated
 //type BeforeValidateProcessor interface {
 //type BeforeValidateProcessor interface {

+ 5 - 1
Godeps/_workspace/src/github.com/go-xorm/xorm/rows.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -41,7 +45,7 @@ func newRows(session *Session, bean interface{}) (*Rows, error) {
 		sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable)
 		sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable)
 	}
 	}
 
 
-	rows.session.Engine.logSQL(sqlStr, args)
+	rows.session.saveLastSQL(sqlStr, args)
 	var err error
 	var err error
 	rows.stmt, err = rows.session.DB().Prepare(sqlStr)
 	rows.stmt, err = rows.session.DB().Prepare(sqlStr)
 	if err != nil {
 	if err != nil {

Файловите разлики са ограничени, защото са твърде много
+ 380 - 212
Godeps/_workspace/src/github.com/go-xorm/xorm/session.go


+ 25 - 5
Godeps/_workspace/src/github.com/go-xorm/xorm/sqlite3_dialect.go

@@ -1,9 +1,14 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
 	"database/sql"
 	"database/sql"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"regexp"
 	"strings"
 	"strings"
 
 
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/core"
@@ -152,13 +157,21 @@ func (db *sqlite3) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName st
 
 
 func (db *sqlite3) SqlType(c *core.Column) string {
 func (db *sqlite3) SqlType(c *core.Column) string {
 	switch t := c.SQLType.Name; t {
 	switch t := c.SQLType.Name; t {
+	case core.Bool:
+		if c.Default == "true" {
+			c.Default = "1"
+		} else if c.Default == "false" {
+			c.Default = "0"
+		}
+		return core.Integer
 	case core.Date, core.DateTime, core.TimeStamp, core.Time:
 	case core.Date, core.DateTime, core.TimeStamp, core.Time:
 		return core.DateTime
 		return core.DateTime
 	case core.TimeStampz:
 	case core.TimeStampz:
 		return core.Text
 		return core.Text
-	case core.Char, core.Varchar, core.NVarchar, core.TinyText, core.Text, core.MediumText, core.LongText:
+	case core.Char, core.Varchar, core.NVarchar, core.TinyText,
+		core.Text, core.MediumText, core.LongText, core.Json:
 		return core.Text
 		return core.Text
-	case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool:
+	case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt:
 		return core.Integer
 		return core.Integer
 	case core.Float, core.Double, core.Real:
 	case core.Float, core.Double, core.Real:
 		return core.Real
 		return core.Real
@@ -238,15 +251,19 @@ func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
 	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
 	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
 }
 }
 
 
+func (db *sqlite3) ForUpdateSql(query string) string {
+	return query
+}
+
 /*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
 /*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
 	args := []interface{}{tableName}
 	args := []interface{}{tableName}
 	sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
 	sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
 	return sql, args
 	return sql, args
 }*/
 }*/
 
 
-func (db *sqlite3) IsColumnExist(tableName string, col *core.Column) (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 '%`" + col.Name + "`%') or (sql like '%[" + col.Name + "]%'))"
+	query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
 	rows, err := db.DB().Query(query, args...)
 	rows, err := db.DB().Query(query, args...)
 	if db.Logger != nil {
 	if db.Logger != nil {
 		db.Logger.Info("[sql]", query, args)
 		db.Logger.Info("[sql]", query, args)
@@ -290,10 +307,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)

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/sqlite3_driver.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (

+ 318 - 309
Godeps/_workspace/src/github.com/go-xorm/xorm/statement.go

@@ -1,6 +1,12 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
+	"bytes"
+	"database/sql/driver"
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
@@ -33,42 +39,46 @@ type exprParam struct {
 
 
 // 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
-	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
-	TableAlias    string
-	allUseBool    bool
-	checkVersion  bool
-	unscoped      bool
-	mustColumnMap 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
+	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
@@ -94,11 +104,15 @@ 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.TableAlias = ""
 	statement.TableAlias = ""
+	statement.selectStr = ""
 	statement.allUseBool = false
 	statement.allUseBool = false
 	statement.useAllCols = false
 	statement.useAllCols = false
 	statement.mustColumnMap = make(map[string]bool)
 	statement.mustColumnMap = make(map[string]bool)
+	statement.nullableMap = make(map[string]bool)
 	statement.checkVersion = true
 	statement.checkVersion = true
 	statement.unscoped = false
 	statement.unscoped = false
 	statement.inColumns = make(map[string]*inParam)
 	statement.inColumns = make(map[string]*inParam)
@@ -107,20 +121,29 @@ 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 {
 	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)
@@ -130,11 +153,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
 	}
 	}
@@ -142,11 +167,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
 	}
 	}
@@ -154,7 +181,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()
@@ -166,127 +193,12 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
 	return statement
 	return statement
 }
 }
 
 
-/*func (statement *Statement) genFields(bean interface{}) map[string]interface{} {
-    results := make(map[string]interface{})
-    table := statement.Engine.TableInfo(bean)
-    for _, col := range table.Columns {
-        fieldValue := col.ValueOf(bean)
-        fieldType := reflect.TypeOf(fieldValue.Interface())
-        var val interface{}
-        switch fieldType.Kind() {
-        case reflect.Bool:
-            if allUseBool {
-                val = fieldValue.Interface()
-            } else if _, ok := boolColumnMap[col.Name]; ok {
-                val = fieldValue.Interface()
-            } else {
-                // if a bool in a struct, it will not be as a condition because it default is false,
-                // please use Where() instead
-                continue
-            }
-        case reflect.String:
-            if fieldValue.String() == "" {
-                continue
-            }
-            // for MyString, should convert to string or panic
-            if fieldType.String() != reflect.String.String() {
-                val = fieldValue.String()
-            } else {
-                val = fieldValue.Interface()
-            }
-        case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
-            if fieldValue.Int() == 0 {
-                continue
-            }
-            val = fieldValue.Interface()
-        case reflect.Float32, reflect.Float64:
-            if fieldValue.Float() == 0.0 {
-                continue
-            }
-            val = fieldValue.Interface()
-        case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
-            if fieldValue.Uint() == 0 {
-                continue
-            }
-            val = fieldValue.Interface()
-        case reflect.Struct:
-            if fieldType == reflect.TypeOf(time.Now()) {
-                t := fieldValue.Interface().(time.Time)
-                if t.IsZero() || !fieldValue.IsValid() {
-                    continue
-                }
-                var str string
-                if col.SQLType.Name == Time {
-                    s := t.UTC().Format("2006-01-02 15:04:05")
-                    val = s[11:19]
-                } else if col.SQLType.Name == Date {
-                    str = t.Format("2006-01-02")
-                    val = str
-                } else {
-                    val = t
-                }
-            } else {
-                engine.autoMapType(fieldValue.Type())
-                if table, ok := engine.Tables[fieldValue.Type()]; ok {
-                    pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumn().FieldName)
-                    if pkField.Int() != 0 {
-                        val = pkField.Interface()
-                    } else {
-                        continue
-                    }
-                } else {
-                    val = fieldValue.Interface()
-                }
-            }
-        case reflect.Array, reflect.Slice, reflect.Map:
-            if fieldValue == reflect.Zero(fieldType) {
-                continue
-            }
-            if fieldValue.IsNil() || !fieldValue.IsValid() {
-                continue
-            }
-
-            if col.SQLType.IsText() {
-                bytes, err := json.Marshal(fieldValue.Interface())
-                if err != nil {
-                    engine.LogError(err)
-                    continue
-                }
-                val = string(bytes)
-            } else if col.SQLType.IsBlob() {
-                var bytes []byte
-                var err error
-                if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
-                    fieldType.Elem().Kind() == reflect.Uint8 {
-                    if fieldValue.Len() > 0 {
-                        val = fieldValue.Bytes()
-                    } else {
-                        continue
-                    }
-                } else {
-                    bytes, err = json.Marshal(fieldValue.Interface())
-                    if err != nil {
-                        engine.LogError(err)
-                        continue
-                    }
-                    val = bytes
-                }
-            } else {
-                continue
-            }
-        default:
-            val = fieldValue.Interface()
-        }
-        results[col.Name] = val
-    }
-    return results
-}*/
-
-// 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, columnMap map[string]bool, update bool) ([]string, []interface{}) {
+	mustColumnMap map[string]bool, nullableMap map[string]bool,
+	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)
@@ -303,17 +215,13 @@ 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.LogError(err)
@@ -325,7 +233,9 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 
 
 		requiredField := useAllCols
 		requiredField := useAllCols
 		includeNil := useAllCols
 		includeNil := useAllCols
-		if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok {
+		lColName := strings.ToLower(col.Name)
+
+		if b, ok := mustColumnMap[lColName]; ok {
 			if b {
 			if b {
 				requiredField = true
 				requiredField = true
 			} else {
 			} else {
@@ -333,6 +243,16 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 			}
 			}
 		}
 		}
 
 
+		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
+		if b, ok := nullableMap[lColName]; ok {
+			if b && col.Nullable && isZero(fieldValue.Interface()) {
+				var nilValue *int
+				fieldValue = reflect.ValueOf(nilValue)
+				fieldType = reflect.TypeOf(fieldValue.Interface())
+				includeNil = true
+			}
+		}
+
 		var val interface{}
 		var val interface{}
 
 
 		if fieldValue.CanAddr() {
 		if fieldValue.CanAddr() {
@@ -410,38 +330,53 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 			t := int64(fieldValue.Uint())
 			t := int64(fieldValue.Uint())
 			val = reflect.ValueOf(&t).Interface()
 			val = reflect.ValueOf(&t).Interface()
 		case reflect.Struct:
 		case reflect.Struct:
-			if fieldType == reflect.TypeOf(time.Now()) {
-				t := fieldValue.Interface().(time.Time)
+			if fieldType.ConvertibleTo(core.TimeType) {
+				t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
 				if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
 				if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
 					continue
 					continue
 				}
 				}
 				val = engine.FormatTime(col.SQLType.Name, t)
 				val = engine.FormatTime(col.SQLType.Name, t)
+			} else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok {
+				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() {
@@ -492,8 +427,7 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
 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) ([]string, []interface{}) {
-
+	mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) ([]string, []interface{}) {
 	colNames := make([]string, 0)
 	colNames := make([]string, 0)
 	var args = make([]interface{}, 0)
 	var args = make([]interface{}, 0)
 	for _, col := range table.Columns() {
 	for _, col := range table.Columns() {
@@ -510,6 +444,21 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 		if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
 		if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
 			continue
 			continue
 		}
 		}
+		if col.SQLType.IsJson() {
+			continue
+		}
+
+		var colName string
+		if addedTableName {
+			var nm = tableName
+			if len(aliasName) > 0 {
+				nm = aliasName
+			}
+			colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
+		} else {
+			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.LogError(err)
@@ -517,7 +466,8 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 		}
 		}
 
 
 		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')", engine.Quote(col.Name), engine.Quote(col.Name)))
+			colNames = append(colNames, fmt.Sprintf("%v IS NULL or %v = '0001-01-01 00:00:00'",
+				colName, colName))
 		}
 		}
 
 
 		fieldValue := *fieldValuePtr
 		fieldValue := *fieldValuePtr
@@ -539,7 +489,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 			if fieldValue.IsNil() {
 			if fieldValue.IsNil() {
 				if includeNil {
 				if includeNil {
 					args = append(args, nil)
 					args = append(args, nil)
-					colNames = append(colNames, fmt.Sprintf("%v %s ?", engine.Quote(col.Name), engine.dialect.EqStr()))
+					colNames = append(colNames, fmt.Sprintf("%v %s ?", colName, engine.dialect.EqStr()))
 				}
 				}
 				continue
 				continue
 			} else if !fieldValue.IsValid() {
 			} else if !fieldValue.IsValid() {
@@ -597,24 +547,49 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 				val = engine.FormatTime(col.SQLType.Name, t)
 				val = engine.FormatTime(col.SQLType.Name, t)
 			} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
 			} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
 				continue
 				continue
+			} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
+				val, _ = valNul.Value()
+				if val == nil {
+					continue
+				}
 			} 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()
-						} else {
+				if col.SQLType.IsJson() {
+					if col.SQLType.IsText() {
+						bytes, err := json.Marshal(fieldValue.Interface())
+						if err != nil {
+							engine.LogError(err)
 							continue
 							continue
 						}
 						}
-					} else {
-						//TODO: how to handler?
-						panic("not supported")
+						val = string(bytes)
+					} else if col.SQLType.IsBlob() {
+						var bytes []byte
+						var err error
+						bytes, err = json.Marshal(fieldValue.Interface())
+						if err != nil {
+							engine.LogError(err)
+							continue
+						}
+						val = bytes
 					}
 					}
 				} else {
 				} else {
-					val = fieldValue.Interface()
+					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()
+							} else {
+								continue
+							}
+						} else {
+							//TODO: how to handler?
+							panic(fmt.Sprintln("not supported", fieldValue.Interface(), "as", table.PrimaryKeys))
+						}
+					} else {
+						val = fieldValue.Interface()
+					}
 				}
 				}
 			}
 			}
 		case reflect.Array, reflect.Slice, reflect.Map:
 		case reflect.Array, reflect.Slice, reflect.Map:
@@ -662,7 +637,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
 		if col.IsPrimaryKey && engine.dialect.DBType() == "ql" {
 		if col.IsPrimaryKey && engine.dialect.DBType() == "ql" {
 			condi = "id() == ?"
 			condi = "id() == ?"
 		} else {
 		} else {
-			condi = fmt.Sprintf("%v %s ?", engine.Quote(col.Name), engine.dialect.EqStr())
+			condi = fmt.Sprintf("%v %s ?", colName, engine.dialect.EqStr())
 		}
 		}
 		colNames = append(colNames, condi)
 		colNames = append(colNames, condi)
 	}
 	}
@@ -709,7 +684,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 {
@@ -720,7 +695,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 {
@@ -731,7 +706,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}
@@ -755,9 +730,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])
@@ -781,12 +761,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))",
+		buf.Reset()
+		fmt.Fprintf(&buf, "(%v IN (%v))",
 			statement.Engine.autoQuote(params.colName),
 			statement.Engine.autoQuote(params.colName),
-			strings.Join(makeArray("?", len(params.args)), ",")))
+			strings.Join(makeArray("?", len(params.args)), ","))
+		inStrs[i] = buf.String()
+		i++
 		args = append(args, params.args...)
 		args = append(args, params.args...)
 	}
 	}
 
 
@@ -799,7 +784,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
@@ -858,6 +843,18 @@ func (statement *Statement) Distinct(columns ...string) *Statement {
 	return statement
 	return statement
 }
 }
 
 
+// Generate "SELECT ... FOR UPDATE" statment
+func (statement *Statement) ForUpdate() *Statement {
+	statement.IsForUpdate = true
+	return statement
+}
+
+// replace select
+func (s *Statement) Select(str string) *Statement {
+	s.selectStr = str
+	return s
+}
+
 // 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...)
 	newColumns := col2NewCols(columns...)
@@ -868,6 +865,7 @@ func (statement *Statement) Cols(columns ...string) *Statement {
 	if strings.Contains(statement.ColumnStr, ".") {
 	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)
 	}
 	}
+	statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.Quote("*"), "*", -1)
 	return statement
 	return statement
 }
 }
 
 
@@ -886,15 +884,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 {
@@ -914,6 +903,14 @@ func (statement *Statement) Omit(columns ...string) {
 	statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
 	statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
 }
 }
 
 
+// Update use only: update columns to null when value is nullable and zero-value
+func (statement *Statement) Nullable(columns ...string) {
+	newColumns := col2NewCols(columns...)
+	for _, nc := range newColumns {
+		statement.nullableMap[strings.ToLower(nc)] = true
+	}
+}
+
 // Generate LIMIT limit statement
 // Generate LIMIT limit statement
 func (statement *Statement) Top(limit int) *Statement {
 func (statement *Statement) Top(limit int) *Statement {
 	statement.Limit(limit)
 	statement.Limit(limit)
@@ -931,7 +928,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
@@ -939,44 +936,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 {
 func (statement *Statement) Join(join_operator string, tablename interface{}, condition string) *Statement {
-	var joinTable string
+	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)
@@ -989,21 +993,17 @@ 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()
 	return statement
 	return statement
 }
 }
 
 
@@ -1120,11 +1120,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 {
@@ -1134,28 +1129,34 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
 		table = statement.RefTable
 		table = statement.RefTable
 	}
 	}
 
 
-	colNames, args := buildConditions(statement.Engine, table, bean, true, true,
-		false, true, statement.allUseBool, statement.useAllCols,
-		statement.unscoped, statement.mustColumnMap)
+	var addedTableName = (len(statement.JoinStr) > 0)
 
 
-	statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.dialect.AndStr()+" ")
-	statement.BeanArgs = args
+	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
+	}
 
 
 	var columnStr string = statement.ColumnStr
 	var columnStr string = statement.ColumnStr
-	if len(statement.JoinStr) == 0 {
-		if len(columnStr) == 0 {
-			if statement.GroupByStr != "" {
-				columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
-			} else {
-				columnStr = statement.genColumnStr()
-			}
-		}
+	if len(statement.selectStr) > 0 {
+		columnStr = statement.selectStr
 	} else {
 	} else {
-		if len(columnStr) == 0 {
-			if statement.GroupByStr != "" {
-				columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
-			} else {
-				columnStr = "*"
+		if len(statement.JoinStr) == 0 {
+			if len(columnStr) == 0 {
+				if statement.GroupByStr != "" {
+					columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
+				} else {
+					columnStr = statement.genColumnStr()
+				}
+			}
+		} else {
+			if len(columnStr) == 0 {
+				if statement.GroupByStr != "" {
+					columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
+				} else {
+					columnStr = "*"
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1185,16 +1186,23 @@ 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
 
 
-	colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
-		true, statement.allUseBool, statement.useAllCols,
-		statement.unscoped, statement.mustColumnMap)
+	var addedTableName = (len(statement.JoinStr) > 0)
 
 
-	statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.Dialect().AndStr()+" ")
-	statement.BeanArgs = args
+	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
+	}
 
 
 	// count(index fieldname) > count(0) > count(*)
 	// count(index fieldname) > count(0) > count(*)
 	var id string = "*"
 	var id string = "*"
@@ -1206,47 +1214,46 @@ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}
 }
 }
 
 
 func (statement *Statement) genSelectSql(columnStr string) (a string) {
 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
-	}*/
 	var distinct string
 	var distinct string
 	if statement.IsDistinct {
 	if statement.IsDistinct {
 		distinct = "DISTINCT "
 		distinct = "DISTINCT "
 	}
 	}
 
 
+	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, statement.Engine.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 statement.Engine.dialect.DBType() == core.ORACLE {
-			fromStr += " " + statement.Engine.Quote(statement.TableAlias)
+		if dialect.DBType() == core.ORACLE {
+			fromStr += " " + quote(statement.TableAlias)
 		} else {
 		} else {
-			fromStr += " AS " + statement.Engine.Quote(statement.TableAlias)
+			fromStr += " AS " + quote(statement.TableAlias)
 		}
 		}
 	}
 	}
 	if statement.JoinStr != "" {
 	if statement.JoinStr != "" {
 		fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr)
 		fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr)
 	}
 	}
 
 
-	if statement.Engine.dialect.DBType() == core.MSSQL {
+	if dialect.DBType() == core.MSSQL {
 		if statement.LimitN > 0 {
 		if statement.LimitN > 0 {
 			top = fmt.Sprintf(" TOP %d ", statement.LimitN)
 			top = fmt.Sprintf(" TOP %d ", statement.LimitN)
 		}
 		}
@@ -1277,10 +1284,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
@@ -1296,17 +1302,20 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
 	if statement.OrderStr != "" {
 	if statement.OrderStr != "" {
 		a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
 		a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
 	}
 	}
-	if statement.Engine.dialect.DBType() != core.MSSQL && statement.Engine.dialect.DBType() != core.ORACLE {
+	if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE {
 		if statement.Start > 0 {
 		if statement.Start > 0 {
 			a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start)
 			a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start)
 		} else if statement.LimitN > 0 {
 		} else if statement.LimitN > 0 {
 			a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN)
 			a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN)
 		}
 		}
-	} else if statement.Engine.dialect.DBType() == core.ORACLE {
+	} else if dialect.DBType() == core.ORACLE {
 		if statement.Start != 0 || statement.LimitN != 0 {
 		if statement.Start != 0 || statement.LimitN != 0 {
 			a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start)
 			a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start)
 		}
 		}
 	}
 	}
+	if statement.IsForUpdate {
+		a = dialect.ForUpdateSql(a)
+	}
 
 
 	return
 	return
 }
 }

+ 4 - 0
Godeps/_workspace/src/github.com/go-xorm/xorm/syslogger.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 // +build !windows,!nacl,!plan9
 // +build !windows,!nacl,!plan9
 
 
 package xorm
 package xorm

+ 6 - 2
Godeps/_workspace/src/github.com/go-xorm/xorm/xorm.go

@@ -1,3 +1,7 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package xorm
 package xorm
 
 
 import (
 import (
@@ -13,7 +17,7 @@ import (
 )
 )
 
 
 const (
 const (
-	Version string = "0.4.2.0225"
+	Version string = "0.4.5.0204"
 )
 )
 
 
 func regDrvsNDialects() bool {
 func regDrvsNDialects() bool {
@@ -35,7 +39,7 @@ func regDrvsNDialects() bool {
 	for driverName, v := range providedDrvsNDialects {
 	for driverName, v := range providedDrvsNDialects {
 		if driver := core.QueryDriver(driverName); driver == nil {
 		if driver := core.QueryDriver(driverName); driver == nil {
 			core.RegisterDriver(driverName, v.getDriver())
 			core.RegisterDriver(driverName, v.getDriver())
-			core.RegisterDialect(v.dbType, v.getDialect())
+			core.RegisterDialect(v.dbType, v.getDialect)
 		}
 		}
 	}
 	}
 	return true
 	return true

Някои файлове не бяха показани, защото твърде много файлове са промени