github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-xorm/xorm/session.go (about) 1 // Copyright 2015 The Xorm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package xorm 6 7 import ( 8 "database/sql" 9 "database/sql/driver" 10 "encoding/json" 11 "errors" 12 "fmt" 13 "hash/crc32" 14 "reflect" 15 "strconv" 16 "strings" 17 "time" 18 19 "github.com/insionng/yougam/libraries/go-xorm/builder" 20 "github.com/insionng/yougam/libraries/go-xorm/core" 21 ) 22 23 // Session keep a pointer to sql.DB and provides all execution of all 24 // kind of database operations. 25 type Session struct { 26 db *core.DB 27 Engine *Engine 28 Tx *core.Tx 29 Statement Statement 30 IsAutoCommit bool 31 IsCommitedOrRollbacked bool 32 TransType string 33 IsAutoClose bool 34 35 // Automatically reset the statement after operations that execute a SQL 36 // query such as Count(), Find(), Get(), ... 37 AutoResetStatement bool 38 39 // !nashtsai! storing these beans due to yet committed tx 40 afterInsertBeans map[interface{}]*[]func(interface{}) 41 afterUpdateBeans map[interface{}]*[]func(interface{}) 42 afterDeleteBeans map[interface{}]*[]func(interface{}) 43 // -- 44 45 beforeClosures []func(interface{}) 46 afterClosures []func(interface{}) 47 48 prepareStmt bool 49 stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr)) 50 cascadeDeep int 51 52 // !evalphobia! stored the last executed query on this session 53 //beforeSQLExec func(string, ...interface{}) 54 lastSQL string 55 lastSQLArgs []interface{} 56 } 57 58 // Clone copy all the session's content and return a new session 59 func (session *Session) Clone() *Session { 60 var sess = *session 61 return &sess 62 } 63 64 // Init reset the session as the init status. 65 func (session *Session) Init() { 66 session.Statement.Init() 67 session.Statement.Engine = session.Engine 68 session.IsAutoCommit = true 69 session.IsCommitedOrRollbacked = false 70 session.IsAutoClose = false 71 session.AutoResetStatement = true 72 session.prepareStmt = false 73 74 // !nashtsai! is lazy init better? 75 session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0) 76 session.afterUpdateBeans = make(map[interface{}]*[]func(interface{}), 0) 77 session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0) 78 session.beforeClosures = make([]func(interface{}), 0) 79 session.afterClosures = make([]func(interface{}), 0) 80 81 session.lastSQL = "" 82 session.lastSQLArgs = []interface{}{} 83 } 84 85 // Close release the connection from pool 86 func (session *Session) Close() { 87 for _, v := range session.stmtCache { 88 v.Close() 89 } 90 91 if session.db != nil { 92 // When Close be called, if session is a transaction and do not call 93 // Commit or Rollback, then call Rollback. 94 if session.Tx != nil && !session.IsCommitedOrRollbacked { 95 session.Rollback() 96 } 97 session.Tx = nil 98 session.stmtCache = nil 99 session.Init() 100 session.db = nil 101 } 102 } 103 104 func (session *Session) resetStatement() { 105 if session.AutoResetStatement { 106 session.Statement.Init() 107 } 108 } 109 110 // Prepare set a flag to session that should be prepare statment before execute query 111 func (session *Session) Prepare() *Session { 112 session.prepareStmt = true 113 return session 114 } 115 116 // Sql !DEPRECIATED! will be deprecated, please use SQL instead. 117 func (session *Session) Sql(query string, args ...interface{}) *Session { 118 return session.SQL(query, args...) 119 } 120 121 // SQL provides raw sql input parameter. When you have a complex SQL statement 122 // and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. 123 func (session *Session) SQL(query interface{}, args ...interface{}) *Session { 124 session.Statement.SQL(query, args...) 125 return session 126 } 127 128 // Where provides custom query condition. 129 func (session *Session) Where(query interface{}, args ...interface{}) *Session { 130 session.Statement.Where(query, args...) 131 return session 132 } 133 134 // And provides custom query condition. 135 func (session *Session) And(query interface{}, args ...interface{}) *Session { 136 session.Statement.And(query, args...) 137 return session 138 } 139 140 // Or provides custom query condition. 141 func (session *Session) Or(query interface{}, args ...interface{}) *Session { 142 session.Statement.Or(query, args...) 143 return session 144 } 145 146 // Id will be deprecated, please use ID instead 147 func (session *Session) Id(id interface{}) *Session { 148 session.Statement.Id(id) 149 return session 150 } 151 152 // ID provides converting id as a query condition 153 func (session *Session) ID(id interface{}) *Session { 154 session.Statement.Id(id) 155 return session 156 } 157 158 // Before Apply before Processor, affected bean is passed to closure arg 159 func (session *Session) Before(closures func(interface{})) *Session { 160 if closures != nil { 161 session.beforeClosures = append(session.beforeClosures, closures) 162 } 163 return session 164 } 165 166 // After Apply after Processor, affected bean is passed to closure arg 167 func (session *Session) After(closures func(interface{})) *Session { 168 if closures != nil { 169 session.afterClosures = append(session.afterClosures, closures) 170 } 171 return session 172 } 173 174 // Table can input a string or pointer to struct for special a table to operate. 175 func (session *Session) Table(tableNameOrBean interface{}) *Session { 176 session.Statement.Table(tableNameOrBean) 177 return session 178 } 179 180 // Alias set the table alias 181 func (session *Session) Alias(alias string) *Session { 182 session.Statement.Alias(alias) 183 return session 184 } 185 186 // In provides a query string like "id in (1, 2, 3)" 187 func (session *Session) In(column string, args ...interface{}) *Session { 188 session.Statement.In(column, args...) 189 return session 190 } 191 192 // NotIn provides a query string like "id in (1, 2, 3)" 193 func (session *Session) NotIn(column string, args ...interface{}) *Session { 194 session.Statement.NotIn(column, args...) 195 return session 196 } 197 198 // Incr provides a query string like "count = count + 1" 199 func (session *Session) Incr(column string, arg ...interface{}) *Session { 200 session.Statement.Incr(column, arg...) 201 return session 202 } 203 204 // Decr provides a query string like "count = count - 1" 205 func (session *Session) Decr(column string, arg ...interface{}) *Session { 206 session.Statement.Decr(column, arg...) 207 return session 208 } 209 210 // SetExpr provides a query string like "column = {expression}" 211 func (session *Session) SetExpr(column string, expression string) *Session { 212 session.Statement.SetExpr(column, expression) 213 return session 214 } 215 216 // Select provides some columns to special 217 func (session *Session) Select(str string) *Session { 218 session.Statement.Select(str) 219 return session 220 } 221 222 // Cols provides some columns to special 223 func (session *Session) Cols(columns ...string) *Session { 224 session.Statement.Cols(columns...) 225 return session 226 } 227 228 // AllCols ask all columns 229 func (session *Session) AllCols() *Session { 230 session.Statement.AllCols() 231 return session 232 } 233 234 // MustCols specify some columns must use even if they are empty 235 func (session *Session) MustCols(columns ...string) *Session { 236 session.Statement.MustCols(columns...) 237 return session 238 } 239 240 // NoCascade indicate that no cascade load child object 241 func (session *Session) NoCascade() *Session { 242 session.Statement.UseCascade = false 243 return session 244 } 245 246 // UseBool automatically retrieve condition according struct, but 247 // if struct has bool field, it will ignore them. So use UseBool 248 // to tell system to do not ignore them. 249 // If no paramters, it will use all the bool field of struct, or 250 // it will use paramters's columns 251 func (session *Session) UseBool(columns ...string) *Session { 252 session.Statement.UseBool(columns...) 253 return session 254 } 255 256 // Distinct use for distinct columns. Caution: when you are using cache, 257 // distinct will not be cached because cache system need id, 258 // but distinct will not provide id 259 func (session *Session) Distinct(columns ...string) *Session { 260 session.Statement.Distinct(columns...) 261 return session 262 } 263 264 // ForUpdate Set Read/Write locking for UPDATE 265 func (session *Session) ForUpdate() *Session { 266 session.Statement.IsForUpdate = true 267 return session 268 } 269 270 // Omit Only not use the paramters as select or update columns 271 func (session *Session) Omit(columns ...string) *Session { 272 session.Statement.Omit(columns...) 273 return session 274 } 275 276 // Nullable Set null when column is zero-value and nullable for update 277 func (session *Session) Nullable(columns ...string) *Session { 278 session.Statement.Nullable(columns...) 279 return session 280 } 281 282 // NoAutoTime means do not automatically give created field and updated field 283 // the current time on the current session temporarily 284 func (session *Session) NoAutoTime() *Session { 285 session.Statement.UseAutoTime = false 286 return session 287 } 288 289 // NoAutoCondition disable generate SQL condition from beans 290 func (session *Session) NoAutoCondition(no ...bool) *Session { 291 session.Statement.NoAutoCondition(no...) 292 return session 293 } 294 295 // Limit provide limit and offset query condition 296 func (session *Session) Limit(limit int, start ...int) *Session { 297 session.Statement.Limit(limit, start...) 298 return session 299 } 300 301 // OrderBy provide order by query condition, the input parameter is the content 302 // after order by on a sql statement. 303 func (session *Session) OrderBy(order string) *Session { 304 session.Statement.OrderBy(order) 305 return session 306 } 307 308 // Desc provide desc order by query condition, the input parameters are columns. 309 func (session *Session) Desc(colNames ...string) *Session { 310 session.Statement.Desc(colNames...) 311 return session 312 } 313 314 // Asc provide asc order by query condition, the input parameters are columns. 315 func (session *Session) Asc(colNames ...string) *Session { 316 session.Statement.Asc(colNames...) 317 return session 318 } 319 320 // StoreEngine is only avialble mysql dialect currently 321 func (session *Session) StoreEngine(storeEngine string) *Session { 322 session.Statement.StoreEngine = storeEngine 323 return session 324 } 325 326 // Charset is only avialble mysql dialect currently 327 func (session *Session) Charset(charset string) *Session { 328 session.Statement.Charset = charset 329 return session 330 } 331 332 // Cascade indicates if loading sub Struct 333 func (session *Session) Cascade(trueOrFalse ...bool) *Session { 334 if len(trueOrFalse) >= 1 { 335 session.Statement.UseCascade = trueOrFalse[0] 336 } 337 return session 338 } 339 340 // NoCache ask this session do not retrieve data from cache system and 341 // get data from database directly. 342 func (session *Session) NoCache() *Session { 343 session.Statement.UseCache = false 344 return session 345 } 346 347 // Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN 348 func (session *Session) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session { 349 session.Statement.Join(joinOperator, tablename, condition, args...) 350 return session 351 } 352 353 // GroupBy Generate Group By statement 354 func (session *Session) GroupBy(keys string) *Session { 355 session.Statement.GroupBy(keys) 356 return session 357 } 358 359 // Having Generate Having statement 360 func (session *Session) Having(conditions string) *Session { 361 session.Statement.Having(conditions) 362 return session 363 } 364 365 // DB db return the wrapper of sql.DB 366 func (session *Session) DB() *core.DB { 367 if session.db == nil { 368 session.db = session.Engine.db 369 session.stmtCache = make(map[uint32]*core.Stmt, 0) 370 } 371 return session.db 372 } 373 374 // Conds returns session query conditions 375 func (session *Session) Conds() builder.Cond { 376 return session.Statement.cond 377 } 378 379 // Begin a transaction 380 func (session *Session) Begin() error { 381 if session.IsAutoCommit { 382 tx, err := session.DB().Begin() 383 if err != nil { 384 return err 385 } 386 session.IsAutoCommit = false 387 session.IsCommitedOrRollbacked = false 388 session.Tx = tx 389 session.saveLastSQL("BEGIN TRANSACTION") 390 } 391 return nil 392 } 393 394 // Rollback When using transaction, you can rollback if any error 395 func (session *Session) Rollback() error { 396 if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { 397 session.saveLastSQL(session.Engine.dialect.RollBackStr()) 398 session.IsCommitedOrRollbacked = true 399 return session.Tx.Rollback() 400 } 401 return nil 402 } 403 404 // Commit When using transaction, Commit will commit all operations. 405 func (session *Session) Commit() error { 406 if !session.IsAutoCommit && !session.IsCommitedOrRollbacked { 407 session.saveLastSQL("COMMIT") 408 session.IsCommitedOrRollbacked = true 409 var err error 410 if err = session.Tx.Commit(); err == nil { 411 // handle processors after tx committed 412 413 closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) { 414 415 if closuresPtr != nil { 416 for _, closure := range *closuresPtr { 417 closure(bean) 418 } 419 } 420 } 421 422 for bean, closuresPtr := range session.afterInsertBeans { 423 closureCallFunc(closuresPtr, bean) 424 425 if processor, ok := interface{}(bean).(AfterInsertProcessor); ok { 426 processor.AfterInsert() 427 } 428 } 429 for bean, closuresPtr := range session.afterUpdateBeans { 430 closureCallFunc(closuresPtr, bean) 431 432 if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok { 433 processor.AfterUpdate() 434 } 435 } 436 for bean, closuresPtr := range session.afterDeleteBeans { 437 closureCallFunc(closuresPtr, bean) 438 439 if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok { 440 processor.AfterDelete() 441 } 442 } 443 cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) { 444 if len(*slices) > 0 { 445 *slices = make(map[interface{}]*[]func(interface{}), 0) 446 } 447 } 448 cleanUpFunc(&session.afterInsertBeans) 449 cleanUpFunc(&session.afterUpdateBeans) 450 cleanUpFunc(&session.afterDeleteBeans) 451 } 452 return err 453 } 454 return nil 455 } 456 457 func cleanupProcessorsClosures(slices *[]func(interface{})) { 458 if len(*slices) > 0 { 459 *slices = make([]func(interface{}), 0) 460 } 461 } 462 463 func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error { 464 dataStruct := rValue(obj) 465 if dataStruct.Kind() != reflect.Struct { 466 return errors.New("Expected a pointer to a struct") 467 } 468 469 var col *core.Column 470 session.Statement.setRefValue(dataStruct) 471 table := session.Statement.RefTable 472 tableName := session.Statement.tableName 473 474 for key, data := range objMap { 475 if col = table.GetColumn(key); col == nil { 476 session.Engine.logger.Warnf("struct %v's has not field %v. %v", 477 table.Type.Name(), key, table.ColumnsSeq()) 478 continue 479 } 480 481 fieldName := col.FieldName 482 fieldPath := strings.Split(fieldName, ".") 483 var fieldValue reflect.Value 484 if len(fieldPath) > 2 { 485 session.Engine.logger.Error("Unsupported mutliderive", fieldName) 486 continue 487 } else if len(fieldPath) == 2 { 488 parentField := dataStruct.FieldByName(fieldPath[0]) 489 if parentField.IsValid() { 490 fieldValue = parentField.FieldByName(fieldPath[1]) 491 } 492 } else { 493 fieldValue = dataStruct.FieldByName(fieldName) 494 } 495 if !fieldValue.IsValid() || !fieldValue.CanSet() { 496 session.Engine.logger.Warnf("table %v's column %v is not valid or cannot set", tableName, key) 497 continue 498 } 499 500 err := session.bytes2Value(col, &fieldValue, data) 501 if err != nil { 502 return err 503 } 504 } 505 506 return nil 507 } 508 509 // Execute sql 510 func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Result, error) { 511 if session.prepareStmt { 512 stmt, err := session.doPrepare(sqlStr) 513 if err != nil { 514 return nil, err 515 } 516 517 res, err := stmt.Exec(args...) 518 if err != nil { 519 return nil, err 520 } 521 return res, nil 522 } 523 524 return session.DB().Exec(sqlStr, args...) 525 } 526 527 func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) { 528 for _, filter := range session.Engine.dialect.Filters() { 529 // TODO: for table name, it's no need to RefTable 530 sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) 531 } 532 533 session.saveLastSQL(sqlStr, args...) 534 535 return session.Engine.logSQLExecutionTime(sqlStr, args, func() (sql.Result, error) { 536 if session.IsAutoCommit { 537 // FIXME: oci8 can not auto commit (github.com/mattn/go-oci8) 538 if session.Engine.dialect.DBType() == core.ORACLE { 539 session.Begin() 540 r, err := session.Tx.Exec(sqlStr, args...) 541 session.Commit() 542 return r, err 543 } 544 return session.innerExec(sqlStr, args...) 545 } 546 return session.Tx.Exec(sqlStr, args...) 547 }) 548 } 549 550 // Exec raw sql 551 func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) { 552 defer session.resetStatement() 553 if session.IsAutoClose { 554 defer session.Close() 555 } 556 557 return session.exec(sqlStr, args...) 558 } 559 560 // CreateTable create a table according a bean 561 func (session *Session) CreateTable(bean interface{}) error { 562 v := rValue(bean) 563 session.Statement.setRefValue(v) 564 565 defer session.resetStatement() 566 if session.IsAutoClose { 567 defer session.Close() 568 } 569 570 return session.createOneTable() 571 } 572 573 // CreateIndexes create indexes 574 func (session *Session) CreateIndexes(bean interface{}) error { 575 v := rValue(bean) 576 session.Statement.setRefValue(v) 577 578 defer session.resetStatement() 579 if session.IsAutoClose { 580 defer session.Close() 581 } 582 583 sqls := session.Statement.genIndexSQL() 584 for _, sqlStr := range sqls { 585 _, err := session.exec(sqlStr) 586 if err != nil { 587 return err 588 } 589 } 590 return nil 591 } 592 593 // CreateUniques create uniques 594 func (session *Session) CreateUniques(bean interface{}) error { 595 v := rValue(bean) 596 session.Statement.setRefValue(v) 597 598 defer session.resetStatement() 599 if session.IsAutoClose { 600 defer session.Close() 601 } 602 603 sqls := session.Statement.genUniqueSQL() 604 for _, sqlStr := range sqls { 605 _, err := session.exec(sqlStr) 606 if err != nil { 607 return err 608 } 609 } 610 return nil 611 } 612 613 func (session *Session) createOneTable() error { 614 sqlStr := session.Statement.genCreateTableSQL() 615 _, err := session.exec(sqlStr) 616 return err 617 } 618 619 // to be deleted 620 func (session *Session) createAll() error { 621 if session.IsAutoClose { 622 defer session.Close() 623 } 624 625 for _, table := range session.Engine.Tables { 626 session.Statement.RefTable = table 627 session.Statement.tableName = table.Name 628 err := session.createOneTable() 629 session.resetStatement() 630 if err != nil { 631 return err 632 } 633 } 634 return nil 635 } 636 637 // DropIndexes drop indexes 638 func (session *Session) DropIndexes(bean interface{}) error { 639 v := rValue(bean) 640 session.Statement.setRefValue(v) 641 642 defer session.resetStatement() 643 if session.IsAutoClose { 644 defer session.Close() 645 } 646 647 sqls := session.Statement.genDelIndexSQL() 648 for _, sqlStr := range sqls { 649 _, err := session.exec(sqlStr) 650 if err != nil { 651 return err 652 } 653 } 654 return nil 655 } 656 657 // DropTable drop table will drop table if exist, if drop failed, it will return error 658 func (session *Session) DropTable(beanOrTableName interface{}) error { 659 tableName, err := session.Engine.tableName(beanOrTableName) 660 if err != nil { 661 return err 662 } 663 664 var needDrop = true 665 if !session.Engine.dialect.SupportDropIfExists() { 666 sqlStr, args := session.Engine.dialect.TableCheckSql(tableName) 667 results, err := session.query(sqlStr, args...) 668 if err != nil { 669 return err 670 } 671 needDrop = len(results) > 0 672 } 673 674 if needDrop { 675 sqlStr := session.Engine.Dialect().DropTableSql(tableName) 676 _, err = session.exec(sqlStr) 677 return err 678 } 679 return nil 680 } 681 682 func (session *Session) canCache() bool { 683 if session.Statement.RefTable == nil || 684 session.Statement.JoinStr != "" || 685 session.Statement.RawSQL != "" || 686 !session.Statement.UseCache || 687 session.Tx != nil || 688 len(session.Statement.selectStr) > 0 { 689 return false 690 } 691 return true 692 } 693 694 func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interface{}) (has bool, err error) { 695 // if has no reftable, then don't use cache currently 696 if !session.canCache() { 697 return false, ErrCacheFailed 698 } 699 700 for _, filter := range session.Engine.dialect.Filters() { 701 sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) 702 } 703 newsql := session.Statement.convertIDSQL(sqlStr) 704 if newsql == "" { 705 return false, ErrCacheFailed 706 } 707 708 cacher := session.Engine.getCacher2(session.Statement.RefTable) 709 tableName := session.Statement.TableName() 710 session.Engine.logger.Debug("[cacheGet] find sql:", newsql, args) 711 ids, err := core.GetCacheSql(cacher, tableName, newsql, args) 712 table := session.Statement.RefTable 713 if err != nil { 714 var res = make([]string, len(table.PrimaryKeys)) 715 rows, err := session.DB().Query(newsql, args...) 716 if err != nil { 717 return false, err 718 } 719 defer rows.Close() 720 721 if rows.Next() { 722 err = rows.ScanSlice(&res) 723 if err != nil { 724 return false, err 725 } 726 } else { 727 return false, ErrCacheFailed 728 } 729 730 var pk core.PK = make([]interface{}, len(table.PrimaryKeys)) 731 for i, col := range table.PKColumns() { 732 if col.SQLType.IsText() { 733 pk[i] = res[i] 734 } else if col.SQLType.IsNumeric() { 735 n, err := strconv.ParseInt(res[i], 10, 64) 736 if err != nil { 737 return false, err 738 } 739 pk[i] = n 740 } else { 741 return false, errors.New("unsupported") 742 } 743 } 744 745 ids = []core.PK{pk} 746 session.Engine.logger.Debug("[cacheGet] cache ids:", newsql, ids) 747 err = core.PutCacheSql(cacher, ids, tableName, newsql, args) 748 if err != nil { 749 return false, err 750 } 751 } else { 752 session.Engine.logger.Debug("[cacheGet] cache hit sql:", newsql) 753 } 754 755 if len(ids) > 0 { 756 structValue := reflect.Indirect(reflect.ValueOf(bean)) 757 id := ids[0] 758 session.Engine.logger.Debug("[cacheGet] get bean:", tableName, id) 759 sid, err := id.ToString() 760 if err != nil { 761 return false, err 762 } 763 cacheBean := cacher.GetBean(tableName, sid) 764 if cacheBean == nil { 765 /*newSession := session.Engine.NewSession() 766 defer newSession.Close() 767 cacheBean = reflect.New(structValue.Type()).Interface() 768 newSession.Id(id).NoCache() 769 if session.Statement.AltTableName != "" { 770 newSession.Table(session.Statement.AltTableName) 771 } 772 if !session.Statement.UseCascade { 773 newSession.NoCascade() 774 } 775 has, err = newSession.Get(cacheBean) 776 */ 777 cacheBean = bean 778 has, err = session.nocacheGet(cacheBean, sqlStr, args...) 779 if err != nil || !has { 780 return has, err 781 } 782 783 session.Engine.logger.Debug("[cacheGet] cache bean:", tableName, id, cacheBean) 784 cacher.PutBean(tableName, sid, cacheBean) 785 } else { 786 session.Engine.logger.Debug("[cacheGet] cache hit bean:", tableName, id, cacheBean) 787 has = true 788 } 789 structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean))) 790 791 return has, nil 792 } 793 return false, nil 794 } 795 796 func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) { 797 if !session.canCache() || 798 indexNoCase(sqlStr, "having") != -1 || 799 indexNoCase(sqlStr, "group by") != -1 { 800 return ErrCacheFailed 801 } 802 803 for _, filter := range session.Engine.dialect.Filters() { 804 sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) 805 } 806 807 newsql := session.Statement.convertIDSQL(sqlStr) 808 if newsql == "" { 809 return ErrCacheFailed 810 } 811 812 tableName := session.Statement.TableName() 813 814 table := session.Statement.RefTable 815 cacher := session.Engine.getCacher2(table) 816 ids, err := core.GetCacheSql(cacher, tableName, newsql, args) 817 if err != nil { 818 rows, err := session.DB().Query(newsql, args...) 819 if err != nil { 820 return err 821 } 822 defer rows.Close() 823 824 var i int 825 ids = make([]core.PK, 0) 826 for rows.Next() { 827 i++ 828 if i > 500 { 829 session.Engine.logger.Debug("[cacheFind] ids length > 500, no cache") 830 return ErrCacheFailed 831 } 832 var res = make([]string, len(table.PrimaryKeys)) 833 err = rows.ScanSlice(&res) 834 if err != nil { 835 return err 836 } 837 838 var pk core.PK = make([]interface{}, len(table.PrimaryKeys)) 839 for i, col := range table.PKColumns() { 840 if col.SQLType.IsNumeric() { 841 n, err := strconv.ParseInt(res[i], 10, 64) 842 if err != nil { 843 return err 844 } 845 pk[i] = n 846 } else if col.SQLType.IsText() { 847 pk[i] = res[i] 848 } else { 849 return errors.New("not supported") 850 } 851 } 852 853 ids = append(ids, pk) 854 } 855 856 session.Engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, newsql, args) 857 err = core.PutCacheSql(cacher, ids, tableName, newsql, args) 858 if err != nil { 859 return err 860 } 861 } else { 862 session.Engine.logger.Debug("[cacheFind] cache hit sql:", newsql, args) 863 } 864 865 sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) 866 867 ididxes := make(map[string]int) 868 var ides []core.PK 869 var temps = make([]interface{}, len(ids)) 870 871 for idx, id := range ids { 872 sid, err := id.ToString() 873 if err != nil { 874 return err 875 } 876 bean := cacher.GetBean(tableName, sid) 877 if bean == nil { 878 ides = append(ides, id) 879 ididxes[sid] = idx 880 } else { 881 session.Engine.logger.Debug("[cacheFind] cache hit bean:", tableName, id, bean) 882 883 pk := session.Engine.IdOf(bean) 884 xid, err := pk.ToString() 885 if err != nil { 886 return err 887 } 888 889 if sid != xid { 890 session.Engine.logger.Error("[cacheFind] error cache", xid, sid, bean) 891 return ErrCacheFailed 892 } 893 temps[idx] = bean 894 } 895 } 896 897 if len(ides) > 0 { 898 newSession := session.Engine.NewSession() 899 defer newSession.Close() 900 901 slices := reflect.New(reflect.SliceOf(t)) 902 beans := slices.Interface() 903 904 if len(table.PrimaryKeys) == 1 { 905 ff := make([]interface{}, 0, len(ides)) 906 for _, ie := range ides { 907 ff = append(ff, ie[0]) 908 } 909 910 newSession.In("`"+table.PrimaryKeys[0]+"`", ff...) 911 } else { 912 for _, ie := range ides { 913 cond := builder.NewCond() 914 for i, name := range table.PrimaryKeys { 915 cond = cond.And(builder.Eq{"`" + name + "`": ie[i]}) 916 } 917 newSession.Or(cond) 918 } 919 } 920 921 err = newSession.NoCache().Find(beans) 922 if err != nil { 923 return err 924 } 925 926 vs := reflect.Indirect(reflect.ValueOf(beans)) 927 for i := 0; i < vs.Len(); i++ { 928 rv := vs.Index(i) 929 if rv.Kind() != reflect.Ptr { 930 rv = rv.Addr() 931 } 932 id := session.Engine.IdOfV(rv) 933 sid, err := id.ToString() 934 if err != nil { 935 return err 936 } 937 938 bean := rv.Interface() 939 temps[ididxes[sid]] = bean 940 session.Engine.logger.Debug("[cacheFind] cache bean:", tableName, id, bean, temps) 941 cacher.PutBean(tableName, sid, bean) 942 } 943 } 944 945 for j := 0; j < len(temps); j++ { 946 bean := temps[j] 947 if bean == nil { 948 session.Engine.logger.Warn("[cacheFind] cache no hit:", tableName, ids[j], temps) 949 // return errors.New("cache error") // !nashtsai! no need to return error, but continue instead 950 continue 951 } 952 if sliceValue.Kind() == reflect.Slice { 953 if t.Kind() == reflect.Ptr { 954 sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean))) 955 } else { 956 sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean)))) 957 } 958 } else if sliceValue.Kind() == reflect.Map { 959 var key = ids[j] 960 keyType := sliceValue.Type().Key() 961 var ikey interface{} 962 if len(key) == 1 { 963 ikey, err = str2PK(fmt.Sprintf("%v", key[0]), keyType) 964 if err != nil { 965 return err 966 } 967 } else { 968 if keyType.Kind() != reflect.Slice { 969 return errors.New("table have multiple primary keys, key is not core.PK or slice") 970 } 971 ikey = key 972 } 973 974 if t.Kind() == reflect.Ptr { 975 sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean)) 976 } else { 977 sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean))) 978 } 979 } 980 } 981 982 return nil 983 } 984 985 // IterFunc only use by Iterate 986 type IterFunc func(idx int, bean interface{}) error 987 988 // Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields 989 // are conditions. 990 func (session *Session) Rows(bean interface{}) (*Rows, error) { 991 return newRows(session, bean) 992 } 993 994 // Iterate record by record handle records from table, condiBeans's non-empty fields 995 // are conditions. beans could be []Struct, []*Struct, map[int64]Struct 996 // map[int64]*Struct 997 func (session *Session) Iterate(bean interface{}, fun IterFunc) error { 998 rows, err := session.Rows(bean) 999 if err != nil { 1000 return err 1001 } 1002 defer rows.Close() 1003 1004 i := 0 1005 for rows.Next() { 1006 b := reflect.New(rows.beanType).Interface() 1007 err = rows.Scan(b) 1008 if err != nil { 1009 return err 1010 } 1011 err = fun(i, b) 1012 if err != nil { 1013 return err 1014 } 1015 i++ 1016 } 1017 return err 1018 } 1019 1020 func (session *Session) doPrepare(sqlStr string) (stmt *core.Stmt, err error) { 1021 crc := crc32.ChecksumIEEE([]byte(sqlStr)) 1022 // TODO try hash(sqlStr+len(sqlStr)) 1023 var has bool 1024 stmt, has = session.stmtCache[crc] 1025 if !has { 1026 stmt, err = session.DB().Prepare(sqlStr) 1027 if err != nil { 1028 return nil, err 1029 } 1030 session.stmtCache[crc] = stmt 1031 } 1032 return 1033 } 1034 1035 func (session *Session) nocacheGet(bean interface{}, sqlStr string, args ...interface{}) (bool, error) { 1036 var rawRows *core.Rows 1037 var err error 1038 session.queryPreprocess(&sqlStr, args...) 1039 if session.IsAutoCommit { 1040 _, rawRows, err = session.innerQuery(sqlStr, args...) 1041 } else { 1042 rawRows, err = session.Tx.Query(sqlStr, args...) 1043 } 1044 if err != nil { 1045 return false, err 1046 } 1047 1048 defer rawRows.Close() 1049 1050 if rawRows.Next() { 1051 if fields, err := rawRows.Columns(); err == nil { 1052 err = session.row2Bean(rawRows, fields, len(fields), bean) 1053 } 1054 return true, err 1055 } 1056 return false, nil 1057 } 1058 1059 // Get retrieve one record from database, bean's non-empty fields 1060 // will be as conditions 1061 func (session *Session) Get(bean interface{}) (bool, error) { 1062 defer session.resetStatement() 1063 if session.IsAutoClose { 1064 defer session.Close() 1065 } 1066 1067 session.Statement.setRefValue(rValue(bean)) 1068 1069 var sqlStr string 1070 var args []interface{} 1071 1072 if session.Statement.RawSQL == "" { 1073 if len(session.Statement.TableName()) <= 0 { 1074 return false, ErrTableNotFound 1075 } 1076 session.Statement.Limit(1) 1077 sqlStr, args = session.Statement.genGetSQL(bean) 1078 } else { 1079 sqlStr = session.Statement.RawSQL 1080 args = session.Statement.RawParams 1081 } 1082 1083 if session.canCache() { 1084 if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && 1085 !session.Statement.unscoped { 1086 has, err := session.cacheGet(bean, sqlStr, args...) 1087 if err != ErrCacheFailed { 1088 return has, err 1089 } 1090 } 1091 } 1092 1093 return session.nocacheGet(bean, sqlStr, args...) 1094 } 1095 1096 // Count counts the records. bean's non-empty fields 1097 // are conditions. 1098 func (session *Session) Count(bean interface{}) (int64, error) { 1099 defer session.resetStatement() 1100 if session.IsAutoClose { 1101 defer session.Close() 1102 } 1103 1104 var sqlStr string 1105 var args []interface{} 1106 if session.Statement.RawSQL == "" { 1107 sqlStr, args = session.Statement.genCountSQL(bean) 1108 } else { 1109 sqlStr = session.Statement.RawSQL 1110 args = session.Statement.RawParams 1111 } 1112 1113 session.queryPreprocess(&sqlStr, args...) 1114 1115 var err error 1116 var total int64 1117 if session.IsAutoCommit { 1118 err = session.DB().QueryRow(sqlStr, args...).Scan(&total) 1119 } else { 1120 err = session.Tx.QueryRow(sqlStr, args...).Scan(&total) 1121 } 1122 1123 if err == sql.ErrNoRows || err == nil { 1124 return total, nil 1125 } 1126 1127 return 0, err 1128 } 1129 1130 // Sum call sum some column. bean's non-empty fields are conditions. 1131 func (session *Session) Sum(bean interface{}, columnName string) (float64, error) { 1132 defer session.resetStatement() 1133 if session.IsAutoClose { 1134 defer session.Close() 1135 } 1136 1137 var sqlStr string 1138 var args []interface{} 1139 if len(session.Statement.RawSQL) == 0 { 1140 sqlStr, args = session.Statement.genSumSQL(bean, columnName) 1141 } else { 1142 sqlStr = session.Statement.RawSQL 1143 args = session.Statement.RawParams 1144 } 1145 1146 session.queryPreprocess(&sqlStr, args...) 1147 1148 var err error 1149 var res float64 1150 if session.IsAutoCommit { 1151 err = session.DB().QueryRow(sqlStr, args...).Scan(&res) 1152 } else { 1153 err = session.Tx.QueryRow(sqlStr, args...).Scan(&res) 1154 } 1155 1156 if err == sql.ErrNoRows || err == nil { 1157 return res, nil 1158 } 1159 return 0, err 1160 } 1161 1162 // Sums call sum some columns. bean's non-empty fields are conditions. 1163 func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) { 1164 defer session.resetStatement() 1165 if session.IsAutoClose { 1166 defer session.Close() 1167 } 1168 1169 var sqlStr string 1170 var args []interface{} 1171 if len(session.Statement.RawSQL) == 0 { 1172 sqlStr, args = session.Statement.genSumSQL(bean, columnNames...) 1173 } else { 1174 sqlStr = session.Statement.RawSQL 1175 args = session.Statement.RawParams 1176 } 1177 1178 session.queryPreprocess(&sqlStr, args...) 1179 1180 var err error 1181 var res = make([]float64, len(columnNames), len(columnNames)) 1182 if session.IsAutoCommit { 1183 err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res) 1184 } else { 1185 err = session.Tx.QueryRow(sqlStr, args...).ScanSlice(&res) 1186 } 1187 1188 if err == sql.ErrNoRows || err == nil { 1189 return res, nil 1190 } 1191 return nil, err 1192 } 1193 1194 // SumsInt sum specify columns and return as []int64 instead of []float64 1195 func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) { 1196 defer session.resetStatement() 1197 if session.IsAutoClose { 1198 defer session.Close() 1199 } 1200 1201 var sqlStr string 1202 var args []interface{} 1203 if len(session.Statement.RawSQL) == 0 { 1204 sqlStr, args = session.Statement.genSumSQL(bean, columnNames...) 1205 } else { 1206 sqlStr = session.Statement.RawSQL 1207 args = session.Statement.RawParams 1208 } 1209 1210 session.queryPreprocess(&sqlStr, args...) 1211 1212 var err error 1213 var res = make([]int64, 0, len(columnNames)) 1214 if session.IsAutoCommit { 1215 err = session.DB().QueryRow(sqlStr, args...).ScanSlice(&res) 1216 } else { 1217 err = session.Tx.QueryRow(sqlStr, args...).ScanSlice(&res) 1218 } 1219 1220 if err == sql.ErrNoRows || err == nil { 1221 return res, nil 1222 } 1223 return nil, err 1224 } 1225 1226 func (session *Session) noCacheFind(sliceValue reflect.Value, sqlStr string, args ...interface{}) error { 1227 var rawRows *core.Rows 1228 var err error 1229 1230 session.queryPreprocess(&sqlStr, args...) 1231 if session.IsAutoCommit { 1232 _, rawRows, err = session.innerQuery(sqlStr, args...) 1233 } else { 1234 rawRows, err = session.Tx.Query(sqlStr, args...) 1235 } 1236 if err != nil { 1237 return err 1238 } 1239 defer rawRows.Close() 1240 1241 fields, err := rawRows.Columns() 1242 if err != nil { 1243 return err 1244 } 1245 1246 var newElemFunc func() reflect.Value 1247 sliceElementType := sliceValue.Type().Elem() 1248 if sliceElementType.Kind() == reflect.Ptr { 1249 newElemFunc = func() reflect.Value { 1250 return reflect.New(sliceElementType.Elem()) 1251 } 1252 } else { 1253 newElemFunc = func() reflect.Value { 1254 return reflect.New(sliceElementType) 1255 } 1256 } 1257 1258 var sliceValueSetFunc func(*reflect.Value) 1259 1260 if sliceValue.Kind() == reflect.Slice { 1261 if sliceElementType.Kind() == reflect.Ptr { 1262 sliceValueSetFunc = func(newValue *reflect.Value) { 1263 sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(newValue.Interface()))) 1264 } 1265 } else { 1266 sliceValueSetFunc = func(newValue *reflect.Value) { 1267 sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(newValue.Interface())))) 1268 } 1269 } 1270 } 1271 1272 var newValue = newElemFunc() 1273 dataStruct := rValue(newValue.Interface()) 1274 if dataStruct.Kind() != reflect.Struct { 1275 return errors.New("Expected a pointer to a struct") 1276 } 1277 1278 return session.rows2Beans(rawRows, fields, len(fields), session.Engine.autoMapType(dataStruct), newElemFunc, sliceValueSetFunc) 1279 } 1280 1281 // Find retrieve records from table, condiBeans's non-empty fields 1282 // are conditions. beans could be []Struct, []*Struct, map[int64]Struct 1283 // map[int64]*Struct 1284 func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error { 1285 defer session.resetStatement() 1286 if session.IsAutoClose { 1287 defer session.Close() 1288 } 1289 1290 sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) 1291 if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map { 1292 return errors.New("needs a pointer to a slice or a map") 1293 } 1294 1295 sliceElementType := sliceValue.Type().Elem() 1296 1297 if session.Statement.RefTable == nil { 1298 if sliceElementType.Kind() == reflect.Ptr { 1299 if sliceElementType.Elem().Kind() == reflect.Struct { 1300 pv := reflect.New(sliceElementType.Elem()) 1301 session.Statement.setRefValue(pv.Elem()) 1302 } else { 1303 return errors.New("slice type") 1304 } 1305 } else if sliceElementType.Kind() == reflect.Struct { 1306 pv := reflect.New(sliceElementType) 1307 session.Statement.setRefValue(pv.Elem()) 1308 } else { 1309 return errors.New("slice type") 1310 } 1311 } 1312 1313 var table = session.Statement.RefTable 1314 1315 var addedTableName = (len(session.Statement.JoinStr) > 0) 1316 var autoCond builder.Cond 1317 if !session.Statement.noAutoCondition && len(condiBean) > 0 { 1318 var err error 1319 autoCond, err = session.Statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName) 1320 if err != nil { 1321 panic(err) 1322 } 1323 } else { 1324 // !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given. 1325 // See https://yougam/libraries/xorm/issues/179 1326 if col := table.DeletedColumn(); col != nil && !session.Statement.unscoped { // tag "deleted" is enabled 1327 var colName = session.Engine.Quote(col.Name) 1328 if addedTableName { 1329 var nm = session.Statement.TableName() 1330 if len(session.Statement.TableAlias) > 0 { 1331 nm = session.Statement.TableAlias 1332 } 1333 colName = session.Engine.Quote(nm) + "." + colName 1334 } 1335 autoCond = builder.IsNull{colName}.Or(builder.Eq{colName: "0001-01-01 00:00:00"}) 1336 } 1337 } 1338 1339 var sqlStr string 1340 var args []interface{} 1341 if session.Statement.RawSQL == "" { 1342 if len(session.Statement.TableName()) <= 0 { 1343 return ErrTableNotFound 1344 } 1345 1346 var columnStr = session.Statement.ColumnStr 1347 if len(session.Statement.selectStr) > 0 { 1348 columnStr = session.Statement.selectStr 1349 } else { 1350 if session.Statement.JoinStr == "" { 1351 if columnStr == "" { 1352 if session.Statement.GroupByStr != "" { 1353 columnStr = session.Statement.Engine.Quote(strings.Replace(session.Statement.GroupByStr, ",", session.Engine.Quote(","), -1)) 1354 } else { 1355 columnStr = session.Statement.genColumnStr() 1356 } 1357 } 1358 } else { 1359 if columnStr == "" { 1360 if session.Statement.GroupByStr != "" { 1361 columnStr = session.Statement.Engine.Quote(strings.Replace(session.Statement.GroupByStr, ",", session.Engine.Quote(","), -1)) 1362 } else { 1363 columnStr = "*" 1364 } 1365 } 1366 } 1367 } 1368 1369 condSQL, condArgs, _ := builder.ToSQL(session.Statement.cond.And(autoCond)) 1370 1371 args = append(session.Statement.joinArgs, condArgs...) 1372 sqlStr = session.Statement.genSelectSQL(columnStr, condSQL) 1373 // for mssql and use limit 1374 qs := strings.Count(sqlStr, "?") 1375 if len(args)*2 == qs { 1376 args = append(args, args...) 1377 } 1378 } else { 1379 sqlStr = session.Statement.RawSQL 1380 args = session.Statement.RawParams 1381 } 1382 1383 var err error 1384 if session.canCache() { 1385 if cacher := session.Engine.getCacher2(table); cacher != nil && 1386 !session.Statement.IsDistinct && 1387 !session.Statement.unscoped { 1388 err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...) 1389 if err != ErrCacheFailed { 1390 return err 1391 } 1392 err = nil // !nashtsai! reset err to nil for ErrCacheFailed 1393 session.Engine.logger.Warn("Cache Find Failed") 1394 } 1395 } 1396 1397 if sliceValue.Kind() != reflect.Map { 1398 return session.noCacheFind(sliceValue, sqlStr, args...) 1399 } 1400 1401 resultsSlice, err := session.query(sqlStr, args...) 1402 if err != nil { 1403 return err 1404 } 1405 1406 keyType := sliceValue.Type().Key() 1407 1408 for _, results := range resultsSlice { 1409 var newValue reflect.Value 1410 if sliceElementType.Kind() == reflect.Ptr { 1411 newValue = reflect.New(sliceElementType.Elem()) 1412 } else { 1413 newValue = reflect.New(sliceElementType) 1414 } 1415 err := session.scanMapIntoStruct(newValue.Interface(), results) 1416 if err != nil { 1417 return err 1418 } 1419 var key interface{} 1420 // if there is only one pk, we can put the id as map key. 1421 if len(table.PrimaryKeys) == 1 { 1422 key, err = str2PK(string(results[table.PrimaryKeys[0]]), keyType) 1423 if err != nil { 1424 return err 1425 } 1426 } else { 1427 if keyType.Kind() != reflect.Slice { 1428 panic("don't support multiple primary key's map has non-slice key type") 1429 } else { 1430 var keys core.PK = make([]interface{}, 0, len(table.PrimaryKeys)) 1431 for _, pk := range table.PrimaryKeys { 1432 skey, err := str2PK(string(results[pk]), keyType) 1433 if err != nil { 1434 return err 1435 } 1436 keys = append(keys, skey) 1437 } 1438 key = keys 1439 } 1440 } 1441 1442 if sliceElementType.Kind() == reflect.Ptr { 1443 sliceValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(newValue.Interface())) 1444 } else { 1445 sliceValue.SetMapIndex(reflect.ValueOf(key), reflect.Indirect(reflect.ValueOf(newValue.Interface()))) 1446 } 1447 } 1448 1449 return nil 1450 } 1451 1452 // Ping test if database is ok 1453 func (session *Session) Ping() error { 1454 defer session.resetStatement() 1455 if session.IsAutoClose { 1456 defer session.Close() 1457 } 1458 1459 return session.DB().Ping() 1460 } 1461 1462 // IsTableExist if a table is exist 1463 func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) { 1464 tableName, err := session.Engine.tableName(beanOrTableName) 1465 if err != nil { 1466 return false, err 1467 } 1468 1469 return session.isTableExist(tableName) 1470 } 1471 1472 func (session *Session) isTableExist(tableName string) (bool, error) { 1473 defer session.resetStatement() 1474 if session.IsAutoClose { 1475 defer session.Close() 1476 } 1477 sqlStr, args := session.Engine.dialect.TableCheckSql(tableName) 1478 results, err := session.query(sqlStr, args...) 1479 return len(results) > 0, err 1480 } 1481 1482 // IsTableEmpty if table have any records 1483 func (session *Session) IsTableEmpty(bean interface{}) (bool, error) { 1484 v := rValue(bean) 1485 t := v.Type() 1486 1487 if t.Kind() == reflect.String { 1488 return session.isTableEmpty(bean.(string)) 1489 } else if t.Kind() == reflect.Struct { 1490 rows, err := session.Count(bean) 1491 return rows == 0, err 1492 } 1493 return false, errors.New("bean should be a struct or struct's point") 1494 } 1495 1496 func (session *Session) isTableEmpty(tableName string) (bool, error) { 1497 defer session.resetStatement() 1498 if session.IsAutoClose { 1499 defer session.Close() 1500 } 1501 1502 var total int64 1503 sqlStr := fmt.Sprintf("select count(*) from %s", session.Engine.Quote(tableName)) 1504 err := session.DB().QueryRow(sqlStr).Scan(&total) 1505 session.saveLastSQL(sqlStr) 1506 if err != nil { 1507 if err == sql.ErrNoRows { 1508 err = nil 1509 } 1510 return true, err 1511 } 1512 1513 return total == 0, nil 1514 } 1515 1516 func (session *Session) isIndexExist(tableName, idxName string, unique bool) (bool, error) { 1517 defer session.resetStatement() 1518 if session.IsAutoClose { 1519 defer session.Close() 1520 } 1521 var idx string 1522 if unique { 1523 idx = uniqueName(tableName, idxName) 1524 } else { 1525 idx = indexName(tableName, idxName) 1526 } 1527 sqlStr, args := session.Engine.dialect.IndexCheckSql(tableName, idx) 1528 results, err := session.query(sqlStr, args...) 1529 return len(results) > 0, err 1530 } 1531 1532 // find if index is exist according cols 1533 func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) { 1534 defer session.resetStatement() 1535 if session.IsAutoClose { 1536 defer session.Close() 1537 } 1538 1539 indexes, err := session.Engine.dialect.GetIndexes(tableName) 1540 if err != nil { 1541 return false, err 1542 } 1543 1544 for _, index := range indexes { 1545 if sliceEq(index.Cols, cols) { 1546 if unique { 1547 return index.Type == core.UniqueType, nil 1548 } 1549 return index.Type == core.IndexType, nil 1550 } 1551 } 1552 return false, nil 1553 } 1554 1555 func (session *Session) addColumn(colName string) error { 1556 defer session.resetStatement() 1557 if session.IsAutoClose { 1558 defer session.Close() 1559 } 1560 1561 col := session.Statement.RefTable.GetColumn(colName) 1562 sql, args := session.Statement.genAddColumnStr(col) 1563 _, err := session.exec(sql, args...) 1564 return err 1565 } 1566 1567 func (session *Session) addIndex(tableName, idxName string) error { 1568 defer session.resetStatement() 1569 if session.IsAutoClose { 1570 defer session.Close() 1571 } 1572 index := session.Statement.RefTable.Indexes[idxName] 1573 sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index) 1574 1575 _, err := session.exec(sqlStr) 1576 return err 1577 } 1578 1579 func (session *Session) addUnique(tableName, uqeName string) error { 1580 defer session.resetStatement() 1581 if session.IsAutoClose { 1582 defer session.Close() 1583 } 1584 index := session.Statement.RefTable.Indexes[uqeName] 1585 sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index) 1586 _, err := session.exec(sqlStr) 1587 return err 1588 } 1589 1590 // To be deleted 1591 func (session *Session) dropAll() error { 1592 defer session.resetStatement() 1593 if session.IsAutoClose { 1594 defer session.Close() 1595 } 1596 1597 for _, table := range session.Engine.Tables { 1598 session.Statement.Init() 1599 session.Statement.RefTable = table 1600 sqlStr := session.Engine.Dialect().DropTableSql(session.Statement.TableName()) 1601 _, err := session.exec(sqlStr) 1602 if err != nil { 1603 return err 1604 } 1605 } 1606 return nil 1607 } 1608 1609 func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) *reflect.Value { 1610 var col *core.Column 1611 if col = table.GetColumnIdx(key, idx); col == nil { 1612 //session.Engine.logger.Warnf("table %v has no column %v. %v", table.Name, key, table.ColumnsSeq()) 1613 return nil 1614 } 1615 1616 fieldValue, err := col.ValueOfV(dataStruct) 1617 if err != nil { 1618 session.Engine.logger.Error(err) 1619 return nil 1620 } 1621 1622 if !fieldValue.IsValid() || !fieldValue.CanSet() { 1623 session.Engine.logger.Warnf("table %v's column %v is not valid or cannot set", table.Name, key) 1624 return nil 1625 } 1626 return fieldValue 1627 } 1628 1629 // Cell cell is a result of one column field 1630 type Cell *interface{} 1631 1632 func (session *Session) rows2Beans(rows *core.Rows, fields []string, fieldsCount int, 1633 table *core.Table, newElemFunc func() reflect.Value, 1634 sliceValueSetFunc func(*reflect.Value)) error { 1635 for rows.Next() { 1636 var newValue = newElemFunc() 1637 bean := newValue.Interface() 1638 dataStruct := rValue(bean) 1639 err := session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table) 1640 if err != nil { 1641 return err 1642 } 1643 sliceValueSetFunc(&newValue) 1644 } 1645 return nil 1646 } 1647 1648 func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error { 1649 dataStruct := rValue(bean) 1650 if dataStruct.Kind() != reflect.Struct { 1651 return errors.New("Expected a pointer to a struct") 1652 } 1653 1654 session.Statement.setRefValue(dataStruct) 1655 1656 return session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, session.Statement.RefTable) 1657 } 1658 1659 func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) error { 1660 scanResults := make([]interface{}, fieldsCount) 1661 for i := 0; i < len(fields); i++ { 1662 var cell interface{} 1663 scanResults[i] = &cell 1664 } 1665 if err := rows.Scan(scanResults...); err != nil { 1666 return err 1667 } 1668 1669 if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet { 1670 for ii, key := range fields { 1671 b.BeforeSet(key, Cell(scanResults[ii].(*interface{}))) 1672 } 1673 } 1674 1675 defer func() { 1676 if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet { 1677 for ii, key := range fields { 1678 b.AfterSet(key, Cell(scanResults[ii].(*interface{}))) 1679 } 1680 } 1681 }() 1682 1683 var tempMap = make(map[string]int) 1684 for ii, key := range fields { 1685 var idx int 1686 var ok bool 1687 var lKey = strings.ToLower(key) 1688 if idx, ok = tempMap[lKey]; !ok { 1689 idx = 0 1690 } else { 1691 idx = idx + 1 1692 } 1693 tempMap[lKey] = idx 1694 1695 if fieldValue := session.getField(dataStruct, key, table, idx); fieldValue != nil { 1696 rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii])) 1697 1698 // if row is null then ignore 1699 if rawValue.Interface() == nil { 1700 continue 1701 } 1702 1703 if fieldValue.CanAddr() { 1704 if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { 1705 if data, err := value2Bytes(&rawValue); err == nil { 1706 structConvert.FromDB(data) 1707 } else { 1708 session.Engine.logger.Error(err) 1709 } 1710 continue 1711 } 1712 } 1713 1714 if _, ok := fieldValue.Interface().(core.Conversion); ok { 1715 if data, err := value2Bytes(&rawValue); err == nil { 1716 if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() { 1717 fieldValue.Set(reflect.New(fieldValue.Type().Elem())) 1718 } 1719 fieldValue.Interface().(core.Conversion).FromDB(data) 1720 } else { 1721 session.Engine.logger.Error(err) 1722 } 1723 continue 1724 } 1725 1726 rawValueType := reflect.TypeOf(rawValue.Interface()) 1727 vv := reflect.ValueOf(rawValue.Interface()) 1728 1729 fieldType := fieldValue.Type() 1730 hasAssigned := false 1731 col := table.GetColumnIdx(key, idx) 1732 1733 if col.SQLType.IsJson() { 1734 var bs []byte 1735 if rawValueType.Kind() == reflect.String { 1736 bs = []byte(vv.String()) 1737 } else if rawValueType.ConvertibleTo(core.BytesType) { 1738 bs = vv.Bytes() 1739 } else { 1740 return fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind()) 1741 } 1742 1743 hasAssigned = true 1744 1745 if len(bs) > 0 { 1746 if fieldValue.CanAddr() { 1747 err := json.Unmarshal(bs, fieldValue.Addr().Interface()) 1748 if err != nil { 1749 session.Engine.logger.Error(key, err) 1750 return err 1751 } 1752 } else { 1753 x := reflect.New(fieldType) 1754 err := json.Unmarshal(bs, x.Interface()) 1755 if err != nil { 1756 session.Engine.logger.Error(key, err) 1757 return err 1758 } 1759 fieldValue.Set(x.Elem()) 1760 } 1761 } 1762 1763 continue 1764 } 1765 1766 switch fieldType.Kind() { 1767 case reflect.Complex64, reflect.Complex128: 1768 // TODO: reimplement this 1769 var bs []byte 1770 if rawValueType.Kind() == reflect.String { 1771 bs = []byte(vv.String()) 1772 } else if rawValueType.ConvertibleTo(core.BytesType) { 1773 bs = vv.Bytes() 1774 } 1775 1776 hasAssigned = true 1777 if len(bs) > 0 { 1778 if fieldValue.CanAddr() { 1779 err := json.Unmarshal(bs, fieldValue.Addr().Interface()) 1780 if err != nil { 1781 session.Engine.logger.Error(err) 1782 return err 1783 } 1784 } else { 1785 x := reflect.New(fieldType) 1786 err := json.Unmarshal(bs, x.Interface()) 1787 if err != nil { 1788 session.Engine.logger.Error(err) 1789 return err 1790 } 1791 fieldValue.Set(x.Elem()) 1792 } 1793 } 1794 case reflect.Slice, reflect.Array: 1795 switch rawValueType.Kind() { 1796 case reflect.Slice, reflect.Array: 1797 switch rawValueType.Elem().Kind() { 1798 case reflect.Uint8: 1799 if fieldType.Elem().Kind() == reflect.Uint8 { 1800 hasAssigned = true 1801 fieldValue.Set(vv) 1802 } 1803 } 1804 } 1805 case reflect.String: 1806 if rawValueType.Kind() == reflect.String { 1807 hasAssigned = true 1808 fieldValue.SetString(vv.String()) 1809 } 1810 case reflect.Bool: 1811 if rawValueType.Kind() == reflect.Bool { 1812 hasAssigned = true 1813 fieldValue.SetBool(vv.Bool()) 1814 } 1815 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1816 switch rawValueType.Kind() { 1817 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1818 hasAssigned = true 1819 fieldValue.SetInt(vv.Int()) 1820 } 1821 case reflect.Float32, reflect.Float64: 1822 switch rawValueType.Kind() { 1823 case reflect.Float32, reflect.Float64: 1824 hasAssigned = true 1825 fieldValue.SetFloat(vv.Float()) 1826 } 1827 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 1828 switch rawValueType.Kind() { 1829 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 1830 hasAssigned = true 1831 fieldValue.SetUint(vv.Uint()) 1832 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1833 hasAssigned = true 1834 fieldValue.SetUint(uint64(vv.Int())) 1835 } 1836 case reflect.Struct: 1837 if fieldType.ConvertibleTo(core.TimeType) { 1838 if rawValueType == core.TimeType { 1839 hasAssigned = true 1840 1841 t := vv.Convert(core.TimeType).Interface().(time.Time) 1842 z, _ := t.Zone() 1843 if len(z) == 0 || t.Year() == 0 { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location 1844 dbTZ := session.Engine.DatabaseTZ 1845 if dbTZ == nil { 1846 dbTZ = time.Local 1847 } 1848 session.Engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location()) 1849 t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 1850 t.Minute(), t.Second(), t.Nanosecond(), dbTZ) 1851 } 1852 // !nashtsai! convert to engine location 1853 if col.TimeZone == nil { 1854 t = t.In(session.Engine.TZLocation) 1855 } else { 1856 t = t.In(col.TimeZone) 1857 } 1858 fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) 1859 1860 // t = fieldValue.Interface().(time.Time) 1861 // z, _ = t.Zone() 1862 // session.Engine.LogDebug("fieldValue key[%v]: %v | zone: %v | location: %+v\n", key, t, z, *t.Location()) 1863 } else if rawValueType == core.IntType || rawValueType == core.Int64Type || 1864 rawValueType == core.Int32Type { 1865 hasAssigned = true 1866 var tz *time.Location 1867 if col.TimeZone == nil { 1868 tz = session.Engine.TZLocation 1869 } else { 1870 tz = col.TimeZone 1871 } 1872 t := time.Unix(vv.Int(), 0).In(tz) 1873 //vv = reflect.ValueOf(t) 1874 fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) 1875 } else { 1876 if d, ok := vv.Interface().([]uint8); ok { 1877 hasAssigned = true 1878 t, err := session.byte2Time(col, d) 1879 if err != nil { 1880 session.Engine.logger.Error("byte2Time error:", err.Error()) 1881 hasAssigned = false 1882 } else { 1883 fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) 1884 } 1885 } else if d, ok := vv.Interface().(string); ok { 1886 hasAssigned = true 1887 t, err := session.str2Time(col, d) 1888 if err != nil { 1889 session.Engine.logger.Error("byte2Time error:", err.Error()) 1890 hasAssigned = false 1891 } else { 1892 fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) 1893 } 1894 } else { 1895 panic(fmt.Sprintf("rawValueType is %v, value is %v", rawValueType, vv.Interface())) 1896 } 1897 } 1898 } else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { 1899 // !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString 1900 hasAssigned = true 1901 if err := nulVal.Scan(vv.Interface()); err != nil { 1902 session.Engine.logger.Error("sql.Sanner error:", err.Error()) 1903 hasAssigned = false 1904 } 1905 } else if col.SQLType.IsJson() { 1906 if rawValueType.Kind() == reflect.String { 1907 hasAssigned = true 1908 x := reflect.New(fieldType) 1909 if len([]byte(vv.String())) > 0 { 1910 err := json.Unmarshal([]byte(vv.String()), x.Interface()) 1911 if err != nil { 1912 session.Engine.logger.Error(err) 1913 return err 1914 } 1915 fieldValue.Set(x.Elem()) 1916 } 1917 } else if rawValueType.Kind() == reflect.Slice { 1918 hasAssigned = true 1919 x := reflect.New(fieldType) 1920 if len(vv.Bytes()) > 0 { 1921 err := json.Unmarshal(vv.Bytes(), x.Interface()) 1922 if err != nil { 1923 session.Engine.logger.Error(err) 1924 return err 1925 } 1926 fieldValue.Set(x.Elem()) 1927 } 1928 } 1929 } else if session.Statement.UseCascade { 1930 table := session.Engine.autoMapType(*fieldValue) 1931 if table != nil { 1932 hasAssigned = true 1933 if len(table.PrimaryKeys) != 1 { 1934 panic("unsupported non or composited primary key cascade") 1935 } 1936 var pk = make(core.PK, len(table.PrimaryKeys)) 1937 1938 switch rawValueType.Kind() { 1939 case reflect.Int64: 1940 pk[0] = vv.Int() 1941 case reflect.Int: 1942 pk[0] = int(vv.Int()) 1943 case reflect.Int32: 1944 pk[0] = int32(vv.Int()) 1945 case reflect.Int16: 1946 pk[0] = int16(vv.Int()) 1947 case reflect.Int8: 1948 pk[0] = int8(vv.Int()) 1949 case reflect.Uint64: 1950 pk[0] = vv.Uint() 1951 case reflect.Uint: 1952 pk[0] = uint(vv.Uint()) 1953 case reflect.Uint32: 1954 pk[0] = uint32(vv.Uint()) 1955 case reflect.Uint16: 1956 pk[0] = uint16(vv.Uint()) 1957 case reflect.Uint8: 1958 pk[0] = uint8(vv.Uint()) 1959 case reflect.String: 1960 pk[0] = vv.String() 1961 case reflect.Slice: 1962 pk[0], _ = strconv.ParseInt(string(rawValue.Interface().([]byte)), 10, 64) 1963 default: 1964 panic(fmt.Sprintf("unsupported primary key type: %v, %v", rawValueType, fieldValue)) 1965 } 1966 1967 if !isPKZero(pk) { 1968 // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch 1969 // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne 1970 // property to be fetched lazily 1971 structInter := reflect.New(fieldValue.Type()) 1972 newsession := session.Engine.NewSession() 1973 defer newsession.Close() 1974 has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) 1975 if err != nil { 1976 return err 1977 } 1978 if has { 1979 //v := structInter.Elem().Interface() 1980 //fieldValue.Set(reflect.ValueOf(v)) 1981 fieldValue.Set(structInter.Elem()) 1982 } else { 1983 return errors.New("cascade obj is not exist") 1984 } 1985 } 1986 } else { 1987 session.Engine.logger.Error("unsupported struct type in Scan: ", fieldValue.Type().String()) 1988 } 1989 } 1990 case reflect.Ptr: 1991 // !nashtsai! TODO merge duplicated codes above 1992 //typeStr := fieldType.String() 1993 switch fieldType { 1994 // following types case matching ptr's native type, therefore assign ptr directly 1995 case core.PtrStringType: 1996 if rawValueType.Kind() == reflect.String { 1997 x := vv.String() 1998 hasAssigned = true 1999 fieldValue.Set(reflect.ValueOf(&x)) 2000 } 2001 case core.PtrBoolType: 2002 if rawValueType.Kind() == reflect.Bool { 2003 x := vv.Bool() 2004 hasAssigned = true 2005 fieldValue.Set(reflect.ValueOf(&x)) 2006 } 2007 case core.PtrTimeType: 2008 if rawValueType == core.PtrTimeType { 2009 hasAssigned = true 2010 var x = rawValue.Interface().(time.Time) 2011 fieldValue.Set(reflect.ValueOf(&x)) 2012 } 2013 case core.PtrFloat64Type: 2014 if rawValueType.Kind() == reflect.Float64 { 2015 x := vv.Float() 2016 hasAssigned = true 2017 fieldValue.Set(reflect.ValueOf(&x)) 2018 } 2019 case core.PtrUint64Type: 2020 if rawValueType.Kind() == reflect.Int64 { 2021 var x = uint64(vv.Int()) 2022 hasAssigned = true 2023 fieldValue.Set(reflect.ValueOf(&x)) 2024 } 2025 case core.PtrInt64Type: 2026 if rawValueType.Kind() == reflect.Int64 { 2027 x := vv.Int() 2028 hasAssigned = true 2029 fieldValue.Set(reflect.ValueOf(&x)) 2030 } 2031 case core.PtrFloat32Type: 2032 if rawValueType.Kind() == reflect.Float64 { 2033 var x = float32(vv.Float()) 2034 hasAssigned = true 2035 fieldValue.Set(reflect.ValueOf(&x)) 2036 } 2037 case core.PtrIntType: 2038 if rawValueType.Kind() == reflect.Int64 { 2039 var x = int(vv.Int()) 2040 hasAssigned = true 2041 fieldValue.Set(reflect.ValueOf(&x)) 2042 } 2043 case core.PtrInt32Type: 2044 if rawValueType.Kind() == reflect.Int64 { 2045 var x = int32(vv.Int()) 2046 hasAssigned = true 2047 fieldValue.Set(reflect.ValueOf(&x)) 2048 } 2049 case core.PtrInt8Type: 2050 if rawValueType.Kind() == reflect.Int64 { 2051 var x = int8(vv.Int()) 2052 hasAssigned = true 2053 fieldValue.Set(reflect.ValueOf(&x)) 2054 } 2055 case core.PtrInt16Type: 2056 if rawValueType.Kind() == reflect.Int64 { 2057 var x = int16(vv.Int()) 2058 hasAssigned = true 2059 fieldValue.Set(reflect.ValueOf(&x)) 2060 } 2061 case core.PtrUintType: 2062 if rawValueType.Kind() == reflect.Int64 { 2063 var x = uint(vv.Int()) 2064 hasAssigned = true 2065 fieldValue.Set(reflect.ValueOf(&x)) 2066 } 2067 case core.PtrUint32Type: 2068 if rawValueType.Kind() == reflect.Int64 { 2069 var x = uint32(vv.Int()) 2070 hasAssigned = true 2071 fieldValue.Set(reflect.ValueOf(&x)) 2072 } 2073 case core.Uint8Type: 2074 if rawValueType.Kind() == reflect.Int64 { 2075 var x = uint8(vv.Int()) 2076 hasAssigned = true 2077 fieldValue.Set(reflect.ValueOf(&x)) 2078 } 2079 case core.Uint16Type: 2080 if rawValueType.Kind() == reflect.Int64 { 2081 var x = uint16(vv.Int()) 2082 hasAssigned = true 2083 fieldValue.Set(reflect.ValueOf(&x)) 2084 } 2085 case core.Complex64Type: 2086 var x complex64 2087 if len([]byte(vv.String())) > 0 { 2088 err := json.Unmarshal([]byte(vv.String()), &x) 2089 if err != nil { 2090 session.Engine.logger.Error(err) 2091 } else { 2092 fieldValue.Set(reflect.ValueOf(&x)) 2093 } 2094 } 2095 hasAssigned = true 2096 case core.Complex128Type: 2097 var x complex128 2098 if len([]byte(vv.String())) > 0 { 2099 err := json.Unmarshal([]byte(vv.String()), &x) 2100 if err != nil { 2101 session.Engine.logger.Error(err) 2102 } else { 2103 fieldValue.Set(reflect.ValueOf(&x)) 2104 } 2105 } 2106 hasAssigned = true 2107 } // switch fieldType 2108 // default: 2109 // session.Engine.LogError("unsupported type in Scan: ", reflect.TypeOf(v).String()) 2110 } // switch fieldType.Kind() 2111 2112 // !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value 2113 if !hasAssigned { 2114 data, err := value2Bytes(&rawValue) 2115 if err == nil { 2116 session.bytes2Value(col, fieldValue, data) 2117 } else { 2118 session.Engine.logger.Error(err.Error()) 2119 } 2120 } 2121 } 2122 } 2123 return nil 2124 2125 } 2126 2127 func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) { 2128 for _, filter := range session.Engine.dialect.Filters() { 2129 *sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable) 2130 } 2131 2132 session.saveLastSQL(*sqlStr, paramStr...) 2133 } 2134 2135 func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { 2136 2137 session.queryPreprocess(&sqlStr, paramStr...) 2138 2139 if session.IsAutoCommit { 2140 return session.innerQuery2(sqlStr, paramStr...) 2141 } 2142 return session.txQuery(session.Tx, sqlStr, paramStr...) 2143 } 2144 2145 func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) { 2146 rows, err := tx.Query(sqlStr, params...) 2147 if err != nil { 2148 return nil, err 2149 } 2150 defer rows.Close() 2151 2152 return rows2maps(rows) 2153 } 2154 2155 func (session *Session) innerQuery(sqlStr string, params ...interface{}) (*core.Stmt, *core.Rows, error) { 2156 var callback func() (*core.Stmt, *core.Rows, error) 2157 if session.prepareStmt { 2158 callback = func() (*core.Stmt, *core.Rows, error) { 2159 stmt, err := session.doPrepare(sqlStr) 2160 if err != nil { 2161 return nil, nil, err 2162 } 2163 rows, err := stmt.Query(params...) 2164 if err != nil { 2165 return nil, nil, err 2166 } 2167 return stmt, rows, nil 2168 } 2169 } else { 2170 callback = func() (*core.Stmt, *core.Rows, error) { 2171 rows, err := session.DB().Query(sqlStr, params...) 2172 if err != nil { 2173 return nil, nil, err 2174 } 2175 return nil, rows, err 2176 } 2177 } 2178 stmt, rows, err := session.Engine.logSQLQueryTime(sqlStr, params, callback) 2179 if err != nil { 2180 return nil, nil, err 2181 } 2182 return stmt, rows, nil 2183 } 2184 2185 func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map[string][]byte, error) { 2186 _, rows, err := session.innerQuery(sqlStr, params...) 2187 if rows != nil { 2188 defer rows.Close() 2189 } 2190 if err != nil { 2191 return nil, err 2192 } 2193 return rows2maps(rows) 2194 } 2195 2196 // Query a raw sql and return records as []map[string][]byte 2197 func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { 2198 defer session.resetStatement() 2199 if session.IsAutoClose { 2200 defer session.Close() 2201 } 2202 2203 return session.query(sqlStr, paramStr...) 2204 } 2205 2206 // ============================= 2207 // for string 2208 // ============================= 2209 func (session *Session) query2(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) { 2210 session.queryPreprocess(&sqlStr, paramStr...) 2211 2212 if session.IsAutoCommit { 2213 return query2(session.DB(), sqlStr, paramStr...) 2214 } 2215 return txQuery2(session.Tx, sqlStr, paramStr...) 2216 } 2217 2218 // Insert insert one or more beans 2219 func (session *Session) Insert(beans ...interface{}) (int64, error) { 2220 var affected int64 2221 var err error 2222 2223 if session.IsAutoClose { 2224 defer session.Close() 2225 } 2226 2227 for _, bean := range beans { 2228 sliceValue := reflect.Indirect(reflect.ValueOf(bean)) 2229 if sliceValue.Kind() == reflect.Slice { 2230 size := sliceValue.Len() 2231 if size > 0 { 2232 if session.Engine.SupportInsertMany() { 2233 cnt, err := session.innerInsertMulti(bean) 2234 //session.resetStatement() 2235 if err != nil { 2236 return affected, err 2237 } 2238 affected += cnt 2239 } else { 2240 for i := 0; i < size; i++ { 2241 cnt, err := session.innerInsert(sliceValue.Index(i).Interface()) 2242 //session.resetStatement() 2243 if err != nil { 2244 return affected, err 2245 } 2246 affected += cnt 2247 } 2248 } 2249 } 2250 } else { 2251 cnt, err := session.innerInsert(bean) 2252 //session.resetStatement() 2253 if err != nil { 2254 return affected, err 2255 } 2256 affected += cnt 2257 } 2258 } 2259 2260 return affected, err 2261 } 2262 2263 func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error) { 2264 sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) 2265 if sliceValue.Kind() != reflect.Slice { 2266 return 0, errors.New("needs a pointer to a slice") 2267 } 2268 2269 if sliceValue.Len() <= 0 { 2270 return 0, errors.New("could not insert a empty slice") 2271 } 2272 2273 session.Statement.setRefValue(sliceValue.Index(0)) 2274 2275 if len(session.Statement.TableName()) <= 0 { 2276 return 0, ErrTableNotFound 2277 } 2278 2279 table := session.Statement.RefTable 2280 size := sliceValue.Len() 2281 2282 var colNames []string 2283 var colMultiPlaces []string 2284 var args []interface{} 2285 var cols []*core.Column 2286 2287 for i := 0; i < size; i++ { 2288 v := sliceValue.Index(i) 2289 vv := reflect.Indirect(v) 2290 elemValue := v.Interface() 2291 var colPlaces []string 2292 2293 // handle BeforeInsertProcessor 2294 // !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi?? 2295 for _, closure := range session.beforeClosures { 2296 closure(elemValue) 2297 } 2298 2299 if processor, ok := interface{}(elemValue).(BeforeInsertProcessor); ok { 2300 processor.BeforeInsert() 2301 } 2302 // -- 2303 2304 if i == 0 { 2305 for _, col := range table.Columns() { 2306 ptrFieldValue, err := col.ValueOfV(&vv) 2307 if err != nil { 2308 return 0, err 2309 } 2310 fieldValue := *ptrFieldValue 2311 if col.IsAutoIncrement && isZero(fieldValue.Interface()) { 2312 continue 2313 } 2314 if col.MapType == core.ONLYFROMDB { 2315 continue 2316 } 2317 if col.IsDeleted { 2318 continue 2319 } 2320 if session.Statement.ColumnStr != "" { 2321 if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok { 2322 continue 2323 } 2324 } 2325 if session.Statement.OmitStr != "" { 2326 if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok { 2327 continue 2328 } 2329 } 2330 if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime { 2331 val, t := session.Engine.NowTime2(col.SQLType.Name) 2332 args = append(args, val) 2333 2334 var colName = col.Name 2335 session.afterClosures = append(session.afterClosures, func(bean interface{}) { 2336 col := table.GetColumn(colName) 2337 setColumnTime(bean, col, t) 2338 }) 2339 } else if col.IsVersion && session.Statement.checkVersion { 2340 args = append(args, 1) 2341 var colName = col.Name 2342 session.afterClosures = append(session.afterClosures, func(bean interface{}) { 2343 col := table.GetColumn(colName) 2344 setColumnInt(bean, col, 1) 2345 }) 2346 } else { 2347 arg, err := session.value2Interface(col, fieldValue) 2348 if err != nil { 2349 return 0, err 2350 } 2351 args = append(args, arg) 2352 } 2353 2354 colNames = append(colNames, col.Name) 2355 cols = append(cols, col) 2356 colPlaces = append(colPlaces, "?") 2357 } 2358 } else { 2359 for _, col := range cols { 2360 ptrFieldValue, err := col.ValueOfV(&vv) 2361 if err != nil { 2362 return 0, err 2363 } 2364 fieldValue := *ptrFieldValue 2365 2366 if col.IsAutoIncrement && isZero(fieldValue.Interface()) { 2367 continue 2368 } 2369 if col.MapType == core.ONLYFROMDB { 2370 continue 2371 } 2372 if col.IsDeleted { 2373 continue 2374 } 2375 if session.Statement.ColumnStr != "" { 2376 if _, ok := getFlagForColumn(session.Statement.columnMap, col); !ok { 2377 continue 2378 } 2379 } 2380 if session.Statement.OmitStr != "" { 2381 if _, ok := getFlagForColumn(session.Statement.columnMap, col); ok { 2382 continue 2383 } 2384 } 2385 if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime { 2386 val, t := session.Engine.NowTime2(col.SQLType.Name) 2387 args = append(args, val) 2388 2389 var colName = col.Name 2390 session.afterClosures = append(session.afterClosures, func(bean interface{}) { 2391 col := table.GetColumn(colName) 2392 setColumnTime(bean, col, t) 2393 }) 2394 } else if col.IsVersion && session.Statement.checkVersion { 2395 args = append(args, 1) 2396 var colName = col.Name 2397 session.afterClosures = append(session.afterClosures, func(bean interface{}) { 2398 col := table.GetColumn(colName) 2399 setColumnInt(bean, col, 1) 2400 }) 2401 } else { 2402 arg, err := session.value2Interface(col, fieldValue) 2403 if err != nil { 2404 return 0, err 2405 } 2406 args = append(args, arg) 2407 } 2408 2409 colPlaces = append(colPlaces, "?") 2410 } 2411 } 2412 colMultiPlaces = append(colMultiPlaces, strings.Join(colPlaces, ", ")) 2413 } 2414 cleanupProcessorsClosures(&session.beforeClosures) 2415 2416 statement := fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", 2417 session.Engine.Quote(session.Statement.TableName()), 2418 session.Engine.QuoteStr(), 2419 strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()), 2420 session.Engine.QuoteStr(), 2421 strings.Join(colMultiPlaces, "),(")) 2422 2423 res, err := session.exec(statement, args...) 2424 if err != nil { 2425 return 0, err 2426 } 2427 2428 if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { 2429 session.cacheInsert(session.Statement.TableName()) 2430 } 2431 2432 lenAfterClosures := len(session.afterClosures) 2433 for i := 0; i < size; i++ { 2434 elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface() 2435 2436 // handle AfterInsertProcessor 2437 if session.IsAutoCommit { 2438 // !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi?? 2439 for _, closure := range session.afterClosures { 2440 closure(elemValue) 2441 } 2442 if processor, ok := interface{}(elemValue).(AfterInsertProcessor); ok { 2443 processor.AfterInsert() 2444 } 2445 } else { 2446 if lenAfterClosures > 0 { 2447 if value, has := session.afterInsertBeans[elemValue]; has && value != nil { 2448 *value = append(*value, session.afterClosures...) 2449 } else { 2450 afterClosures := make([]func(interface{}), lenAfterClosures) 2451 copy(afterClosures, session.afterClosures) 2452 session.afterInsertBeans[elemValue] = &afterClosures 2453 } 2454 } else { 2455 if _, ok := interface{}(elemValue).(AfterInsertProcessor); ok { 2456 session.afterInsertBeans[elemValue] = nil 2457 } 2458 } 2459 } 2460 } 2461 2462 cleanupProcessorsClosures(&session.afterClosures) 2463 return res.RowsAffected() 2464 } 2465 2466 // InsertMulti insert multiple records 2467 func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { 2468 defer session.resetStatement() 2469 if session.IsAutoClose { 2470 defer session.Close() 2471 } 2472 2473 sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) 2474 if sliceValue.Kind() != reflect.Slice { 2475 return 0, ErrParamsType 2476 2477 } 2478 2479 if sliceValue.Len() <= 0 { 2480 return 0, nil 2481 } 2482 2483 return session.innerInsertMulti(rowsSlicePtr) 2484 } 2485 2486 func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) { 2487 sdata := strings.TrimSpace(data) 2488 var x time.Time 2489 var err error 2490 2491 if sdata == "0000-00-00 00:00:00" || 2492 sdata == "0001-01-01 00:00:00" { 2493 } else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column 2494 // time stamp 2495 sd, err := strconv.ParseInt(sdata, 10, 64) 2496 if err == nil { 2497 x = time.Unix(sd, 0) 2498 // !nashtsai! HACK mymysql driver is casuing Local location being change to CHAT and cause wrong time conversion 2499 if col.TimeZone == nil { 2500 x = x.In(session.Engine.TZLocation) 2501 } else { 2502 x = x.In(col.TimeZone) 2503 } 2504 session.Engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) 2505 } else { 2506 session.Engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) 2507 } 2508 } else if len(sdata) > 19 && strings.Contains(sdata, "-") { 2509 x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation) 2510 session.Engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) 2511 if err != nil { 2512 x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation) 2513 session.Engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) 2514 } 2515 if err != nil { 2516 x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation) 2517 session.Engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) 2518 } 2519 2520 } else if len(sdata) == 19 && strings.Contains(sdata, "-") { 2521 x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation) 2522 session.Engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) 2523 } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' { 2524 x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation) 2525 session.Engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) 2526 } else if col.SQLType.Name == core.Time { 2527 if strings.Contains(sdata, " ") { 2528 ssd := strings.Split(sdata, " ") 2529 sdata = ssd[1] 2530 } 2531 2532 sdata = strings.TrimSpace(sdata) 2533 if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 { 2534 sdata = sdata[len(sdata)-8:] 2535 } 2536 2537 st := fmt.Sprintf("2006-01-02 %v", sdata) 2538 x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation) 2539 session.Engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) 2540 } else { 2541 outErr = fmt.Errorf("unsupported time format %v", sdata) 2542 return 2543 } 2544 if err != nil { 2545 outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err) 2546 return 2547 } 2548 outTime = x 2549 return 2550 } 2551 2552 func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) { 2553 return session.str2Time(col, string(data)) 2554 } 2555 2556 // convert a db data([]byte) to a field value 2557 func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error { 2558 if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { 2559 return structConvert.FromDB(data) 2560 } 2561 2562 if structConvert, ok := fieldValue.Interface().(core.Conversion); ok { 2563 return structConvert.FromDB(data) 2564 } 2565 2566 var v interface{} 2567 key := col.Name 2568 fieldType := fieldValue.Type() 2569 2570 switch fieldType.Kind() { 2571 case reflect.Complex64, reflect.Complex128: 2572 x := reflect.New(fieldType) 2573 if len(data) > 0 { 2574 err := json.Unmarshal(data, x.Interface()) 2575 if err != nil { 2576 session.Engine.logger.Error(err) 2577 return err 2578 } 2579 fieldValue.Set(x.Elem()) 2580 } 2581 case reflect.Slice, reflect.Array, reflect.Map: 2582 v = data 2583 t := fieldType.Elem() 2584 k := t.Kind() 2585 if col.SQLType.IsText() { 2586 x := reflect.New(fieldType) 2587 if len(data) > 0 { 2588 err := json.Unmarshal(data, x.Interface()) 2589 if err != nil { 2590 session.Engine.logger.Error(err) 2591 return err 2592 } 2593 fieldValue.Set(x.Elem()) 2594 } 2595 } else if col.SQLType.IsBlob() { 2596 if k == reflect.Uint8 { 2597 fieldValue.Set(reflect.ValueOf(v)) 2598 } else { 2599 x := reflect.New(fieldType) 2600 if len(data) > 0 { 2601 err := json.Unmarshal(data, x.Interface()) 2602 if err != nil { 2603 session.Engine.logger.Error(err) 2604 return err 2605 } 2606 fieldValue.Set(x.Elem()) 2607 } 2608 } 2609 } else { 2610 return ErrUnSupportedType 2611 } 2612 case reflect.String: 2613 fieldValue.SetString(string(data)) 2614 case reflect.Bool: 2615 d := string(data) 2616 v, err := strconv.ParseBool(d) 2617 if err != nil { 2618 return fmt.Errorf("arg %v as bool: %s", key, err.Error()) 2619 } 2620 fieldValue.Set(reflect.ValueOf(v)) 2621 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 2622 sdata := string(data) 2623 var x int64 2624 var err error 2625 // for mysql, when use bit, it returned \x01 2626 if col.SQLType.Name == core.Bit && 2627 session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API 2628 if len(data) == 1 { 2629 x = int64(data[0]) 2630 } else { 2631 x = 0 2632 } 2633 } else if strings.HasPrefix(sdata, "0x") { 2634 x, err = strconv.ParseInt(sdata, 16, 64) 2635 } else if strings.HasPrefix(sdata, "0") { 2636 x, err = strconv.ParseInt(sdata, 8, 64) 2637 } else if strings.EqualFold(sdata, "true") { 2638 x = 1 2639 } else if strings.EqualFold(sdata, "false") { 2640 x = 0 2641 } else { 2642 x, err = strconv.ParseInt(sdata, 10, 64) 2643 } 2644 if err != nil { 2645 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2646 } 2647 fieldValue.SetInt(x) 2648 case reflect.Float32, reflect.Float64: 2649 x, err := strconv.ParseFloat(string(data), 64) 2650 if err != nil { 2651 return fmt.Errorf("arg %v as float64: %s", key, err.Error()) 2652 } 2653 fieldValue.SetFloat(x) 2654 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 2655 x, err := strconv.ParseUint(string(data), 10, 64) 2656 if err != nil { 2657 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2658 } 2659 fieldValue.SetUint(x) 2660 //Currently only support Time type 2661 case reflect.Struct: 2662 // !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString 2663 if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { 2664 if err := nulVal.Scan(data); err != nil { 2665 return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error()) 2666 } 2667 } else { 2668 if fieldType.ConvertibleTo(core.TimeType) { 2669 x, err := session.byte2Time(col, data) 2670 if err != nil { 2671 return err 2672 } 2673 v = x 2674 fieldValue.Set(reflect.ValueOf(v).Convert(fieldType)) 2675 } else if session.Statement.UseCascade { 2676 table := session.Engine.autoMapType(*fieldValue) 2677 if table != nil { 2678 // TODO: current only support 1 primary key 2679 if len(table.PrimaryKeys) > 1 { 2680 panic("unsupported composited primary key cascade") 2681 } 2682 var pk = make(core.PK, len(table.PrimaryKeys)) 2683 rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) 2684 var err error 2685 pk[0], err = str2PK(string(data), rawValueType) 2686 if err != nil { 2687 return err 2688 } 2689 2690 if !isPKZero(pk) { 2691 // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch 2692 // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne 2693 // property to be fetched lazily 2694 structInter := reflect.New(fieldValue.Type()) 2695 newsession := session.Engine.NewSession() 2696 defer newsession.Close() 2697 has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) 2698 if err != nil { 2699 return err 2700 } 2701 if has { 2702 v = structInter.Elem().Interface() 2703 fieldValue.Set(reflect.ValueOf(v)) 2704 } else { 2705 return errors.New("cascade obj is not exist") 2706 } 2707 } 2708 } else { 2709 return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String()) 2710 } 2711 } 2712 } 2713 case reflect.Ptr: 2714 // !nashtsai! TODO merge duplicated codes above 2715 //typeStr := fieldType.String() 2716 switch fieldType.Elem().Kind() { 2717 // case "*string": 2718 case core.StringType.Kind(): 2719 x := string(data) 2720 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2721 // case "*bool": 2722 case core.BoolType.Kind(): 2723 d := string(data) 2724 v, err := strconv.ParseBool(d) 2725 if err != nil { 2726 return fmt.Errorf("arg %v as bool: %s", key, err.Error()) 2727 } 2728 fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType)) 2729 // case "*complex64": 2730 case core.Complex64Type.Kind(): 2731 var x complex64 2732 if len(data) > 0 { 2733 err := json.Unmarshal(data, &x) 2734 if err != nil { 2735 session.Engine.logger.Error(err) 2736 return err 2737 } 2738 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2739 } 2740 // case "*complex128": 2741 case core.Complex128Type.Kind(): 2742 var x complex128 2743 if len(data) > 0 { 2744 err := json.Unmarshal(data, &x) 2745 if err != nil { 2746 session.Engine.logger.Error(err) 2747 return err 2748 } 2749 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2750 } 2751 // case "*float64": 2752 case core.Float64Type.Kind(): 2753 x, err := strconv.ParseFloat(string(data), 64) 2754 if err != nil { 2755 return fmt.Errorf("arg %v as float64: %s", key, err.Error()) 2756 } 2757 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2758 // case "*float32": 2759 case core.Float32Type.Kind(): 2760 var x float32 2761 x1, err := strconv.ParseFloat(string(data), 32) 2762 if err != nil { 2763 return fmt.Errorf("arg %v as float32: %s", key, err.Error()) 2764 } 2765 x = float32(x1) 2766 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2767 // case "*uint64": 2768 case core.Uint64Type.Kind(): 2769 var x uint64 2770 x, err := strconv.ParseUint(string(data), 10, 64) 2771 if err != nil { 2772 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2773 } 2774 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2775 // case "*uint": 2776 case core.UintType.Kind(): 2777 var x uint 2778 x1, err := strconv.ParseUint(string(data), 10, 64) 2779 if err != nil { 2780 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2781 } 2782 x = uint(x1) 2783 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2784 // case "*uint32": 2785 case core.Uint32Type.Kind(): 2786 var x uint32 2787 x1, err := strconv.ParseUint(string(data), 10, 64) 2788 if err != nil { 2789 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2790 } 2791 x = uint32(x1) 2792 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2793 // case "*uint8": 2794 case core.Uint8Type.Kind(): 2795 var x uint8 2796 x1, err := strconv.ParseUint(string(data), 10, 64) 2797 if err != nil { 2798 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2799 } 2800 x = uint8(x1) 2801 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2802 // case "*uint16": 2803 case core.Uint16Type.Kind(): 2804 var x uint16 2805 x1, err := strconv.ParseUint(string(data), 10, 64) 2806 if err != nil { 2807 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2808 } 2809 x = uint16(x1) 2810 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2811 // case "*int64": 2812 case core.Int64Type.Kind(): 2813 sdata := string(data) 2814 var x int64 2815 var err error 2816 // for mysql, when use bit, it returned \x01 2817 if col.SQLType.Name == core.Bit && 2818 strings.Contains(session.Engine.DriverName(), "mysql") { 2819 if len(data) == 1 { 2820 x = int64(data[0]) 2821 } else { 2822 x = 0 2823 } 2824 } else if strings.HasPrefix(sdata, "0x") { 2825 x, err = strconv.ParseInt(sdata, 16, 64) 2826 } else if strings.HasPrefix(sdata, "0") { 2827 x, err = strconv.ParseInt(sdata, 8, 64) 2828 } else { 2829 x, err = strconv.ParseInt(sdata, 10, 64) 2830 } 2831 if err != nil { 2832 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2833 } 2834 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2835 // case "*int": 2836 case core.IntType.Kind(): 2837 sdata := string(data) 2838 var x int 2839 var x1 int64 2840 var err error 2841 // for mysql, when use bit, it returned \x01 2842 if col.SQLType.Name == core.Bit && 2843 strings.Contains(session.Engine.DriverName(), "mysql") { 2844 if len(data) == 1 { 2845 x = int(data[0]) 2846 } else { 2847 x = 0 2848 } 2849 } else if strings.HasPrefix(sdata, "0x") { 2850 x1, err = strconv.ParseInt(sdata, 16, 64) 2851 x = int(x1) 2852 } else if strings.HasPrefix(sdata, "0") { 2853 x1, err = strconv.ParseInt(sdata, 8, 64) 2854 x = int(x1) 2855 } else { 2856 x1, err = strconv.ParseInt(sdata, 10, 64) 2857 x = int(x1) 2858 } 2859 if err != nil { 2860 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2861 } 2862 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2863 // case "*int32": 2864 case core.Int32Type.Kind(): 2865 sdata := string(data) 2866 var x int32 2867 var x1 int64 2868 var err error 2869 // for mysql, when use bit, it returned \x01 2870 if col.SQLType.Name == core.Bit && 2871 session.Engine.dialect.DBType() == core.MYSQL { 2872 if len(data) == 1 { 2873 x = int32(data[0]) 2874 } else { 2875 x = 0 2876 } 2877 } else if strings.HasPrefix(sdata, "0x") { 2878 x1, err = strconv.ParseInt(sdata, 16, 64) 2879 x = int32(x1) 2880 } else if strings.HasPrefix(sdata, "0") { 2881 x1, err = strconv.ParseInt(sdata, 8, 64) 2882 x = int32(x1) 2883 } else { 2884 x1, err = strconv.ParseInt(sdata, 10, 64) 2885 x = int32(x1) 2886 } 2887 if err != nil { 2888 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2889 } 2890 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2891 // case "*int8": 2892 case core.Int8Type.Kind(): 2893 sdata := string(data) 2894 var x int8 2895 var x1 int64 2896 var err error 2897 // for mysql, when use bit, it returned \x01 2898 if col.SQLType.Name == core.Bit && 2899 strings.Contains(session.Engine.DriverName(), "mysql") { 2900 if len(data) == 1 { 2901 x = int8(data[0]) 2902 } else { 2903 x = 0 2904 } 2905 } else if strings.HasPrefix(sdata, "0x") { 2906 x1, err = strconv.ParseInt(sdata, 16, 64) 2907 x = int8(x1) 2908 } else if strings.HasPrefix(sdata, "0") { 2909 x1, err = strconv.ParseInt(sdata, 8, 64) 2910 x = int8(x1) 2911 } else { 2912 x1, err = strconv.ParseInt(sdata, 10, 64) 2913 x = int8(x1) 2914 } 2915 if err != nil { 2916 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2917 } 2918 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2919 // case "*int16": 2920 case core.Int16Type.Kind(): 2921 sdata := string(data) 2922 var x int16 2923 var x1 int64 2924 var err error 2925 // for mysql, when use bit, it returned \x01 2926 if col.SQLType.Name == core.Bit && 2927 strings.Contains(session.Engine.DriverName(), "mysql") { 2928 if len(data) == 1 { 2929 x = int16(data[0]) 2930 } else { 2931 x = 0 2932 } 2933 } else if strings.HasPrefix(sdata, "0x") { 2934 x1, err = strconv.ParseInt(sdata, 16, 64) 2935 x = int16(x1) 2936 } else if strings.HasPrefix(sdata, "0") { 2937 x1, err = strconv.ParseInt(sdata, 8, 64) 2938 x = int16(x1) 2939 } else { 2940 x1, err = strconv.ParseInt(sdata, 10, 64) 2941 x = int16(x1) 2942 } 2943 if err != nil { 2944 return fmt.Errorf("arg %v as int: %s", key, err.Error()) 2945 } 2946 fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) 2947 // case "*SomeStruct": 2948 case reflect.Struct: 2949 switch fieldType { 2950 // case "*.time.Time": 2951 case core.PtrTimeType: 2952 x, err := session.byte2Time(col, data) 2953 if err != nil { 2954 return err 2955 } 2956 v = x 2957 fieldValue.Set(reflect.ValueOf(&x)) 2958 default: 2959 if session.Statement.UseCascade { 2960 structInter := reflect.New(fieldType.Elem()) 2961 table := session.Engine.autoMapType(structInter.Elem()) 2962 if table != nil { 2963 if len(table.PrimaryKeys) > 1 { 2964 panic("unsupported composited primary key cascade") 2965 } 2966 var pk = make(core.PK, len(table.PrimaryKeys)) 2967 var err error 2968 rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) 2969 pk[0], err = str2PK(string(data), rawValueType) 2970 if err != nil { 2971 return err 2972 } 2973 2974 if !isPKZero(pk) { 2975 // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch 2976 // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne 2977 // property to be fetched lazily 2978 newsession := session.Engine.NewSession() 2979 defer newsession.Close() 2980 has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) 2981 if err != nil { 2982 return err 2983 } 2984 if has { 2985 v = structInter.Interface() 2986 fieldValue.Set(reflect.ValueOf(v)) 2987 } else { 2988 return errors.New("cascade obj is not exist") 2989 } 2990 } 2991 } 2992 } else { 2993 return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String()) 2994 } 2995 } 2996 default: 2997 return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) 2998 } 2999 default: 3000 return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) 3001 } 3002 3003 return nil 3004 } 3005 3006 // convert a field value of a struct to interface for put into db 3007 func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) { 3008 if fieldValue.CanAddr() { 3009 if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { 3010 data, err := fieldConvert.ToDB() 3011 if err != nil { 3012 return 0, err 3013 } 3014 return string(data), nil 3015 } 3016 } 3017 3018 if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok { 3019 data, err := fieldConvert.ToDB() 3020 if err != nil { 3021 return 0, err 3022 } 3023 return string(data), nil 3024 } 3025 3026 fieldType := fieldValue.Type() 3027 k := fieldType.Kind() 3028 if k == reflect.Ptr { 3029 if fieldValue.IsNil() { 3030 return nil, nil 3031 } else if !fieldValue.IsValid() { 3032 session.Engine.logger.Warn("the field[", col.FieldName, "] is invalid") 3033 return nil, nil 3034 } else { 3035 // !nashtsai! deference pointer type to instance type 3036 fieldValue = fieldValue.Elem() 3037 fieldType = fieldValue.Type() 3038 k = fieldType.Kind() 3039 } 3040 } 3041 3042 switch k { 3043 case reflect.Bool: 3044 return fieldValue.Bool(), nil 3045 case reflect.String: 3046 return fieldValue.String(), nil 3047 case reflect.Struct: 3048 if fieldType.ConvertibleTo(core.TimeType) { 3049 t := fieldValue.Convert(core.TimeType).Interface().(time.Time) 3050 if session.Engine.dialect.DBType() == core.MSSQL { 3051 if t.IsZero() { 3052 return nil, nil 3053 } 3054 } 3055 tf := session.Engine.FormatTime(col.SQLType.Name, t) 3056 return tf, nil 3057 } 3058 3059 if !col.SQLType.IsJson() { 3060 // !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString 3061 if v, ok := fieldValue.Interface().(driver.Valuer); ok { 3062 return v.Value() 3063 } 3064 3065 fieldTable := session.Engine.autoMapType(fieldValue) 3066 if len(fieldTable.PrimaryKeys) == 1 { 3067 pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName) 3068 return pkField.Interface(), nil 3069 } 3070 return 0, fmt.Errorf("no primary key for col %v", col.Name) 3071 } 3072 3073 if col.SQLType.IsText() { 3074 bytes, err := json.Marshal(fieldValue.Interface()) 3075 if err != nil { 3076 session.Engine.logger.Error(err) 3077 return 0, err 3078 } 3079 return string(bytes), nil 3080 } else if col.SQLType.IsBlob() { 3081 bytes, err := json.Marshal(fieldValue.Interface()) 3082 if err != nil { 3083 session.Engine.logger.Error(err) 3084 return 0, err 3085 } 3086 return bytes, nil 3087 } 3088 return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type()) 3089 case reflect.Complex64, reflect.Complex128: 3090 bytes, err := json.Marshal(fieldValue.Interface()) 3091 if err != nil { 3092 session.Engine.logger.Error(err) 3093 return 0, err 3094 } 3095 return string(bytes), nil 3096 case reflect.Array, reflect.Slice, reflect.Map: 3097 if !fieldValue.IsValid() { 3098 return fieldValue.Interface(), nil 3099 } 3100 3101 if col.SQLType.IsText() { 3102 bytes, err := json.Marshal(fieldValue.Interface()) 3103 if err != nil { 3104 session.Engine.logger.Error(err) 3105 return 0, err 3106 } 3107 return string(bytes), nil 3108 } else if col.SQLType.IsBlob() { 3109 var bytes []byte 3110 var err error 3111 if (k == reflect.Array || k == reflect.Slice) && 3112 (fieldValue.Type().Elem().Kind() == reflect.Uint8) { 3113 bytes = fieldValue.Bytes() 3114 } else { 3115 bytes, err = json.Marshal(fieldValue.Interface()) 3116 if err != nil { 3117 session.Engine.logger.Error(err) 3118 return 0, err 3119 } 3120 } 3121 return bytes, nil 3122 } 3123 return nil, ErrUnSupportedType 3124 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 3125 return int64(fieldValue.Uint()), nil 3126 default: 3127 return fieldValue.Interface(), nil 3128 } 3129 } 3130 3131 func (session *Session) innerInsert(bean interface{}) (int64, error) { 3132 session.Statement.setRefValue(rValue(bean)) 3133 if len(session.Statement.TableName()) <= 0 { 3134 return 0, ErrTableNotFound 3135 } 3136 3137 table := session.Statement.RefTable 3138 3139 // handle BeforeInsertProcessor 3140 for _, closure := range session.beforeClosures { 3141 closure(bean) 3142 } 3143 cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used 3144 3145 if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok { 3146 processor.BeforeInsert() 3147 } 3148 // -- 3149 colNames, args, err := genCols(session.Statement.RefTable, session, bean, false, false) 3150 if err != nil { 3151 return 0, err 3152 } 3153 // insert expr columns, override if exists 3154 exprColumns := session.Statement.getExpr() 3155 exprColVals := make([]string, 0, len(exprColumns)) 3156 for _, v := range exprColumns { 3157 // remove the expr columns 3158 for i, colName := range colNames { 3159 if colName == v.colName { 3160 colNames = append(colNames[:i], colNames[i+1:]...) 3161 args = append(args[:i], args[i+1:]...) 3162 } 3163 } 3164 3165 // append expr column to the end 3166 colNames = append(colNames, v.colName) 3167 exprColVals = append(exprColVals, v.expr) 3168 } 3169 3170 colPlaces := strings.Repeat("?, ", len(colNames)-len(exprColumns)) 3171 if len(exprColVals) > 0 { 3172 colPlaces = colPlaces + strings.Join(exprColVals, ", ") 3173 } else { 3174 colPlaces = colPlaces[0 : len(colPlaces)-2] 3175 } 3176 3177 sqlStr := fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", 3178 session.Engine.Quote(session.Statement.TableName()), 3179 session.Engine.QuoteStr(), 3180 strings.Join(colNames, session.Engine.Quote(", ")), 3181 session.Engine.QuoteStr(), 3182 colPlaces) 3183 3184 handleAfterInsertProcessorFunc := func(bean interface{}) { 3185 if session.IsAutoCommit { 3186 for _, closure := range session.afterClosures { 3187 closure(bean) 3188 } 3189 if processor, ok := interface{}(bean).(AfterInsertProcessor); ok { 3190 processor.AfterInsert() 3191 } 3192 } else { 3193 lenAfterClosures := len(session.afterClosures) 3194 if lenAfterClosures > 0 { 3195 if value, has := session.afterInsertBeans[bean]; has && value != nil { 3196 *value = append(*value, session.afterClosures...) 3197 } else { 3198 afterClosures := make([]func(interface{}), lenAfterClosures) 3199 copy(afterClosures, session.afterClosures) 3200 session.afterInsertBeans[bean] = &afterClosures 3201 } 3202 3203 } else { 3204 if _, ok := interface{}(bean).(AfterInsertProcessor); ok { 3205 session.afterInsertBeans[bean] = nil 3206 } 3207 } 3208 } 3209 cleanupProcessorsClosures(&session.afterClosures) // cleanup after used 3210 } 3211 3212 // for postgres, many of them didn't implement lastInsertId, so we should 3213 // implemented it ourself. 3214 if session.Engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 { 3215 //assert table.AutoIncrement != "" 3216 res, err := session.query("select seq_atable.currval from dual", args...) 3217 if err != nil { 3218 return 0, err 3219 } 3220 3221 handleAfterInsertProcessorFunc(bean) 3222 3223 if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { 3224 session.cacheInsert(session.Statement.TableName()) 3225 } 3226 3227 if table.Version != "" && session.Statement.checkVersion { 3228 verValue, err := table.VersionColumn().ValueOf(bean) 3229 if err != nil { 3230 session.Engine.logger.Error(err) 3231 } else if verValue.IsValid() && verValue.CanSet() { 3232 verValue.SetInt(1) 3233 } 3234 } 3235 3236 if len(res) < 1 { 3237 return 0, errors.New("insert no error but not returned id") 3238 } 3239 3240 idByte := res[0][table.AutoIncrement] 3241 id, err := strconv.ParseInt(string(idByte), 10, 64) 3242 if err != nil || id <= 0 { 3243 return 1, err 3244 } 3245 3246 aiValue, err := table.AutoIncrColumn().ValueOf(bean) 3247 if err != nil { 3248 session.Engine.logger.Error(err) 3249 } 3250 3251 if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { 3252 return 1, nil 3253 } 3254 3255 aiValue.Set(int64ToIntValue(id, aiValue.Type())) 3256 3257 return 1, nil 3258 } else if session.Engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 { 3259 //assert table.AutoIncrement != "" 3260 sqlStr = sqlStr + " RETURNING " + session.Engine.Quote(table.AutoIncrement) 3261 res, err := session.query(sqlStr, args...) 3262 3263 if err != nil { 3264 return 0, err 3265 } 3266 handleAfterInsertProcessorFunc(bean) 3267 3268 if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { 3269 session.cacheInsert(session.Statement.TableName()) 3270 } 3271 3272 if table.Version != "" && session.Statement.checkVersion { 3273 verValue, err := table.VersionColumn().ValueOf(bean) 3274 if err != nil { 3275 session.Engine.logger.Error(err) 3276 } else if verValue.IsValid() && verValue.CanSet() { 3277 verValue.SetInt(1) 3278 } 3279 } 3280 3281 if len(res) < 1 { 3282 return 0, errors.New("insert no error but not returned id") 3283 } 3284 3285 idByte := res[0][table.AutoIncrement] 3286 id, err := strconv.ParseInt(string(idByte), 10, 64) 3287 if err != nil || id <= 0 { 3288 return 1, err 3289 } 3290 3291 aiValue, err := table.AutoIncrColumn().ValueOf(bean) 3292 if err != nil { 3293 session.Engine.logger.Error(err) 3294 } 3295 3296 if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { 3297 return 1, nil 3298 } 3299 3300 aiValue.Set(int64ToIntValue(id, aiValue.Type())) 3301 3302 return 1, nil 3303 } else { 3304 res, err := session.exec(sqlStr, args...) 3305 if err != nil { 3306 return 0, err 3307 } 3308 3309 defer handleAfterInsertProcessorFunc(bean) 3310 3311 if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { 3312 session.cacheInsert(session.Statement.TableName()) 3313 } 3314 3315 if table.Version != "" && session.Statement.checkVersion { 3316 verValue, err := table.VersionColumn().ValueOf(bean) 3317 if err != nil { 3318 session.Engine.logger.Error(err) 3319 } else if verValue.IsValid() && verValue.CanSet() { 3320 verValue.SetInt(1) 3321 } 3322 } 3323 3324 if table.AutoIncrement == "" { 3325 return res.RowsAffected() 3326 } 3327 3328 var id int64 3329 id, err = res.LastInsertId() 3330 if err != nil || id <= 0 { 3331 return res.RowsAffected() 3332 } 3333 3334 aiValue, err := table.AutoIncrColumn().ValueOf(bean) 3335 if err != nil { 3336 session.Engine.logger.Error(err) 3337 } 3338 3339 if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { 3340 return res.RowsAffected() 3341 } 3342 3343 aiValue.Set(int64ToIntValue(id, aiValue.Type())) 3344 3345 return res.RowsAffected() 3346 } 3347 } 3348 3349 // InsertOne insert only one struct into database as a record. 3350 // The in parameter bean must a struct or a point to struct. The return 3351 // parameter is inserted and error 3352 func (session *Session) InsertOne(bean interface{}) (int64, error) { 3353 defer session.resetStatement() 3354 if session.IsAutoClose { 3355 defer session.Close() 3356 } 3357 3358 return session.innerInsert(bean) 3359 } 3360 3361 func (session *Session) cacheInsert(tables ...string) error { 3362 if session.Statement.RefTable == nil { 3363 return ErrCacheFailed 3364 } 3365 3366 table := session.Statement.RefTable 3367 cacher := session.Engine.getCacher2(table) 3368 3369 for _, t := range tables { 3370 session.Engine.logger.Debug("[cache] clear sql:", t) 3371 cacher.ClearIds(t) 3372 } 3373 3374 return nil 3375 } 3376 3377 func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error { 3378 if session.Statement.RefTable == nil || 3379 session.Tx != nil { 3380 return ErrCacheFailed 3381 } 3382 3383 oldhead, newsql := session.Statement.convertUpdateSQL(sqlStr) 3384 if newsql == "" { 3385 return ErrCacheFailed 3386 } 3387 for _, filter := range session.Engine.dialect.Filters() { 3388 newsql = filter.Do(newsql, session.Engine.dialect, session.Statement.RefTable) 3389 } 3390 session.Engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql) 3391 3392 var nStart int 3393 if len(args) > 0 { 3394 if strings.Index(sqlStr, "?") > -1 { 3395 nStart = strings.Count(oldhead, "?") 3396 } else { 3397 // only for pq, TODO: if any other databse? 3398 nStart = strings.Count(oldhead, "$") 3399 } 3400 } 3401 table := session.Statement.RefTable 3402 cacher := session.Engine.getCacher2(table) 3403 tableName := session.Statement.TableName() 3404 session.Engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:]) 3405 ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:]) 3406 if err != nil { 3407 rows, err := session.DB().Query(newsql, args[nStart:]...) 3408 if err != nil { 3409 return err 3410 } 3411 defer rows.Close() 3412 3413 ids = make([]core.PK, 0) 3414 for rows.Next() { 3415 var res = make([]string, len(table.PrimaryKeys)) 3416 err = rows.ScanSlice(&res) 3417 if err != nil { 3418 return err 3419 } 3420 var pk core.PK = make([]interface{}, len(table.PrimaryKeys)) 3421 for i, col := range table.PKColumns() { 3422 if col.SQLType.IsNumeric() { 3423 n, err := strconv.ParseInt(res[i], 10, 64) 3424 if err != nil { 3425 return err 3426 } 3427 pk[i] = n 3428 } else if col.SQLType.IsText() { 3429 pk[i] = res[i] 3430 } else { 3431 return errors.New("not supported") 3432 } 3433 } 3434 3435 ids = append(ids, pk) 3436 } 3437 session.Engine.logger.Debug("[cacheUpdate] find updated id", ids) 3438 } /*else { 3439 session.Engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args) 3440 cacher.DelIds(tableName, genSqlKey(newsql, args)) 3441 }*/ 3442 3443 for _, id := range ids { 3444 sid, err := id.ToString() 3445 if err != nil { 3446 return err 3447 } 3448 if bean := cacher.GetBean(tableName, sid); bean != nil { 3449 sqls := splitNNoCase(sqlStr, "where", 2) 3450 if len(sqls) == 0 || len(sqls) > 2 { 3451 return ErrCacheFailed 3452 } 3453 3454 sqls = splitNNoCase(sqls[0], "set", 2) 3455 if len(sqls) != 2 { 3456 return ErrCacheFailed 3457 } 3458 kvs := strings.Split(strings.TrimSpace(sqls[1]), ",") 3459 for idx, kv := range kvs { 3460 sps := strings.SplitN(kv, "=", 2) 3461 sps2 := strings.Split(sps[0], ".") 3462 colName := sps2[len(sps2)-1] 3463 if strings.Contains(colName, "`") { 3464 colName = strings.TrimSpace(strings.Replace(colName, "`", "", -1)) 3465 } else if strings.Contains(colName, session.Engine.QuoteStr()) { 3466 colName = strings.TrimSpace(strings.Replace(colName, session.Engine.QuoteStr(), "", -1)) 3467 } else { 3468 session.Engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName) 3469 return ErrCacheFailed 3470 } 3471 3472 if col := table.GetColumn(colName); col != nil { 3473 fieldValue, err := col.ValueOf(bean) 3474 if err != nil { 3475 session.Engine.logger.Error(err) 3476 } else { 3477 session.Engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface()) 3478 if col.IsVersion && session.Statement.checkVersion { 3479 fieldValue.SetInt(fieldValue.Int() + 1) 3480 } else { 3481 fieldValue.Set(reflect.ValueOf(args[idx])) 3482 } 3483 } 3484 } else { 3485 session.Engine.logger.Errorf("[cacheUpdate] ERROR: column %v is not table %v's", 3486 colName, table.Name) 3487 } 3488 } 3489 3490 session.Engine.logger.Debug("[cacheUpdate] update cache", tableName, id, bean) 3491 cacher.PutBean(tableName, sid, bean) 3492 } 3493 } 3494 session.Engine.logger.Debug("[cacheUpdate] clear cached table sql:", tableName) 3495 cacher.ClearIds(tableName) 3496 return nil 3497 } 3498 3499 // Update records, bean's non-empty fields are updated contents, 3500 // condiBean' non-empty filds are conditions 3501 // CAUTION: 3502 // 1.bool will defaultly be updated content nor conditions 3503 // You should call UseBool if you have bool to use. 3504 // 2.float32 & float64 may be not inexact as conditions 3505 func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) { 3506 defer session.resetStatement() 3507 if session.IsAutoClose { 3508 defer session.Close() 3509 } 3510 3511 v := rValue(bean) 3512 t := v.Type() 3513 3514 var colNames []string 3515 var args []interface{} 3516 3517 // handle before update processors 3518 for _, closure := range session.beforeClosures { 3519 closure(bean) 3520 } 3521 cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used 3522 if processor, ok := interface{}(bean).(BeforeUpdateProcessor); ok { 3523 processor.BeforeUpdate() 3524 } 3525 // -- 3526 3527 var err error 3528 var isMap = t.Kind() == reflect.Map 3529 var isStruct = t.Kind() == reflect.Struct 3530 if isStruct { 3531 session.Statement.setRefValue(v) 3532 3533 if len(session.Statement.TableName()) <= 0 { 3534 return 0, ErrTableNotFound 3535 } 3536 3537 if session.Statement.ColumnStr == "" { 3538 colNames, args = buildUpdates(session.Engine, session.Statement.RefTable, bean, false, false, 3539 false, false, session.Statement.allUseBool, session.Statement.useAllCols, 3540 session.Statement.mustColumnMap, session.Statement.nullableMap, 3541 session.Statement.columnMap, true, session.Statement.unscoped) 3542 } else { 3543 colNames, args, err = genCols(session.Statement.RefTable, session, bean, true, true) 3544 if err != nil { 3545 return 0, err 3546 } 3547 } 3548 } else if isMap { 3549 colNames = make([]string, 0) 3550 args = make([]interface{}, 0) 3551 bValue := reflect.Indirect(reflect.ValueOf(bean)) 3552 3553 for _, v := range bValue.MapKeys() { 3554 colNames = append(colNames, session.Engine.Quote(v.String())+" = ?") 3555 args = append(args, bValue.MapIndex(v).Interface()) 3556 } 3557 } else { 3558 return 0, ErrParamsType 3559 } 3560 3561 table := session.Statement.RefTable 3562 3563 if session.Statement.UseAutoTime && table != nil && table.Updated != "" { 3564 colNames = append(colNames, session.Engine.Quote(table.Updated)+" = ?") 3565 col := table.UpdatedColumn() 3566 val, t := session.Engine.NowTime2(col.SQLType.Name) 3567 args = append(args, val) 3568 3569 var colName = col.Name 3570 if isStruct { 3571 session.afterClosures = append(session.afterClosures, func(bean interface{}) { 3572 col := table.GetColumn(colName) 3573 setColumnTime(bean, col, t) 3574 }) 3575 } 3576 } 3577 3578 //for update action to like "column = column + ?" 3579 incColumns := session.Statement.getInc() 3580 for _, v := range incColumns { 3581 colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+session.Engine.Quote(v.colName)+" + ?") 3582 args = append(args, v.arg) 3583 } 3584 //for update action to like "column = column - ?" 3585 decColumns := session.Statement.getDec() 3586 for _, v := range decColumns { 3587 colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+session.Engine.Quote(v.colName)+" - ?") 3588 args = append(args, v.arg) 3589 } 3590 //for update action to like "column = expression" 3591 exprColumns := session.Statement.getExpr() 3592 for _, v := range exprColumns { 3593 colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+v.expr) 3594 } 3595 3596 session.Statement.processIdParam() 3597 3598 var autoCond builder.Cond 3599 if !session.Statement.noAutoCondition && len(condiBean) > 0 { 3600 var err error 3601 autoCond, err = session.Statement.buildConds(session.Statement.RefTable, condiBean[0], true, true, false, true, false) 3602 if err != nil { 3603 return 0, err 3604 } 3605 } 3606 3607 st := session.Statement 3608 defer session.resetStatement() 3609 3610 var sqlStr string 3611 var condArgs []interface{} 3612 var condSQL string 3613 cond := session.Statement.cond.And(autoCond) 3614 3615 doIncVer := false 3616 var verValue *reflect.Value 3617 if table != nil && table.Version != "" && session.Statement.checkVersion { 3618 verValue, err = table.VersionColumn().ValueOf(bean) 3619 if err != nil { 3620 return 0, err 3621 } 3622 3623 cond = cond.And(builder.Eq{session.Engine.Quote(table.Version): verValue.Interface()}) 3624 condSQL, condArgs, _ = builder.ToSQL(cond) 3625 3626 if len(condSQL) > 0 { 3627 condSQL = "WHERE " + condSQL 3628 } 3629 3630 if st.LimitN > 0 { 3631 condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) 3632 } 3633 3634 sqlStr = fmt.Sprintf("UPDATE %v SET %v, %v %v", 3635 session.Engine.Quote(session.Statement.TableName()), 3636 strings.Join(colNames, ", "), 3637 session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1", 3638 condSQL) 3639 3640 doIncVer = true 3641 } else { 3642 condSQL, condArgs, _ = builder.ToSQL(cond) 3643 if len(condSQL) > 0 { 3644 condSQL = "WHERE " + condSQL 3645 } 3646 3647 if st.LimitN > 0 { 3648 condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) 3649 } 3650 3651 sqlStr = fmt.Sprintf("UPDATE %v SET %v %v", 3652 session.Engine.Quote(session.Statement.TableName()), 3653 strings.Join(colNames, ", "), 3654 condSQL) 3655 } 3656 3657 res, err := session.exec(sqlStr, append(args, condArgs...)...) 3658 if err != nil { 3659 return 0, err 3660 } else if doIncVer { 3661 if verValue != nil && verValue.IsValid() && verValue.CanSet() { 3662 verValue.SetInt(verValue.Int() + 1) 3663 } 3664 } 3665 3666 if table != nil { 3667 if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache { 3668 cacher.ClearIds(session.Statement.TableName()) 3669 cacher.ClearBeans(session.Statement.TableName()) 3670 } 3671 } 3672 3673 // handle after update processors 3674 if session.IsAutoCommit { 3675 for _, closure := range session.afterClosures { 3676 closure(bean) 3677 } 3678 if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok { 3679 session.Engine.logger.Debug("[event]", session.Statement.TableName(), " has after update processor") 3680 processor.AfterUpdate() 3681 } 3682 } else { 3683 lenAfterClosures := len(session.afterClosures) 3684 if lenAfterClosures > 0 { 3685 if value, has := session.afterUpdateBeans[bean]; has && value != nil { 3686 *value = append(*value, session.afterClosures...) 3687 } else { 3688 afterClosures := make([]func(interface{}), lenAfterClosures) 3689 copy(afterClosures, session.afterClosures) 3690 // FIXME: if bean is a map type, it will panic because map cannot be as map key 3691 session.afterUpdateBeans[bean] = &afterClosures 3692 } 3693 3694 } else { 3695 if _, ok := interface{}(bean).(AfterInsertProcessor); ok { 3696 session.afterUpdateBeans[bean] = nil 3697 } 3698 } 3699 } 3700 cleanupProcessorsClosures(&session.afterClosures) // cleanup after used 3701 // -- 3702 3703 return res.RowsAffected() 3704 } 3705 3706 func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error { 3707 if session.Statement.RefTable == nil || 3708 session.Tx != nil { 3709 return ErrCacheFailed 3710 } 3711 3712 for _, filter := range session.Engine.dialect.Filters() { 3713 sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable) 3714 } 3715 3716 newsql := session.Statement.convertIDSQL(sqlStr) 3717 if newsql == "" { 3718 return ErrCacheFailed 3719 } 3720 3721 cacher := session.Engine.getCacher2(session.Statement.RefTable) 3722 tableName := session.Statement.TableName() 3723 ids, err := core.GetCacheSql(cacher, tableName, newsql, args) 3724 if err != nil { 3725 resultsSlice, err := session.query(newsql, args...) 3726 if err != nil { 3727 return err 3728 } 3729 ids = make([]core.PK, 0) 3730 if len(resultsSlice) > 0 { 3731 for _, data := range resultsSlice { 3732 var id int64 3733 var pk core.PK = make([]interface{}, 0) 3734 for _, col := range session.Statement.RefTable.PKColumns() { 3735 if v, ok := data[col.Name]; !ok { 3736 return errors.New("no id") 3737 } else if col.SQLType.IsText() { 3738 pk = append(pk, string(v)) 3739 } else if col.SQLType.IsNumeric() { 3740 id, err = strconv.ParseInt(string(v), 10, 64) 3741 if err != nil { 3742 return err 3743 } 3744 pk = append(pk, id) 3745 } else { 3746 return errors.New("not supported primary key type") 3747 } 3748 } 3749 ids = append(ids, pk) 3750 } 3751 } 3752 } /*else { 3753 session.Engine.LogDebug("delete cache sql %v", newsql) 3754 cacher.DelIds(tableName, genSqlKey(newsql, args)) 3755 }*/ 3756 3757 for _, id := range ids { 3758 session.Engine.logger.Debug("[cacheDelete] delete cache obj", tableName, id) 3759 sid, err := id.ToString() 3760 if err != nil { 3761 return err 3762 } 3763 cacher.DelBean(tableName, sid) 3764 } 3765 session.Engine.logger.Debug("[cacheDelete] clear cache sql", tableName) 3766 cacher.ClearIds(tableName) 3767 return nil 3768 } 3769 3770 // Delete records, bean's non-empty fields are conditions 3771 func (session *Session) Delete(bean interface{}) (int64, error) { 3772 defer session.resetStatement() 3773 if session.IsAutoClose { 3774 defer session.Close() 3775 } 3776 3777 session.Statement.setRefValue(rValue(bean)) 3778 var table = session.Statement.RefTable 3779 3780 // handle before delete processors 3781 for _, closure := range session.beforeClosures { 3782 closure(bean) 3783 } 3784 cleanupProcessorsClosures(&session.beforeClosures) 3785 3786 if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok { 3787 processor.BeforeDelete() 3788 } 3789 3790 // -- 3791 condSQL, condArgs, _ := session.Statement.genConds(bean) 3792 if len(condSQL) == 0 && session.Statement.LimitN == 0 { 3793 return 0, ErrNeedDeletedCond 3794 } 3795 3796 var tableName = session.Engine.Quote(session.Statement.TableName()) 3797 var deleteSQL string 3798 if len(condSQL) > 0 { 3799 deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL) 3800 } else { 3801 deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName) 3802 } 3803 3804 var orderSQL string 3805 if len(session.Statement.OrderStr) > 0 { 3806 orderSQL += fmt.Sprintf(" ORDER BY %s", session.Statement.OrderStr) 3807 } 3808 if session.Statement.LimitN > 0 { 3809 orderSQL += fmt.Sprintf(" LIMIT %d", session.Statement.LimitN) 3810 } 3811 3812 if len(orderSQL) > 0 { 3813 switch session.Engine.dialect.DBType() { 3814 case core.POSTGRES: 3815 inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL) 3816 if len(condSQL) > 0 { 3817 deleteSQL += " AND " + inSQL 3818 } else { 3819 deleteSQL += " WHERE " + inSQL 3820 } 3821 case core.SQLITE: 3822 inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL) 3823 if len(condSQL) > 0 { 3824 deleteSQL += " AND " + inSQL 3825 } else { 3826 deleteSQL += " WHERE " + inSQL 3827 } 3828 // TODO: how to handle delete limit on mssql? 3829 case core.MSSQL: 3830 return 0, ErrNotImplemented 3831 default: 3832 deleteSQL += orderSQL 3833 } 3834 } 3835 3836 var realSQL string 3837 argsForCache := make([]interface{}, 0, len(condArgs)*2) 3838 if session.Statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled 3839 realSQL = deleteSQL 3840 copy(argsForCache, condArgs) 3841 argsForCache = append(condArgs, argsForCache...) 3842 } else { 3843 // !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache. 3844 copy(argsForCache, condArgs) 3845 argsForCache = append(condArgs, argsForCache...) 3846 3847 deletedColumn := table.DeletedColumn() 3848 realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v", 3849 session.Engine.Quote(session.Statement.TableName()), 3850 session.Engine.Quote(deletedColumn.Name), 3851 condSQL) 3852 3853 if len(orderSQL) > 0 { 3854 switch session.Engine.dialect.DBType() { 3855 case core.POSTGRES: 3856 inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL) 3857 if len(condSQL) > 0 { 3858 realSQL += " AND " + inSQL 3859 } else { 3860 realSQL += " WHERE " + inSQL 3861 } 3862 case core.SQLITE: 3863 inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL) 3864 if len(condSQL) > 0 { 3865 realSQL += " AND " + inSQL 3866 } else { 3867 realSQL += " WHERE " + inSQL 3868 } 3869 // TODO: how to handle delete limit on mssql? 3870 case core.MSSQL: 3871 return 0, ErrNotImplemented 3872 default: 3873 realSQL += orderSQL 3874 } 3875 } 3876 3877 // !oinume! Insert NowTime to the head of session.Statement.Params 3878 condArgs = append(condArgs, "") 3879 paramsLen := len(condArgs) 3880 copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1]) 3881 3882 val, t := session.Engine.NowTime2(deletedColumn.SQLType.Name) 3883 condArgs[0] = val 3884 3885 var colName = deletedColumn.Name 3886 session.afterClosures = append(session.afterClosures, func(bean interface{}) { 3887 col := table.GetColumn(colName) 3888 setColumnTime(bean, col, t) 3889 }) 3890 } 3891 3892 if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache { 3893 session.cacheDelete(deleteSQL, argsForCache...) 3894 } 3895 3896 res, err := session.exec(realSQL, condArgs...) 3897 if err != nil { 3898 return 0, err 3899 } 3900 3901 // handle after delete processors 3902 if session.IsAutoCommit { 3903 for _, closure := range session.afterClosures { 3904 closure(bean) 3905 } 3906 if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok { 3907 processor.AfterDelete() 3908 } 3909 } else { 3910 lenAfterClosures := len(session.afterClosures) 3911 if lenAfterClosures > 0 { 3912 if value, has := session.afterDeleteBeans[bean]; has && value != nil { 3913 *value = append(*value, session.afterClosures...) 3914 } else { 3915 afterClosures := make([]func(interface{}), lenAfterClosures) 3916 copy(afterClosures, session.afterClosures) 3917 session.afterDeleteBeans[bean] = &afterClosures 3918 } 3919 } else { 3920 if _, ok := interface{}(bean).(AfterInsertProcessor); ok { 3921 session.afterDeleteBeans[bean] = nil 3922 } 3923 } 3924 } 3925 cleanupProcessorsClosures(&session.afterClosures) 3926 // -- 3927 3928 return res.RowsAffected() 3929 } 3930 3931 // saveLastSQL stores executed query information 3932 func (session *Session) saveLastSQL(sql string, args ...interface{}) { 3933 session.lastSQL = sql 3934 session.lastSQLArgs = args 3935 session.Engine.logSQL(sql, args...) 3936 } 3937 3938 // LastSQL returns last query information 3939 func (session *Session) LastSQL() (string, []interface{}) { 3940 return session.lastSQL, session.lastSQLArgs 3941 } 3942 3943 // tbName get some table's table name 3944 func (session *Session) tbNameNoSchema(table *core.Table) string { 3945 if len(session.Statement.AltTableName) > 0 { 3946 return session.Statement.AltTableName 3947 } 3948 3949 return table.Name 3950 } 3951 3952 // Sync2 synchronize structs to database tables 3953 func (session *Session) Sync2(beans ...interface{}) error { 3954 engine := session.Engine 3955 3956 tables, err := engine.DBMetas() 3957 if err != nil { 3958 return err 3959 } 3960 3961 var structTables []*core.Table 3962 3963 for _, bean := range beans { 3964 v := rValue(bean) 3965 table := engine.mapType(v) 3966 structTables = append(structTables, table) 3967 var tbName = session.tbNameNoSchema(table) 3968 3969 var oriTable *core.Table 3970 for _, tb := range tables { 3971 if strings.EqualFold(tb.Name, tbName) { 3972 oriTable = tb 3973 break 3974 } 3975 } 3976 3977 if oriTable == nil { 3978 err = session.StoreEngine(session.Statement.StoreEngine).CreateTable(bean) 3979 if err != nil { 3980 return err 3981 } 3982 3983 err = session.CreateUniques(bean) 3984 if err != nil { 3985 return err 3986 } 3987 3988 err = session.CreateIndexes(bean) 3989 if err != nil { 3990 return err 3991 } 3992 } else { 3993 for _, col := range table.Columns() { 3994 var oriCol *core.Column 3995 for _, col2 := range oriTable.Columns() { 3996 if strings.EqualFold(col.Name, col2.Name) { 3997 oriCol = col2 3998 break 3999 } 4000 } 4001 4002 if oriCol != nil { 4003 expectedType := engine.dialect.SqlType(col) 4004 curType := engine.dialect.SqlType(oriCol) 4005 if expectedType != curType { 4006 if expectedType == core.Text && 4007 strings.HasPrefix(curType, core.Varchar) { 4008 // currently only support mysql & postgres 4009 if engine.dialect.DBType() == core.MYSQL || 4010 engine.dialect.DBType() == core.POSTGRES { 4011 engine.logger.Infof("Table %s column %s change type from %s to %s\n", 4012 tbName, col.Name, curType, expectedType) 4013 _, err = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col)) 4014 } else { 4015 engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n", 4016 tbName, col.Name, curType, expectedType) 4017 } 4018 } else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) { 4019 if engine.dialect.DBType() == core.MYSQL { 4020 if oriCol.Length < col.Length { 4021 engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", 4022 tbName, col.Name, oriCol.Length, col.Length) 4023 _, err = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col)) 4024 } 4025 } 4026 } else { 4027 if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') { 4028 engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s", 4029 tbName, col.Name, curType, expectedType) 4030 } 4031 } 4032 } else if expectedType == core.Varchar { 4033 if engine.dialect.DBType() == core.MYSQL { 4034 if oriCol.Length < col.Length { 4035 engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", 4036 tbName, col.Name, oriCol.Length, col.Length) 4037 _, err = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col)) 4038 } 4039 } 4040 } 4041 if col.Default != oriCol.Default { 4042 engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s", 4043 tbName, col.Name, oriCol.Default, col.Default) 4044 } 4045 if col.Nullable != oriCol.Nullable { 4046 engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v", 4047 tbName, col.Name, oriCol.Nullable, col.Nullable) 4048 } 4049 } else { 4050 session := engine.NewSession() 4051 session.Statement.RefTable = table 4052 session.Statement.tableName = tbName 4053 defer session.Close() 4054 err = session.addColumn(col.Name) 4055 } 4056 if err != nil { 4057 return err 4058 } 4059 } 4060 4061 var foundIndexNames = make(map[string]bool) 4062 var addedNames = make(map[string]*core.Index) 4063 4064 for name, index := range table.Indexes { 4065 var oriIndex *core.Index 4066 for name2, index2 := range oriTable.Indexes { 4067 if index.Equal(index2) { 4068 oriIndex = index2 4069 foundIndexNames[name2] = true 4070 break 4071 } 4072 } 4073 4074 if oriIndex != nil { 4075 if oriIndex.Type != index.Type { 4076 sql := engine.dialect.DropIndexSql(tbName, oriIndex) 4077 _, err = engine.Exec(sql) 4078 if err != nil { 4079 return err 4080 } 4081 oriIndex = nil 4082 } 4083 } 4084 4085 if oriIndex == nil { 4086 addedNames[name] = index 4087 } 4088 } 4089 4090 for name2, index2 := range oriTable.Indexes { 4091 if _, ok := foundIndexNames[name2]; !ok { 4092 sql := engine.dialect.DropIndexSql(tbName, index2) 4093 _, err = engine.Exec(sql) 4094 if err != nil { 4095 return err 4096 } 4097 } 4098 } 4099 4100 for name, index := range addedNames { 4101 if index.Type == core.UniqueType { 4102 session := engine.NewSession() 4103 session.Statement.RefTable = table 4104 session.Statement.tableName = tbName 4105 defer session.Close() 4106 err = session.addUnique(tbName, name) 4107 } else if index.Type == core.IndexType { 4108 session := engine.NewSession() 4109 session.Statement.RefTable = table 4110 session.Statement.tableName = tbName 4111 defer session.Close() 4112 err = session.addIndex(tbName, name) 4113 } 4114 if err != nil { 4115 return err 4116 } 4117 } 4118 } 4119 } 4120 4121 for _, table := range tables { 4122 var oriTable *core.Table 4123 for _, structTable := range structTables { 4124 if strings.EqualFold(table.Name, session.tbNameNoSchema(structTable)) { 4125 oriTable = structTable 4126 break 4127 } 4128 } 4129 4130 if oriTable == nil { 4131 //engine.LogWarnf("Table %s has no struct to mapping it", table.Name) 4132 continue 4133 } 4134 4135 for _, colName := range table.ColumnsSeq() { 4136 if oriTable.GetColumn(colName) == nil { 4137 engine.logger.Warnf("Table %s has column %s but struct has not related field", table.Name, colName) 4138 } 4139 } 4140 } 4141 return nil 4142 } 4143 4144 // Unscoped always disable struct tag "deleted" 4145 func (session *Session) Unscoped() *Session { 4146 session.Statement.Unscoped() 4147 return session 4148 }