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

This commit is contained in:
Nash Tsai 2014-06-20 21:56:46 +08:00
commit 2f121b9566
12 changed files with 379 additions and 129 deletions

View File

@ -1 +1 @@
xorm v0.4.0 RC1
xorm v0.4.0

View File

@ -4,7 +4,7 @@
新特性:
* 移动xorm cmd [github.com/go-xorm/cmd](github.com/go-xorm/cmd)
* 在重构一般DB操作核心库 [github.com/go-xorm/core](https://github.com/go-xorm/core)
* 移动测试github.com/复XORM/测试 [github.com/go-xorm/tests](github.com/go-xorm/tests)
* 移动测试github.com/XORM/tests [github.com/go-xorm/tests](github.com/go-xorm/tests)
改进:
* Prepared statement 缓存

View File

@ -224,6 +224,8 @@ type Conversion interface {
}
```
- 5. If one struct has a Conversion field, so we need set an implementation to the field before get data from database. We can implement `BeforeSet(name string, cell xorm.Cell)` on struct to do this. For example: [testConversion](https://github.com/go-xorm/tests/blob/master/base.go#L1826)
<a name="30" id="30"></a>
## 3. database meta information
@ -510,7 +512,7 @@ total, err := engine.Where("id >?", 1).Count(user)
```
<a name="70" id="70"></a>
## 6.更新数据
## 6.Update
更新数据使用`Update`方法Update方法的第一个参数为需要更新的内容可以为一个结构体指针或者一个Map[string]interface{}类型。当传入的为结构体指针时只有非空和0的field才会被作为更新的字段。当传入的为Map类型时key为数据库Column的名字value为要更新的内容。
@ -691,7 +693,7 @@ Please visit [https://github.com/go-xorm/xorm/tree/master/examples](https://gith
<a name="160"></a>
## 15.FAQ
1.How the xorm tag use both with json?
* How the xorm tag use both with json?
Use space.
@ -700,3 +702,40 @@ type User struct {
Name string `json:"name" xorm:"name"`
}
```
* Does xorm support composite primary key?
Yes. You can use pk tag. All fields have tag will as one primary key by fields order on struct. When use, you can use xorm.PK{1, 2}. For example: `Id(xorm.PK{1, 2})`.
* How to use join
We can use Join() and extends tag to do join operation. For example:
type Userinfo struct {
Id int64
Name string
DetailId int64
}
type Userdetail struct {
Id int64
Gender int
}
type User struct {
Userinfo `xorm:"extends"`
Userdetail `xorm:"extends"`
}
var users = make([]User, 0)
err := engine.Table(&Userinfo{}).Join("LEFT", "userdetail", "userinfo.detail_id = userdetail.id").Find(&users)
//assert(User.Userinfo.Id != 0 && User.Userdetail.Id != 0)
Please notice that Userinfo field on User should be before Userdetail because of the order on join SQL stsatement. If the order is wrong, the same name field may be set a wrong value.
Of course, If join statment is very long, you could directly use Sql():
err := engine.Sql("select * from userinfo, userdetail where userinfo.detail_id = userdetail.id").Find(&users)
//assert(User.Userinfo.Id != 0 && User.Userdetail.Id != 0)

View File

@ -224,6 +224,8 @@ type Conversion interface {
}
```
- 5.如果一个结构体包含一个Conversion的接口类型那么在获取数据时必须要预先设置一个实现此接口的struct或者struct的指针。此时可以在此struct中实现`BeforeSet(name string, cell xorm.Cell)`方法来进行预先给Conversion赋值。例子参见 [testConversion](https://github.com/go-xorm/tests/blob/master/base.go#L1826)
<a name="24" id="24"></a>
### 2.4.Go与字段类型对应表
@ -828,6 +830,34 @@ money float64 `xorm:"Numeric"`
支持。在定义时如果有多个字段标记了pk则这些字段自动成为复合主键顺序为在struct中出现的顺序。在使用Id方法时可以用`Id(xorm.PK{1, 2})`的方式来用。
* xorm如何使用Join
一般我们配合Join()和extends标记来进行比如我们要对两个表进行Join操作我们可以这样
type Userinfo struct {
Id int64
Name string
DetailId int64
}
type Userdetail struct {
Id int64
Gender int
}
type User struct {
Userinfo `xorm:"extends"`
Userdetail `xorm:"extends"`
}
var users = make([]User, 0)
err := engine.Table(&Userinfo{}).Join("LEFT", "userdetail", "userinfo.detail_id = userdetail.id").Find(&users)
请注意这里的Userinfo在User中的位置必须在Userdetail的前面因为他在join语句中的顺序在userdetail前面。如果顺序不对那么对于同名的列有可能会赋值出错。
当然如果Join语句比较复杂我们也可以直接用Sql函数
err := engine.Sql("select * from userinfo, userdetail where userinfo.detail_id = userdetail.id").Find(&users)
<a name="170" id="170"></a>
## 17.讨论

182
engine.go
View File

@ -31,6 +31,7 @@ type Engine struct {
mutex *sync.RWMutex
Cacher core.Cacher
ShowInfo bool
ShowSQL bool
ShowErr bool
ShowDebug bool
@ -141,8 +142,8 @@ func (engine *Engine) NoCascade() *Session {
// Set a table use a special cacher
func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) {
v := rValue(bean)
engine.autoMapType(v)
engine.Tables[v.Type()].Cacher = cacher
tb := engine.autoMapType(v)
tb.Cacher = cacher
}
// NewDB provides an interface to operate database directly
@ -182,9 +183,9 @@ func (engine *Engine) Ping() error {
func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
if engine.ShowSQL {
if len(sqlArgs) > 0 {
engine.LogInfo("[sql]", sqlStr, "[args]", sqlArgs)
engine.Logger.Info(fmt.Sprintln("[sql]", sqlStr, "[args]", sqlArgs))
} else {
engine.LogInfo("[sql]", sqlStr)
engine.Logger.Info(fmt.Sprintln("[sql]", sqlStr))
}
}
}
@ -198,7 +199,9 @@ func (engine *Engine) LogError(contents ...interface{}) {
// logging error
func (engine *Engine) LogInfo(contents ...interface{}) {
engine.Logger.Info(fmt.Sprintln(contents...))
if engine.ShowInfo {
engine.Logger.Info(fmt.Sprintln(contents...))
}
}
// logging debug
@ -333,10 +336,19 @@ func (engine *Engine) DumpAll(w io.Writer) error {
} else if col.SQLType.IsText() || col.SQLType.IsTime() {
var v = fmt.Sprintf("%s", d)
temp += ", '" + strings.Replace(v, "'", "''", -1) + "'"
} else if col.SQLType.IsBlob() /*reflect.TypeOf(d).Kind() == reflect.Slice*/ {
temp += fmt.Sprintf(", %s", engine.dialect.FormatBytes(d.([]byte)))
} else if col.SQLType.IsBlob() /**/ {
if reflect.TypeOf(d).Kind() == reflect.Slice {
temp += fmt.Sprintf(", %s", engine.dialect.FormatBytes(d.([]byte)))
} else if reflect.TypeOf(d).Kind() == reflect.String {
temp += fmt.Sprintf(", '%s'", d.(string))
}
} else {
temp += fmt.Sprintf(", %s", d)
s := fmt.Sprintf("%v", d)
if strings.Contains(s, ":") || strings.Contains(s, "-") {
temp += fmt.Sprintf(", '%s'", s)
} else {
temp += fmt.Sprintf(", %s", s)
}
}
}
_, err = io.WriteString(w, temp[2:]+");\n\n")
@ -479,7 +491,7 @@ func (engine *Engine) Desc(colNames ...string) *Session {
return session.Desc(colNames...)
}
// Method Asc will generate "ORDER BY column1 DESC, column2 Asc"
// Method Asc will generate "ORDER BY column1,column2 Asc"
// This method can chainable use.
//
// engine.Desc("name").Asc("age").Find(&users)
@ -614,6 +626,7 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
for i := 0; i < t.NumField(); i++ {
tag := t.Field(i).Tag
ormTagStr := tag.Get(engine.TagIdentifier)
if !hasProcessedCacheTag {
cacheTagStr := tag.Get("xorm_cache")
@ -637,15 +650,10 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
continue
}
if strings.ToUpper(tags[0]) == "EXTENDS" {
//fieldValue = reflect.Indirect(fieldValue)
//fmt.Println("----", fieldValue.Kind())
if fieldValue.Kind() == reflect.Struct {
//parentTable := mappingTable(fieldType, tableMapper, colMapper, dialect, tagId)
parentTable := engine.mapType(fieldValue)
for _, col := range parentTable.Columns() {
col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName)
//fmt.Println("---", col.FieldName)
table.AddColumn(col)
}
@ -657,7 +665,6 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
if !fieldValue.IsValid() || fieldValue.IsNil() {
fieldValue = reflect.New(f).Elem()
}
//fmt.Println("00000", fieldValue)
}
parentTable := engine.mapType(fieldValue)
@ -779,7 +786,7 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table {
if col.Length2 == 0 {
col.Length2 = col.SQLType.DefaultLength2
}
//fmt.Println("======", col)
if col.Name == "" {
col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name)
}
@ -1053,6 +1060,138 @@ func (engine *Engine) Sync(beans ...interface{}) error {
return nil
}
func (engine *Engine) Sync2(beans ...interface{}) error {
tables, err := engine.DBMetas()
if err != nil {
return err
}
for _, bean := range beans {
table := engine.autoMap(bean)
var oriTable *core.Table
for _, tb := range tables {
if tb.Name == table.Name {
oriTable = tb
break
}
}
if oriTable == nil {
err = engine.CreateTables(bean)
if err != nil {
return err
}
err = engine.CreateUniques(bean)
if err != nil {
return err
}
err = engine.CreateIndexes(bean)
if err != nil {
return err
}
} else {
for _, col := range table.Columns() {
var oriCol *core.Column
for _, col2 := range oriTable.Columns() {
if col.Name == col2.Name {
oriCol = col2
break
}
}
if oriCol != nil {
if col.SQLType.Name != oriCol.SQLType.Name {
if col.SQLType.Name == core.Text &&
oriCol.SQLType.Name == core.Varchar {
// currently only support mysql
if engine.dialect.DBType() == core.MYSQL {
_, err = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col))
} else {
engine.LogWarn("Table %s Column %s Old data type is %s, new data type is %s",
table.Name, col.Name, oriCol.SQLType.Name, col.SQLType.Name)
}
} else {
engine.LogWarn("Table %s Column %s Old data type is %s, new data type is %s",
table.Name, col.Name, oriCol.SQLType.Name, col.SQLType.Name)
}
}
if col.Default != oriCol.Default {
engine.LogWarn("Table %s Column %s Old default is %s, new default is %s",
table.Name, col.Name, oriCol.Default, col.Default)
}
if col.Nullable != oriCol.Nullable {
engine.LogWarn("Table %s Column %s Old nullable is %v, new nullable is %v",
table.Name, col.Name, oriCol.Nullable, col.Nullable)
}
} else {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
err = session.addColumn(col.Name)
}
if err != nil {
return err
}
}
var foundIndexNames = make(map[string]bool)
for name, index := range table.Indexes {
var oriIndex *core.Index
for name2, index2 := range oriTable.Indexes {
if index.Equal(index2) {
oriIndex = index2
foundIndexNames[name2] = true
break
}
}
if oriIndex != nil {
if oriIndex.Type != index.Type {
sql := engine.dialect.DropIndexSql(table.Name, oriIndex)
_, err = engine.Exec(sql)
if err != nil {
return err
}
oriIndex = nil
}
}
if oriIndex == nil {
if index.Type == core.UniqueType {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
err = session.addUnique(table.Name, name)
} else if index.Type == core.IndexType {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
err = session.addIndex(table.Name, name)
}
if err != nil {
return err
}
}
}
for name2, index2 := range oriTable.Indexes {
if _, ok := foundIndexNames[name2]; !ok {
sql := engine.dialect.DropIndexSql(table.Name, index2)
_, err = engine.Exec(sql)
if err != nil {
return err
}
}
}
}
}
return nil
}
func (engine *Engine) unMap(beans ...interface{}) (e error) {
engine.mutex.Lock()
defer engine.mutex.Unlock()
@ -1213,17 +1352,20 @@ func (engine *Engine) Count(bean interface{}) (int64, error) {
}
// Import SQL DDL file
func (engine *Engine) Import(ddlPath string) ([]sql.Result, error) {
func (engine *Engine) ImportFile(ddlPath string) ([]sql.Result, error) {
file, err := os.Open(ddlPath)
if err != nil {
return nil, err
}
defer file.Close()
return engine.Import(file)
}
// Import SQL DDL file
func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
var results []sql.Result
var lastError error
scanner := bufio.NewScanner(file)
scanner := bufio.NewScanner(r)
semiColSpliter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
@ -1244,7 +1386,7 @@ func (engine *Engine) Import(ddlPath string) ([]sql.Result, error) {
session := engine.NewSession()
defer session.Close()
err = session.newDb()
err := session.newDb()
if err != nil {
return results, err
}

View File

@ -62,10 +62,10 @@ func (db *mssql) SqlType(c *core.Column) string {
var hasLen1 bool = (c.Length > 0)
var hasLen2 bool = (c.Length2 > 0)
if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
} else if hasLen2 {
if hasLen2 {
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
} else if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
}
return res
}

View File

@ -70,10 +70,11 @@ func (db *mysql) SqlType(c *core.Column) string {
var hasLen1 bool = (c.Length > 0)
var hasLen2 bool = (c.Length2 > 0)
if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
} else if hasLen2 {
if hasLen2 {
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
} else if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
}
return res
}

View File

@ -44,10 +44,10 @@ func (db *oracle) SqlType(c *core.Column) string {
var hasLen1 bool = (c.Length > 0)
var hasLen2 bool = (c.Length2 > 0)
if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
} else if hasLen2 {
if hasLen2 {
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
} else if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
}
return res
}

View File

@ -59,10 +59,10 @@ func (db *postgres) SqlType(c *core.Column) string {
var hasLen1 bool = (c.Length > 0)
var hasLen2 bool = (c.Length2 > 0)
if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
} else if hasLen2 {
if hasLen2 {
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
} else if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
}
return res
}
@ -108,10 +108,28 @@ func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
" AND column_name = ?", args
}*/
func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string {
return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
tableName, col.Name, db.SqlType(col))
}
func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
quote := db.Quote
//var unique string
var idxName string = index.Name
if !strings.HasPrefix(idxName, "UQE_") &&
!strings.HasPrefix(idxName, "IDX_") {
if index.Type == core.UniqueType {
idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
} else {
idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
}
}
return fmt.Sprintf("DROP INDEX %v", quote(idxName))
}
func (db *postgres) IsColumnExist(tableName string, col *core.Column) (bool, error) {
args := []interface{}{tableName, col.Name}
//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_name = $1" +
" AND column_name = $2"
rows, err := db.DB().Query(query, args...)
@ -120,10 +138,7 @@ func (db *postgres) IsColumnExist(tableName string, col *core.Column) (bool, err
}
defer rows.Close()
if rows.Next() {
return true, nil
}
return false, nil
return rows.Next(), nil
}
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
@ -169,11 +184,7 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Col
}
}
if isNullable == "YES" {
col.Nullable = true
} else {
col.Nullable = false
}
col.Nullable = (isNullable == "YES")
switch dataType {
case "character varying", "character":
@ -257,7 +268,9 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
return nil, err
}
indexName = strings.Trim(indexName, `" `)
if strings.HasSuffix(indexName, "_pkey") {
continue
}
if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
indexType = core.UniqueType
} else {
@ -266,9 +279,6 @@ func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error)
cs := strings.Split(indexdef, "(")
colNames = strings.Split(cs[1][0:len(cs[1])-1], ",")
if strings.HasSuffix(indexName, "_pkey") {
continue
}
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
newIdxName := indexName[5+len(tableName) : len(indexName)]
if newIdxName != "" {

View File

@ -26,6 +26,10 @@ type Session struct {
TransType string
IsAutoClose bool
// Automatically reset the statement after operations that execute a SQL
// query such as Count(), Find(), Get(), ...
AutoResetStatement bool
// !nashtsai! storing these beans due to yet committed tx
afterInsertBeans map[interface{}]*[]func(interface{})
afterUpdateBeans map[interface{}]*[]func(interface{})
@ -45,6 +49,7 @@ func (session *Session) Init() {
session.IsAutoCommit = true
session.IsCommitedOrRollbacked = false
session.IsAutoClose = false
session.AutoResetStatement = true
// !nashtsai! is lazy init better?
session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0)
@ -69,6 +74,12 @@ func (session *Session) Close() {
}
}
func (session *Session) resetStatement() {
if session.AutoResetStatement {
session.Statement.Init()
}
}
// Method Sql provides raw sql input parameter. When you have a complex SQL statement
// and cannot use Where, Id, In and etc. Methods to describe, you can use Sql.
func (session *Session) Sql(querystring string, args ...interface{}) *Session {
@ -431,7 +442,7 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
}
session.Engine.logSQL(sqlStr, args)
session.Engine.logSQL(sqlStr, args...)
if session.IsAutoCommit {
return session.innerExec(sqlStr, args...)
@ -445,7 +456,7 @@ func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, er
if err != nil {
return nil, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -461,7 +472,7 @@ func (session *Session) CreateTable(bean interface{}) error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -477,7 +488,7 @@ func (session *Session) CreateIndexes(bean interface{}) error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -500,7 +511,7 @@ func (session *Session) CreateUniques(bean interface{}) error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -528,7 +539,7 @@ func (session *Session) createAll() error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -549,7 +560,7 @@ func (session *Session) DropIndexes(bean interface{}) error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -571,13 +582,13 @@ func (session *Session) DropTable(bean interface{}) error {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
t := reflect.Indirect(reflect.ValueOf(bean)).Type()
defer session.Statement.Init()
defer session.resetStatement()
if t.Kind() == reflect.String {
session.Statement.AltTableName = bean.(string)
} else if t.Kind() == reflect.Struct {
@ -599,7 +610,6 @@ func (statement *Statement) convertIdSql(sqlStr string) string {
if len(sqls) != 2 {
return ""
}
//fmt.Println("-----", col)
newsql := fmt.Sprintf("SELECT %v.%v FROM %v", statement.Engine.Quote(statement.TableName()),
statement.Engine.Quote(col.Name), sqls[1])
return newsql
@ -728,7 +738,6 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
ids = make([]core.PK, 0)
if len(resultsSlice) > 0 {
for _, data := range resultsSlice {
//fmt.Println(data)
var id int64
if v, ok := data[session.Statement.RefTable.PrimaryKeys[0]]; !ok {
return errors.New("no id")
@ -930,7 +939,7 @@ func (session *Session) Get(bean interface{}) (bool, error) {
return false, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -939,7 +948,9 @@ func (session *Session) Get(bean interface{}) (bool, error) {
var sqlStr string
var args []interface{}
session.Statement.RefTable = session.Engine.autoMap(bean)
if session.Statement.RefTable == nil {
session.Statement.RefTable = session.Engine.autoMap(bean)
}
if session.Statement.RawSQL == "" {
sqlStr, args = session.Statement.genGetSql(bean)
@ -948,10 +959,12 @@ func (session *Session) Get(bean interface{}) (bool, error) {
args = session.Statement.RawParams
}
if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache {
has, err := session.cacheGet(bean, sqlStr, args...)
if err != ErrCacheFailed {
return has, err
if session.Statement.JoinStr == "" {
if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache {
has, err := session.cacheGet(bean, sqlStr, args...)
if err != ErrCacheFailed {
return has, err
}
}
}
@ -991,7 +1004,7 @@ func (session *Session) Count(bean interface{}) (int64, error) {
return 0, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1030,7 +1043,7 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1073,8 +1086,14 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
var args []interface{}
if session.Statement.RawSQL == "" {
var columnStr string = session.Statement.ColumnStr
if columnStr == "" {
columnStr = session.Statement.genColumnStr()
if session.Statement.JoinStr == "" {
if columnStr == "" {
columnStr = session.Statement.genColumnStr()
}
} else {
if columnStr == "" {
columnStr = "*"
}
}
session.Statement.attachInSql()
@ -1086,15 +1105,17 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
args = session.Statement.RawParams
}
if cacher := session.Engine.getCacher2(table); cacher != nil &&
session.Statement.UseCache &&
!session.Statement.IsDistinct {
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
if err != ErrCacheFailed {
return err
if session.Statement.JoinStr == "" {
if cacher := session.Engine.getCacher2(table); cacher != nil &&
session.Statement.UseCache &&
!session.Statement.IsDistinct {
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
if err != ErrCacheFailed {
return err
}
err = nil // !nashtsai! reset err to nil for ErrCacheFailed
session.Engine.LogWarn("Cache Find Failed")
}
err = nil // !nashtsai! reset err to nil for ErrCacheFailed
session.Engine.LogWarn("Cache Find Failed")
}
if sliceValue.Kind() != reflect.Map {
@ -1102,14 +1123,6 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
var stmt *core.Stmt
session.queryPreprocess(&sqlStr, args...)
// err = session.queryRows(&stmt, &rawRows, sqlStr, args...)
// if err != nil {
// return err
// }
// if stmt != nil {
// defer stmt.Close()
// }
// defer rawRows.Close()
if session.IsAutoCommit {
stmt, err = session.doPrepare(sqlStr)
@ -1226,7 +1239,7 @@ func (session *Session) Ping() error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1239,7 +1252,7 @@ func (session *Session) isColumnExist(tableName string, col *core.Column) (bool,
if err != nil {
return false, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1254,7 +1267,7 @@ func (session *Session) isTableExist(tableName string) (bool, error) {
if err != nil {
return false, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1268,7 +1281,7 @@ func (session *Session) isIndexExist(tableName, idxName string, unique bool) (bo
if err != nil {
return false, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1307,11 +1320,10 @@ func (session *Session) addColumn(colName string) error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
//fmt.Println(session.Statement.RefTable)
col := session.Statement.RefTable.GetColumn(colName)
sql, args := session.Statement.genAddColumnStr(col)
@ -1324,7 +1336,7 @@ func (session *Session) addIndex(tableName, idxName string) error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1340,11 +1352,10 @@ func (session *Session) addUnique(tableName, uqeName string) error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
//fmt.Println(uqeName, session.Statement.RefTable.Uniques)
index := session.Statement.RefTable.Indexes[uqeName]
sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index)
_, err = session.exec(sqlStr)
@ -1357,7 +1368,7 @@ func (session *Session) dropAll() error {
if err != nil {
return err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1402,9 +1413,9 @@ func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, er
return result, nil
}
func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table) *reflect.Value {
func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) *reflect.Value {
var col *core.Column
if col = table.GetColumn(key); col == nil {
if col = table.GetColumnIdx(key, idx); col == nil {
session.Engine.LogWarn(fmt.Sprintf("table %v's has not column %v. %v", table.Name, key, table.Columns()))
return nil
}
@ -1448,13 +1459,22 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
}
}
var tempMap = make(map[string]int)
for ii, key := range fields {
if fieldValue := session.getField(&dataStruct, key, table); fieldValue != nil {
var idx int
var ok bool
if idx, ok = tempMap[strings.ToLower(key)]; !ok {
idx = 0
} else {
idx = idx + 1
}
tempMap[strings.ToLower(key)] = idx
if fieldValue := session.getField(&dataStruct, key, table, idx); fieldValue != nil {
rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
//if row is null then ignore
if rawValue.Interface() == nil {
//fmt.Println("ignore ...", key, rawValue)
continue
}
@ -1485,9 +1505,6 @@ func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount i
vv := reflect.ValueOf(rawValue.Interface())
fieldType := fieldValue.Type()
//fmt.Println("column name:", key, ", fieldType:", fieldType.String())
hasAssigned := false
switch fieldType.Kind() {
@ -1734,7 +1751,7 @@ func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{})
*sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable)
}
session.Engine.logSQL(*sqlStr, paramStr)
session.Engine.logSQL(*sqlStr, paramStr...)
}
func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
@ -1767,7 +1784,6 @@ func query(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []ma
return nil, err
}
defer rows.Close()
//fmt.Println(rows)
return rows2maps(rows)
}
@ -1777,7 +1793,7 @@ func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSl
if err != nil {
return nil, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1793,7 +1809,7 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) {
if err != nil {
return 0, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -1980,7 +1996,7 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
if err != nil {
return 0, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -2034,11 +2050,9 @@ func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.T
}
sdata = strings.TrimSpace(sdata)
//fmt.Println(sdata)
if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
sdata = sdata[len(sdata)-8:]
}
//fmt.Println(sdata)
st := fmt.Sprintf("2006-01-02 %v", sdata)
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation)
@ -2069,7 +2083,6 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
key := col.Name
fieldType := fieldValue.Type()
//fmt.Println("column name:", key, ", fieldType:", fieldType.String())
switch fieldType.Kind() {
case reflect.Complex64, reflect.Complex128:
x := reflect.New(fieldType)
@ -2578,7 +2591,6 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
}
colPlaces := strings.Repeat("?, ", len(colNames))
//fmt.Println(colNames, args)
colPlaces = colPlaces[0 : len(colPlaces)-2]
sqlStr := fmt.Sprintf("INSERT INTO %v%v%v (%v%v%v) VALUES (%v)",
@ -2748,7 +2760,7 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) {
if err != nil {
return 0, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -2934,7 +2946,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
if err != nil {
return 0, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -2988,7 +3000,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
if session.Statement.UseAutoTime && table.Updated != "" {
colNames = append(colNames, session.Engine.Quote(table.Updated)+" = ?")
args = append(args, session.Engine.NowTime(table.Columns()[strings.ToLower(table.Updated)].SQLType.Name))
args = append(args, session.Engine.NowTime(table.UpdatedColumn().SQLType.Name))
}
//for update action to like "column = column + ?"
@ -3009,7 +3021,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
var condition = ""
session.Statement.processIdParam()
st := session.Statement
defer session.Statement.Init()
defer session.resetStatement()
if st.WhereStr != "" {
condition = fmt.Sprintf("%v", st.WhereStr)
}
@ -3187,7 +3199,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
if err != nil {
return 0, err
}
defer session.Statement.Init()
defer session.resetStatement()
if session.IsAutoClose {
defer session.Close()
}
@ -3332,6 +3344,7 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool,
args = append(args, session.Engine.NowTime(col.SQLType.Name))
} else if col.IsVersion && session.Statement.checkVersion {
args = append(args, 1)
//} else if !col.DefaultIsEmpty {
} else {
arg, err := session.value2Interface(col, fieldValue)
if err != nil {

View File

@ -1,6 +1,7 @@
package xorm
import (
"errors"
"fmt"
"strings"
@ -120,6 +121,11 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
if err != nil {
return nil, nil, err
}
break
}
if name == "" {
return nil, nil, errors.New("no table named " + tableName)
}
nStart := strings.Index(name, "(")

View File

@ -277,11 +277,11 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
if !includeAutoIncr && col.IsAutoIncrement {
continue
}
//
//fmt.Println(engine.dialect.DBType(), Text)
if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
continue
}
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
engine.LogError(err)
@ -292,6 +292,7 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
fieldType := reflect.TypeOf(fieldValue.Interface())
requiredField := useAllCols
includeNil := useAllCols
if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok {
if b {
requiredField = true
@ -382,7 +383,6 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{},
continue
}
val = engine.FormatTime(col.SQLType.Name, t)
//fmt.Println("-------", t, val, col.Name)
} else {
engine.autoMapType(fieldValue)
if table, ok := engine.Tables[fieldValue.Type()]; ok {
@ -470,8 +470,7 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
if !includeAutoIncr && col.IsAutoIncrement {
continue
}
//
//fmt.Println(engine.dialect.DBType(), Text)
if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
continue
}
@ -555,7 +554,6 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
continue
}
val = engine.FormatTime(col.SQLType.Name, t)
//fmt.Println("-------", t, val, col.Name)
} else {
engine.autoMapType(fieldValue)
if table, ok := engine.Tables[fieldValue.Type()]; ok {
@ -948,8 +946,13 @@ func (s *Statement) genDropSQL() string {
}
func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) {
table := statement.Engine.autoMap(bean)
statement.RefTable = table
var table *core.Table
if statement.RefTable == nil {
table = statement.Engine.autoMap(bean)
statement.RefTable = table
} else {
table = statement.RefTable
}
colNames, args := buildConditions(statement.Engine, table, bean, true, true,
false, true, statement.allUseBool, statement.useAllCols,
@ -959,8 +962,14 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
statement.BeanArgs = args
var columnStr string = statement.ColumnStr
if columnStr == "" {
columnStr = statement.genColumnStr()
if statement.JoinStr == "" {
if columnStr == "" {
columnStr = statement.genColumnStr()
}
} else {
if columnStr == "" {
columnStr = "*"
}
}
statement.attachInSql() // !admpub! fix bug:Iterate func missing "... IN (...)"