Browse Source

初始化

xormplus 10 năm trước cách đây
mục cha
commit
c93a5bbd96
36 tập tin đã thay đổi với 17690 bổ sung0 xóa
  1. 3462 0
      cover.out
  2. 1470 0
      engine.go
  3. 166 0
      engineplus.go
  4. 19 0
      error.go
  5. 42 0
      goracle_driver.go
  6. 385 0
      helpers.go
  7. 279 0
      helpersplus.go
  8. 110 0
      logger.go
  9. 289 0
      lru_cacher.go
  10. 47 0
      memroy_store.go
  11. 509 0
      mssql_dialect.go
  12. 69 0
      mymysql_driver.go
  13. 500 0
      mysql_dialect.go
  14. 54 0
      mysql_driver.go
  15. 41 0
      oci8_driver.go
  16. 38 0
      odbc_driver.go
  17. 860 0
      oracle_dialect.go
  18. 746 0
      pg_reserved.txt
  19. 1095 0
      postgres_dialect.go
  20. 119 0
      pq_driver.go
  21. 46 0
      processors.go
  22. 145 0
      rows.go
  23. 4055 0
      session.go
  24. 660 0
      sessionplus.go
  25. 7 0
      sql/oracle/select.example.stpl
  26. 429 0
      sqlite3_dialect.go
  27. 20 0
      sqlite3_driver.go
  28. 1336 0
      statement.go
  29. 63 0
      syslogger.go
  30. 7 0
      test/sql/oracle/select.example.stpl
  31. 9 0
      test/sql/oracle/studygolang.xml
  32. 1 0
      test/sql/xormcfg.ini
  33. 273 0
      test/xorm_test.go
  34. 87 0
      test/测试结果.txt
  35. 111 0
      xorm.go
  36. 141 0
      xormplus.go

+ 3462 - 0
cover.out

@@ -0,0 +1,3462 @@
+mode: set
+github.com\Chronokeeper\activego\odbc_driver.go:21.82,25.23 3 0
+github.com\Chronokeeper\activego\odbc_driver.go:34.2,34.18 1 0
+github.com\Chronokeeper\activego\odbc_driver.go:37.2,37.59 1 0
+github.com\Chronokeeper\activego\odbc_driver.go:25.23,27.19 2 0
+github.com\Chronokeeper\activego\odbc_driver.go:27.19,28.34 1 0
+github.com\Chronokeeper\activego\odbc_driver.go:29.4,30.19 1 0
+github.com\Chronokeeper\activego\odbc_driver.go:34.18,36.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:508.92,510.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:512.50,514.32 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:533.2,535.13 3 0
+github.com\Chronokeeper\activego\oracle_dialect.go:540.2,540.12 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:515.2,516.17 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:517.2,518.19 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:519.2,520.23 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:521.2,522.35 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:523.2,524.17 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:525.2,526.15 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:527.2,528.19 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:529.2,530.10 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:535.13,537.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:537.3,537.20 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:537.20,539.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:543.40,545.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:547.44,549.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:551.48,554.2 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:556.45,558.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:560.37,562.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:564.40,566.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:568.41,570.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:572.46,574.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:576.39,578.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:580.57,582.2 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:584.99,587.21 3 0
+github.com\Chronokeeper\activego\oracle_dialect.go:591.2,595.45 3 0
+github.com\Chronokeeper\activego\oracle_dialect.go:606.2,606.21 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:612.2,613.44 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:616.2,616.24 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:624.2,624.12 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:587.21,589.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:595.45,604.3 4 0
+github.com\Chronokeeper\activego\oracle_dialect.go:606.21,610.3 3 0
+github.com\Chronokeeper\activego\oracle_dialect.go:613.44,615.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:616.24,617.24 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:620.3,620.23 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:617.24,619.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:620.23,622.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:627.84,631.2 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:633.75,636.2 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:638.57,640.22 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:644.2,645.16 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:648.2,650.18 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:654.2,655.22 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:658.2,659.12 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:640.22,642.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:645.16,647.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:650.18,652.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:655.22,657.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:668.83,673.22 4 0
+github.com\Chronokeeper\activego\oracle_dialect.go:676.2,676.16 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:679.2,681.17 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:684.2,684.19 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:673.22,675.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:676.16,678.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:681.17,683.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:687.91,693.22 4 0
+github.com\Chronokeeper\activego\oracle_dialect.go:696.2,696.16 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:699.2,703.18 4 0
+github.com\Chronokeeper\activego\oracle_dialect.go:784.2,784.26 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:693.22,695.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:696.16,698.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:703.18,712.17 6 0
+github.com\Chronokeeper\activego\oracle_dialect.go:716.3,717.24 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:722.3,722.23 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:728.3,734.19 6 0
+github.com\Chronokeeper\activego\oracle_dialect.go:744.3,744.13 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:765.3,765.13 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:769.3,769.52 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:773.3,775.51 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:780.3,781.36 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:712.17,714.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:717.24,720.4 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:722.23,724.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:724.4,726.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:734.19,736.21 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:736.21,739.5 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:739.5,741.5 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:745.3,746.56 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:747.3,748.57 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:749.3,750.53 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:751.3,752.55 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:753.3,754.47 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:755.3,756.49 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:757.3,758.51 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:759.3,760.17 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:761.3,762.63 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:765.13,766.12 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:769.52,771.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:775.51,776.27 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:776.27,778.5 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:787.54,792.22 4 0
+github.com\Chronokeeper\activego\oracle_dialect.go:795.2,795.16 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:798.2,801.18 3 0
+github.com\Chronokeeper\activego\oracle_dialect.go:810.2,810.20 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:792.22,794.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:795.16,797.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:801.18,804.17 3 0
+github.com\Chronokeeper\activego\oracle_dialect.go:808.3,808.33 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:804.17,806.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:813.80,819.22 4 0
+github.com\Chronokeeper\activego\oracle_dialect.go:822.2,822.16 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:825.2,828.18 3 0
+github.com\Chronokeeper\activego\oracle_dialect.go:855.2,855.21 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:819.22,821.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:822.16,824.3 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:828.18,833.17 4 0
+github.com\Chronokeeper\activego\oracle_dialect.go:837.3,839.29 2 0
+github.com\Chronokeeper\activego\oracle_dialect.go:845.3,847.42 3 0
+github.com\Chronokeeper\activego\oracle_dialect.go:853.3,853.27 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:833.17,835.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:839.29,841.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:841.4,843.4 1 0
+github.com\Chronokeeper\activego\oracle_dialect.go:847.42,852.4 4 0
+github.com\Chronokeeper\activego\oracle_dialect.go:858.43,860.2 1 0
+github.com\Chronokeeper\activego\xormplus.go:14.75,16.2 1 0
+github.com\Chronokeeper\activego\xormplus.go:18.74,20.2 1 0
+github.com\Chronokeeper\activego\xormplus.go:22.74,24.2 1 0
+github.com\Chronokeeper\activego\xormplus.go:26.60,28.2 1 1
+github.com\Chronokeeper\activego\xormplus.go:30.57,32.2 1 0
+github.com\Chronokeeper\activego\xormplus.go:34.71,36.2 1 0
+github.com\Chronokeeper\activego\memroy_store.go:21.36,23.2 1 1
+github.com\Chronokeeper\activego\memroy_store.go:25.64,30.2 4 0
+github.com\Chronokeeper\activego\memroy_store.go:32.60,35.31 3 0
+github.com\Chronokeeper\activego\memroy_store.go:39.2,39.25 1 0
+github.com\Chronokeeper\activego\memroy_store.go:35.31,37.3 1 0
+github.com\Chronokeeper\activego\memroy_store.go:42.45,47.2 4 0
+github.com\Chronokeeper\activego\helpersplus.go:11.110,14.19 3 0
+github.com\Chronokeeper\activego\helpersplus.go:56.2,56.8 1 0
+github.com\Chronokeeper\activego\helpersplus.go:15.2,16.19 1 0
+github.com\Chronokeeper\activego\helpersplus.go:17.2,18.20 1 0
+github.com\Chronokeeper\activego\helpersplus.go:19.2,20.21 1 0
+github.com\Chronokeeper\activego\helpersplus.go:21.2,22.22 1 0
+github.com\Chronokeeper\activego\helpersplus.go:23.2,24.27 1 0
+github.com\Chronokeeper\activego\helpersplus.go:34.2,35.26 1 0
+github.com\Chronokeeper\activego\helpersplus.go:42.2,43.20 1 0
+github.com\Chronokeeper\activego\helpersplus.go:44.2,45.23 1 0
+github.com\Chronokeeper\activego\helpersplus.go:53.2,54.67 1 0
+github.com\Chronokeeper\activego\helpersplus.go:25.3,29.24 2 0
+github.com\Chronokeeper\activego\helpersplus.go:30.3,31.68 1 0
+github.com\Chronokeeper\activego\helpersplus.go:35.26,39.4 1 0
+github.com\Chronokeeper\activego\helpersplus.go:39.4,41.4 1 0
+github.com\Chronokeeper\activego\helpersplus.go:59.107,61.16 2 0
+github.com\Chronokeeper\activego\helpersplus.go:64.2,64.8 1 0
+github.com\Chronokeeper\activego\helpersplus.go:61.16,63.3 1 0
+github.com\Chronokeeper\activego\helpersplus.go:67.123,69.16 2 0
+github.com\Chronokeeper\activego\helpersplus.go:72.2,72.18 1 0
+github.com\Chronokeeper\activego\helpersplus.go:80.2,80.26 1 0
+github.com\Chronokeeper\activego\helpersplus.go:69.16,71.3 1 0
+github.com\Chronokeeper\activego\helpersplus.go:72.18,74.17 2 0
+github.com\Chronokeeper\activego\helpersplus.go:77.3,77.46 1 0
+github.com\Chronokeeper\activego\helpersplus.go:74.17,76.4 1 0
+github.com\Chronokeeper\activego\helpersplus.go:83.135,86.35 3 0
+github.com\Chronokeeper\activego\helpersplus.go:90.2,90.59 1 0
+github.com\Chronokeeper\activego\helpersplus.go:94.2,94.30 1 0
+github.com\Chronokeeper\activego\helpersplus.go:110.2,110.20 1 0
+github.com\Chronokeeper\activego\helpersplus.go:86.35,89.3 2 0
+github.com\Chronokeeper\activego\helpersplus.go:90.59,92.3 1 0
+github.com\Chronokeeper\activego\helpersplus.go:94.30,97.34 2 0
+github.com\Chronokeeper\activego\helpersplus.go:102.3,102.81 1 0
+github.com\Chronokeeper\activego\helpersplus.go:97.34,99.12 1 0
+github.com\Chronokeeper\activego\helpersplus.go:102.81,105.4 1 0
+github.com\Chronokeeper\activego\helpersplus.go:105.4,107.4 1 0
+github.com\Chronokeeper\activego\helpersplus.go:113.118,115.16 2 0
+github.com\Chronokeeper\activego\helpersplus.go:118.2,120.30 2 0
+github.com\Chronokeeper\activego\helpersplus.go:115.16,117.3 1 0
+github.com\Chronokeeper\activego\helpersplus.go:123.150,125.16 2 0
+github.com\Chronokeeper\activego\helpersplus.go:128.2,130.56 2 0
+github.com\Chronokeeper\activego\helpersplus.go:125.16,127.3 1 0
+github.com\Chronokeeper\activego\helpersplus.go:133.116,135.16 2 0
+github.com\Chronokeeper\activego\helpersplus.go:138.2,142.16 3 0
+github.com\Chronokeeper\activego\helpersplus.go:145.2,146.30 2 0
+github.com\Chronokeeper\activego\helpersplus.go:135.16,137.3 1 0
+github.com\Chronokeeper\activego\helpersplus.go:142.16,144.3 1 0
+github.com\Chronokeeper\activego\helpersplus.go:149.148,151.16 2 0
+github.com\Chronokeeper\activego\helpersplus.go:154.2,157.16 3 0
+github.com\Chronokeeper\activego\helpersplus.go:160.2,161.56 2 0
+github.com\Chronokeeper\activego\helpersplus.go:151.16,153.3 1 0
+github.com\Chronokeeper\activego\helpersplus.go:157.16,159.3 1 0
+github.com\Chronokeeper\activego\logger.go:29.51,31.2 1 1
+github.com\Chronokeeper\activego\logger.go:33.77,35.2 1 1
+github.com\Chronokeeper\activego\logger.go:37.94,45.2 1 1
+github.com\Chronokeeper\activego\logger.go:47.58,48.55 1 0
+github.com\Chronokeeper\activego\logger.go:51.2,51.8 1 0
+github.com\Chronokeeper\activego\logger.go:48.55,50.3 1 0
+github.com\Chronokeeper\activego\logger.go:54.74,55.55 1 0
+github.com\Chronokeeper\activego\logger.go:58.2,58.8 1 0
+github.com\Chronokeeper\activego\logger.go:55.55,57.3 1 0
+github.com\Chronokeeper\activego\logger.go:61.60,62.57 1 0
+github.com\Chronokeeper\activego\logger.go:65.2,65.8 1 0
+github.com\Chronokeeper\activego\logger.go:62.57,64.3 1 0
+github.com\Chronokeeper\activego\logger.go:68.76,69.57 1 0
+github.com\Chronokeeper\activego\logger.go:72.2,72.8 1 0
+github.com\Chronokeeper\activego\logger.go:69.57,71.3 1 0
+github.com\Chronokeeper\activego\logger.go:75.59,76.56 1 0
+github.com\Chronokeeper\activego\logger.go:79.2,79.8 1 0
+github.com\Chronokeeper\activego\logger.go:76.56,78.3 1 0
+github.com\Chronokeeper\activego\logger.go:82.75,83.56 1 0
+github.com\Chronokeeper\activego\logger.go:86.2,86.8 1 0
+github.com\Chronokeeper\activego\logger.go:83.56,85.3 1 0
+github.com\Chronokeeper\activego\logger.go:89.62,90.59 1 0
+github.com\Chronokeeper\activego\logger.go:93.2,93.8 1 0
+github.com\Chronokeeper\activego\logger.go:90.59,92.3 1 0
+github.com\Chronokeeper\activego\logger.go:96.78,97.59 1 0
+github.com\Chronokeeper\activego\logger.go:100.2,100.8 1 0
+github.com\Chronokeeper\activego\logger.go:97.59,99.3 1 0
+github.com\Chronokeeper\activego\logger.go:103.46,105.2 1 0
+github.com\Chronokeeper\activego\logger.go:107.62,110.2 2 0
+github.com\Chronokeeper\activego\mysql_driver.go:21.83,33.32 5 0
+github.com\Chronokeeper\activego\mysql_driver.go:53.2,53.17 1 0
+github.com\Chronokeeper\activego\mysql_driver.go:33.32,34.19 1 0
+github.com\Chronokeeper\activego\mysql_driver.go:35.3,36.22 1 0
+github.com\Chronokeeper\activego\mysql_driver.go:37.3,38.22 1 0
+github.com\Chronokeeper\activego\mysql_driver.go:38.22,40.28 2 0
+github.com\Chronokeeper\activego\mysql_driver.go:40.28,42.26 2 0
+github.com\Chronokeeper\activego\mysql_driver.go:42.26,43.24 1 0
+github.com\Chronokeeper\activego\mysql_driver.go:44.7,45.31 1 0
+github.com\Chronokeeper\activego\oci8_driver.go:23.82,31.32 5 0
+github.com\Chronokeeper\activego\oci8_driver.go:37.2,37.21 1 0
+github.com\Chronokeeper\activego\oci8_driver.go:40.2,40.16 1 0
+github.com\Chronokeeper\activego\oci8_driver.go:31.32,32.19 1 0
+github.com\Chronokeeper\activego\oci8_driver.go:33.3,34.21 1 0
+github.com\Chronokeeper\activego\oci8_driver.go:37.21,39.3 1 0
+github.com\Chronokeeper\activego\session.go:52.32,66.2 11 1
+github.com\Chronokeeper\activego\session.go:69.33,70.38 1 1
+github.com\Chronokeeper\activego\session.go:74.2,74.23 1 1
+github.com\Chronokeeper\activego\session.go:70.38,72.3 1 1
+github.com\Chronokeeper\activego\session.go:74.23,77.59 1 1
+github.com\Chronokeeper\activego\session.go:80.3,83.19 4 1
+github.com\Chronokeeper\activego\session.go:77.59,79.4 1 0
+github.com\Chronokeeper\activego\session.go:87.42,88.32 1 1
+github.com\Chronokeeper\activego\session.go:88.32,90.3 1 1
+github.com\Chronokeeper\activego\session.go:95.79,98.2 2 0
+github.com\Chronokeeper\activego\session.go:101.81,104.2 2 0
+github.com\Chronokeeper\activego\session.go:107.79,110.2 2 0
+github.com\Chronokeeper\activego\session.go:113.78,116.2 2 0
+github.com\Chronokeeper\activego\session.go:119.53,122.2 2 1
+github.com\Chronokeeper\activego\session.go:125.69,126.21 1 0
+github.com\Chronokeeper\activego\session.go:129.2,129.16 1 0
+github.com\Chronokeeper\activego\session.go:126.21,128.3 1 0
+github.com\Chronokeeper\activego\session.go:133.68,134.21 1 0
+github.com\Chronokeeper\activego\session.go:137.2,137.16 1 0
+github.com\Chronokeeper\activego\session.go:134.21,136.3 1 0
+github.com\Chronokeeper\activego\session.go:141.69,144.2 2 0
+github.com\Chronokeeper\activego\session.go:147.54,150.2 2 0
+github.com\Chronokeeper\activego\session.go:153.73,156.2 2 0
+github.com\Chronokeeper\activego\session.go:159.74,162.2 2 0
+github.com\Chronokeeper\activego\session.go:165.74,168.2 2 0
+github.com\Chronokeeper\activego\session.go:171.76,174.2 2 0
+github.com\Chronokeeper\activego\session.go:177.58,180.2 2 0
+github.com\Chronokeeper\activego\session.go:182.44,185.2 2 0
+github.com\Chronokeeper\activego\session.go:187.62,190.2 2 0
+github.com\Chronokeeper\activego\session.go:192.46,195.2 2 0
+github.com\Chronokeeper\activego\session.go:202.61,205.2 2 0
+github.com\Chronokeeper\activego\session.go:210.62,213.2 2 0
+github.com\Chronokeeper\activego\session.go:216.58,219.2 2 0
+github.com\Chronokeeper\activego\session.go:223.47,226.2 2 0
+github.com\Chronokeeper\activego\session.go:229.65,232.2 2 0
+github.com\Chronokeeper\activego\session.go:236.56,239.2 2 0
+github.com\Chronokeeper\activego\session.go:242.59,245.2 2 0
+github.com\Chronokeeper\activego\session.go:248.58,251.2 2 0
+github.com\Chronokeeper\activego\session.go:254.66,257.2 2 0
+github.com\Chronokeeper\activego\session.go:260.58,263.2 2 0
+github.com\Chronokeeper\activego\session.go:266.63,267.27 1 0
+github.com\Chronokeeper\activego\session.go:270.2,270.16 1 0
+github.com\Chronokeeper\activego\session.go:267.27,269.3 1 0
+github.com\Chronokeeper\activego\session.go:275.44,278.2 2 0
+github.com\Chronokeeper\activego\session.go:281.102,284.2 2 0
+github.com\Chronokeeper\activego\session.go:287.55,290.2 2 0
+github.com\Chronokeeper\activego\session.go:293.60,296.2 2 0
+github.com\Chronokeeper\activego\session.go:298.39,299.23 1 1
+github.com\Chronokeeper\activego\session.go:303.2,303.19 1 1
+github.com\Chronokeeper\activego\session.go:299.23,302.3 2 1
+github.com\Chronokeeper\activego\session.go:307.39,308.26 1 0
+github.com\Chronokeeper\activego\session.go:319.2,319.12 1 0
+github.com\Chronokeeper\activego\session.go:308.26,310.17 2 0
+github.com\Chronokeeper\activego\session.go:313.3,317.45 4 0
+github.com\Chronokeeper\activego\session.go:310.17,312.4 1 0
+github.com\Chronokeeper\activego\session.go:323.42,324.62 1 0
+github.com\Chronokeeper\activego\session.go:329.2,329.12 1 0
+github.com\Chronokeeper\activego\session.go:324.62,328.3 3 0
+github.com\Chronokeeper\activego\session.go:333.40,334.62 1 0
+github.com\Chronokeeper\activego\session.go:382.2,382.12 1 0
+github.com\Chronokeeper\activego\session.go:334.62,338.44 4 0
+github.com\Chronokeeper\activego\session.go:380.3,380.13 1 0
+github.com\Chronokeeper\activego\session.go:338.44,341.80 1 0
+github.com\Chronokeeper\activego\session.go:350.4,350.60 1 0
+github.com\Chronokeeper\activego\session.go:357.4,357.60 1 0
+github.com\Chronokeeper\activego\session.go:364.4,364.60 1 0
+github.com\Chronokeeper\activego\session.go:371.4,371.70 1 0
+github.com\Chronokeeper\activego\session.go:376.4,378.42 3 0
+github.com\Chronokeeper\activego\session.go:341.80,343.27 1 0
+github.com\Chronokeeper\activego\session.go:343.27,344.43 1 0
+github.com\Chronokeeper\activego\session.go:344.43,346.7 1 0
+github.com\Chronokeeper\activego\session.go:350.60,353.70 2 0
+github.com\Chronokeeper\activego\session.go:353.70,355.6 1 0
+github.com\Chronokeeper\activego\session.go:357.60,360.70 2 0
+github.com\Chronokeeper\activego\session.go:360.70,362.6 1 0
+github.com\Chronokeeper\activego\session.go:364.60,367.70 2 0
+github.com\Chronokeeper\activego\session.go:367.70,369.6 1 0
+github.com\Chronokeeper\activego\session.go:371.70,372.25 1 0
+github.com\Chronokeeper\activego\session.go:372.25,374.6 1 0
+github.com\Chronokeeper\activego\session.go:385.61,386.22 1 0
+github.com\Chronokeeper\activego\session.go:386.22,388.3 1 0
+github.com\Chronokeeper\activego\session.go:391.92,393.41 2 0
+github.com\Chronokeeper\activego\session.go:397.2,400.32 3 0
+github.com\Chronokeeper\activego\session.go:433.2,433.12 1 0
+github.com\Chronokeeper\activego\session.go:393.41,395.3 1 0
+github.com\Chronokeeper\activego\session.go:400.32,401.45 1 0
+github.com\Chronokeeper\activego\session.go:407.3,410.25 4 0
+github.com\Chronokeeper\activego\session.go:421.3,421.52 1 0
+github.com\Chronokeeper\activego\session.go:427.3,428.17 2 0
+github.com\Chronokeeper\activego\session.go:401.45,404.12 2 0
+github.com\Chronokeeper\activego\session.go:410.25,412.12 2 0
+github.com\Chronokeeper\activego\session.go:413.4,413.33 1 0
+github.com\Chronokeeper\activego\session.go:413.33,415.29 2 0
+github.com\Chronokeeper\activego\session.go:415.29,417.5 1 0
+github.com\Chronokeeper\activego\session.go:418.4,420.4 1 0
+github.com\Chronokeeper\activego\session.go:421.52,424.12 2 0
+github.com\Chronokeeper\activego\session.go:428.17,430.4 1 0
+github.com\Chronokeeper\activego\session.go:437.91,439.16 2 0
+github.com\Chronokeeper\activego\session.go:444.2,445.16 2 0
+github.com\Chronokeeper\activego\session.go:448.2,448.17 1 0
+github.com\Chronokeeper\activego\session.go:439.16,441.3 1 0
+github.com\Chronokeeper\activego\session.go:445.16,447.3 1 0
+github.com\Chronokeeper\activego\session.go:451.86,452.58 1 0
+github.com\Chronokeeper\activego\session.go:456.2,458.85 2 0
+github.com\Chronokeeper\activego\session.go:452.58,454.3 1 0
+github.com\Chronokeeper\activego\session.go:458.85,459.27 1 0
+github.com\Chronokeeper\activego\session.go:469.3,469.42 1 0
+github.com\Chronokeeper\activego\session.go:459.27,461.54 1 0
+github.com\Chronokeeper\activego\session.go:467.4,467.45 1 0
+github.com\Chronokeeper\activego\session.go:461.54,466.5 4 0
+github.com\Chronokeeper\activego\session.go:474.86,476.25 2 0
+github.com\Chronokeeper\activego\session.go:480.2,480.38 1 0
+github.com\Chronokeeper\activego\session.go:476.25,478.3 1 0
+github.com\Chronokeeper\activego\session.go:484.61,488.25 3 0
+github.com\Chronokeeper\activego\session.go:492.2,492.33 1 0
+github.com\Chronokeeper\activego\session.go:488.25,490.3 1 0
+github.com\Chronokeeper\activego\session.go:496.63,500.25 3 0
+github.com\Chronokeeper\activego\session.go:504.2,505.30 2 0
+github.com\Chronokeeper\activego\session.go:511.2,511.12 1 0
+github.com\Chronokeeper\activego\session.go:500.25,502.3 1 0
+github.com\Chronokeeper\activego\session.go:505.30,507.17 2 0
+github.com\Chronokeeper\activego\session.go:507.17,509.4 1 0
+github.com\Chronokeeper\activego\session.go:515.63,519.25 3 0
+github.com\Chronokeeper\activego\session.go:523.2,524.30 2 0
+github.com\Chronokeeper\activego\session.go:530.2,530.12 1 0
+github.com\Chronokeeper\activego\session.go:519.25,521.3 1 0
+github.com\Chronokeeper\activego\session.go:524.30,526.17 2 0
+github.com\Chronokeeper\activego\session.go:526.17,528.4 1 0
+github.com\Chronokeeper\activego\session.go:533.48,538.2 4 0
+github.com\Chronokeeper\activego\session.go:541.43,543.25 2 0
+github.com\Chronokeeper\activego\session.go:547.2,547.46 1 0
+github.com\Chronokeeper\activego\session.go:554.2,554.12 1 0
+github.com\Chronokeeper\activego\session.go:543.25,545.3 1 0
+github.com\Chronokeeper\activego\session.go:547.46,550.17 3 0
+github.com\Chronokeeper\activego\session.go:550.17,552.4 1 0
+github.com\Chronokeeper\activego\session.go:558.61,560.25 2 0
+github.com\Chronokeeper\activego\session.go:564.2,565.30 2 0
+github.com\Chronokeeper\activego\session.go:571.2,571.12 1 0
+github.com\Chronokeeper\activego\session.go:560.25,562.3 1 0
+github.com\Chronokeeper\activego\session.go:565.30,567.17 2 0
+github.com\Chronokeeper\activego\session.go:567.17,569.4 1 0
+github.com\Chronokeeper\activego\session.go:575.70,577.16 2 0
+github.com\Chronokeeper\activego\session.go:581.2,582.51 2 0
+github.com\Chronokeeper\activego\session.go:591.2,591.14 1 0
+github.com\Chronokeeper\activego\session.go:596.2,596.12 1 0
+github.com\Chronokeeper\activego\session.go:577.16,579.3 1 0
+github.com\Chronokeeper\activego\session.go:582.51,585.17 3 0
+github.com\Chronokeeper\activego\session.go:588.3,588.30 1 0
+github.com\Chronokeeper\activego\session.go:585.17,587.4 1 0
+github.com\Chronokeeper\activego\session.go:591.14,595.3 3 0
+github.com\Chronokeeper\activego\session.go:599.69,601.27 2 0
+github.com\Chronokeeper\activego\session.go:605.2,605.37 1 0
+github.com\Chronokeeper\activego\session.go:601.27,604.3 1 0
+github.com\Chronokeeper\activego\session.go:608.64,609.31 1 0
+github.com\Chronokeeper\activego\session.go:622.2,622.11 1 0
+github.com\Chronokeeper\activego\session.go:609.31,611.21 2 0
+github.com\Chronokeeper\activego\session.go:615.3,617.21 3 0
+github.com\Chronokeeper\activego\session.go:620.3,620.60 1 0
+github.com\Chronokeeper\activego\session.go:611.21,613.4 1 0
+github.com\Chronokeeper\activego\session.go:617.21,619.4 1 0
+github.com\Chronokeeper\activego\session.go:625.110,630.21 1 0
+github.com\Chronokeeper\activego\session.go:634.2,634.58 1 0
+github.com\Chronokeeper\activego\session.go:637.2,638.18 2 0
+github.com\Chronokeeper\activego\session.go:642.2,647.16 6 0
+github.com\Chronokeeper\activego\session.go:689.2,689.18 1 0
+github.com\Chronokeeper\activego\session.go:724.2,724.19 1 0
+github.com\Chronokeeper\activego\session.go:630.21,632.3 1 0
+github.com\Chronokeeper\activego\session.go:634.58,636.3 1 0
+github.com\Chronokeeper\activego\session.go:638.18,640.3 1 0
+github.com\Chronokeeper\activego\session.go:647.16,650.17 3 0
+github.com\Chronokeeper\activego\session.go:653.3,655.18 2 0
+github.com\Chronokeeper\activego\session.go:664.3,665.41 2 0
+github.com\Chronokeeper\activego\session.go:679.3,682.17 4 0
+github.com\Chronokeeper\activego\session.go:650.17,652.4 1 0
+github.com\Chronokeeper\activego\session.go:655.18,657.18 2 0
+github.com\Chronokeeper\activego\session.go:657.18,659.5 1 0
+github.com\Chronokeeper\activego\session.go:660.4,662.4 1 0
+github.com\Chronokeeper\activego\session.go:665.41,666.28 1 0
+github.com\Chronokeeper\activego\session.go:666.28,668.5 1 0
+github.com\Chronokeeper\activego\session.go:668.5,668.38 1 0
+github.com\Chronokeeper\activego\session.go:668.38,670.19 2 0
+github.com\Chronokeeper\activego\session.go:673.5,673.14 1 0
+github.com\Chronokeeper\activego\session.go:670.19,672.6 1 0
+github.com\Chronokeeper\activego\session.go:674.5,676.5 1 0
+github.com\Chronokeeper\activego\session.go:682.17,684.4 1 0
+github.com\Chronokeeper\activego\session.go:685.3,687.3 1 0
+github.com\Chronokeeper\activego\session.go:689.18,694.17 5 0
+github.com\Chronokeeper\activego\session.go:697.3,698.23 2 0
+github.com\Chronokeeper\activego\session.go:720.3,722.18 2 0
+github.com\Chronokeeper\activego\session.go:694.17,696.4 1 0
+github.com\Chronokeeper\activego\session.go:698.23,703.44 5 0
+github.com\Chronokeeper\activego\session.go:706.4,706.37 1 0
+github.com\Chronokeeper\activego\session.go:709.4,710.26 2 0
+github.com\Chronokeeper\activego\session.go:714.4,715.45 2 0
+github.com\Chronokeeper\activego\session.go:703.44,705.5 1 0
+github.com\Chronokeeper\activego\session.go:706.37,708.5 1 0
+github.com\Chronokeeper\activego\session.go:710.26,712.5 1 0
+github.com\Chronokeeper\activego\session.go:716.4,719.4 2 0
+github.com\Chronokeeper\activego\session.go:727.125,731.21 1 0
+github.com\Chronokeeper\activego\session.go:735.2,735.58 1 0
+github.com\Chronokeeper\activego\session.go:739.2,740.18 2 0
+github.com\Chronokeeper\activego\session.go:744.2,747.16 4 0
+github.com\Chronokeeper\activego\session.go:797.2,803.27 6 0
+github.com\Chronokeeper\activego\session.go:829.2,829.19 1 0
+github.com\Chronokeeper\activego\session.go:878.2,878.34 1 0
+github.com\Chronokeeper\activego\session.go:915.2,915.12 1 0
+github.com\Chronokeeper\activego\session.go:731.21,733.3 1 0
+github.com\Chronokeeper\activego\session.go:735.58,737.3 1 0
+github.com\Chronokeeper\activego\session.go:740.18,742.3 1 0
+github.com\Chronokeeper\activego\session.go:747.16,749.17 2 0
+github.com\Chronokeeper\activego\session.go:752.3,756.19 4 0
+github.com\Chronokeeper\activego\session.go:786.3,790.17 4 0
+github.com\Chronokeeper\activego\session.go:749.17,751.4 1 0
+github.com\Chronokeeper\activego\session.go:756.19,758.15 2 0
+github.com\Chronokeeper\activego\session.go:762.4,764.18 3 0
+github.com\Chronokeeper\activego\session.go:768.4,769.42 2 0
+github.com\Chronokeeper\activego\session.go:783.4,783.25 1 0
+github.com\Chronokeeper\activego\session.go:758.15,761.5 2 0
+github.com\Chronokeeper\activego\session.go:764.18,766.5 1 0
+github.com\Chronokeeper\activego\session.go:769.42,770.32 1 0
+github.com\Chronokeeper\activego\session.go:770.32,772.20 2 0
+github.com\Chronokeeper\activego\session.go:775.6,775.15 1 0
+github.com\Chronokeeper\activego\session.go:772.20,774.7 1 0
+github.com\Chronokeeper\activego\session.go:776.6,776.36 1 0
+github.com\Chronokeeper\activego\session.go:776.36,778.6 1 0
+github.com\Chronokeeper\activego\session.go:778.6,780.6 1 0
+github.com\Chronokeeper\activego\session.go:790.17,792.4 1 0
+github.com\Chronokeeper\activego\session.go:793.3,795.3 1 0
+github.com\Chronokeeper\activego\session.go:803.27,805.17 2 0
+github.com\Chronokeeper\activego\session.go:808.3,809.18 2 0
+github.com\Chronokeeper\activego\session.go:805.17,807.4 1 0
+github.com\Chronokeeper\activego\session.go:809.18,812.4 2 0
+github.com\Chronokeeper\activego\session.go:812.4,817.18 4 0
+github.com\Chronokeeper\activego\session.go:821.4,821.18 1 0
+github.com\Chronokeeper\activego\session.go:825.4,825.21 1 0
+github.com\Chronokeeper\activego\session.go:817.18,819.5 1 0
+github.com\Chronokeeper\activego\session.go:821.18,824.5 2 0
+github.com\Chronokeeper\activego\session.go:829.19,836.34 5 0
+github.com\Chronokeeper\activego\session.go:854.3,855.17 2 0
+github.com\Chronokeeper\activego\session.go:859.3,860.33 2 0
+github.com\Chronokeeper\activego\session.go:836.34,838.28 2 0
+github.com\Chronokeeper\activego\session.go:842.4,842.46 1 0
+github.com\Chronokeeper\activego\session.go:838.28,840.5 1 0
+github.com\Chronokeeper\activego\session.go:843.4,845.43 2 0
+github.com\Chronokeeper\activego\session.go:848.4,849.28 2 0
+github.com\Chronokeeper\activego\session.go:845.43,847.5 1 0
+github.com\Chronokeeper\activego\session.go:849.28,851.5 1 0
+github.com\Chronokeeper\activego\session.go:855.17,857.4 1 0
+github.com\Chronokeeper\activego\session.go:860.33,862.32 2 0
+github.com\Chronokeeper\activego\session.go:865.4,868.18 4 0
+github.com\Chronokeeper\activego\session.go:872.4,874.40 3 0
+github.com\Chronokeeper\activego\session.go:862.32,864.5 1 0
+github.com\Chronokeeper\activego\session.go:868.18,870.5 1 0
+github.com\Chronokeeper\activego\session.go:878.34,880.18 2 0
+github.com\Chronokeeper\activego\session.go:885.3,885.41 1 0
+github.com\Chronokeeper\activego\session.go:880.18,883.12 2 0
+github.com\Chronokeeper\activego\session.go:885.41,886.31 1 0
+github.com\Chronokeeper\activego\session.go:886.31,888.5 1 0
+github.com\Chronokeeper\activego\session.go:888.5,890.5 1 0
+github.com\Chronokeeper\activego\session.go:891.4,891.46 1 0
+github.com\Chronokeeper\activego\session.go:891.46,895.21 4 0
+github.com\Chronokeeper\activego\session.go:907.4,907.31 1 0
+github.com\Chronokeeper\activego\session.go:895.21,897.19 2 0
+github.com\Chronokeeper\activego\session.go:897.19,899.6 1 0
+github.com\Chronokeeper\activego\session.go:900.5,901.40 1 0
+github.com\Chronokeeper\activego\session.go:904.5,904.15 1 0
+github.com\Chronokeeper\activego\session.go:901.40,903.6 1 0
+github.com\Chronokeeper\activego\session.go:907.31,909.5 1 0
+github.com\Chronokeeper\activego\session.go:909.5,911.5 1 0
+github.com\Chronokeeper\activego\session.go:923.63,925.2 1 0
+github.com\Chronokeeper\activego\session.go:930.71,932.16 2 0
+github.com\Chronokeeper\activego\session.go:935.2,938.18 3 0
+github.com\Chronokeeper\activego\session.go:950.2,950.12 1 0
+github.com\Chronokeeper\activego\session.go:932.16,934.3 1 0
+github.com\Chronokeeper\activego\session.go:938.18,941.17 3 0
+github.com\Chronokeeper\activego\session.go:944.3,945.17 2 0
+github.com\Chronokeeper\activego\session.go:948.3,948.6 1 0
+github.com\Chronokeeper\activego\session.go:941.17,943.4 1 0
+github.com\Chronokeeper\activego\session.go:945.17,947.4 1 0
+github.com\Chronokeeper\activego\session.go:953.79,958.10 4 1
+github.com\Chronokeeper\activego\session.go:965.2,965.8 1 1
+github.com\Chronokeeper\activego\session.go:958.10,960.17 2 1
+github.com\Chronokeeper\activego\session.go:963.3,963.32 1 1
+github.com\Chronokeeper\activego\session.go:960.17,962.4 1 0
+github.com\Chronokeeper\activego\session.go:970.61,972.25 2 1
+github.com\Chronokeeper\activego\session.go:976.2,980.39 4 1
+github.com\Chronokeeper\activego\session.go:984.2,984.36 1 1
+github.com\Chronokeeper\activego\session.go:991.2,991.37 1 1
+github.com\Chronokeeper\activego\session.go:1002.2,1005.26 4 1
+github.com\Chronokeeper\activego\session.go:1015.2,1015.16 1 1
+github.com\Chronokeeper\activego\session.go:1019.2,1021.20 2 1
+github.com\Chronokeeper\activego\session.go:1027.2,1027.19 1 0
+github.com\Chronokeeper\activego\session.go:972.25,974.3 1 1
+github.com\Chronokeeper\activego\session.go:980.39,982.3 1 1
+github.com\Chronokeeper\activego\session.go:984.36,986.3 1 1
+github.com\Chronokeeper\activego\session.go:986.3,989.3 2 0
+github.com\Chronokeeper\activego\session.go:991.37,994.32 1 1
+github.com\Chronokeeper\activego\session.go:994.32,996.29 2 0
+github.com\Chronokeeper\activego\session.go:996.29,998.5 1 0
+github.com\Chronokeeper\activego\session.go:1005.26,1007.24 2 1
+github.com\Chronokeeper\activego\session.go:1011.3,1011.37 1 1
+github.com\Chronokeeper\activego\session.go:1007.24,1009.4 1 0
+github.com\Chronokeeper\activego\session.go:1012.3,1014.3 1 0
+github.com\Chronokeeper\activego\session.go:1015.16,1017.3 1 0
+github.com\Chronokeeper\activego\session.go:1021.20,1022.51 1 1
+github.com\Chronokeeper\activego\session.go:1025.3,1025.19 1 1
+github.com\Chronokeeper\activego\session.go:1022.51,1024.4 1 1
+github.com\Chronokeeper\activego\session.go:1112.57,1117.36 4 0
+github.com\Chronokeeper\activego\session.go:1120.2,1120.13 1 0
+github.com\Chronokeeper\activego\session.go:1117.36,1119.3 1 0
+github.com\Chronokeeper\activego\session.go:1141.64,1143.25 2 0
+github.com\Chronokeeper\activego\session.go:1147.2,1149.36 3 0
+github.com\Chronokeeper\activego\session.go:1156.2,1157.16 2 0
+github.com\Chronokeeper\activego\session.go:1161.2,1162.27 2 0
+github.com\Chronokeeper\activego\session.go:1170.2,1170.26 1 0
+github.com\Chronokeeper\activego\session.go:1143.25,1145.3 1 0
+github.com\Chronokeeper\activego\session.go:1149.36,1151.3 1 0
+github.com\Chronokeeper\activego\session.go:1151.3,1154.3 2 0
+github.com\Chronokeeper\activego\session.go:1157.16,1159.3 1 0
+github.com\Chronokeeper\activego\session.go:1162.27,1164.33 2 0
+github.com\Chronokeeper\activego\session.go:1164.33,1166.9 2 0
+github.com\Chronokeeper\activego\session.go:1173.59,1176.19 3 0
+github.com\Chronokeeper\activego\session.go:1239.2,1239.20 1 0
+github.com\Chronokeeper\activego\session.go:1177.2,1179.17 2 0
+github.com\Chronokeeper\activego\session.go:1182.2,1184.17 2 0
+github.com\Chronokeeper\activego\session.go:1187.3,1187.19 1 0
+github.com\Chronokeeper\activego\session.go:1188.2,1190.17 2 0
+github.com\Chronokeeper\activego\session.go:1193.3,1193.20 1 0
+github.com\Chronokeeper\activego\session.go:1194.2,1196.17 2 0
+github.com\Chronokeeper\activego\session.go:1199.3,1199.20 1 0
+github.com\Chronokeeper\activego\session.go:1200.2,1202.17 2 0
+github.com\Chronokeeper\activego\session.go:1205.2,1207.17 2 0
+github.com\Chronokeeper\activego\session.go:1210.3,1210.19 1 0
+github.com\Chronokeeper\activego\session.go:1211.2,1213.17 2 0
+github.com\Chronokeeper\activego\session.go:1216.3,1216.20 1 0
+github.com\Chronokeeper\activego\session.go:1217.2,1219.17 2 0
+github.com\Chronokeeper\activego\session.go:1222.3,1222.21 1 0
+github.com\Chronokeeper\activego\session.go:1223.2,1225.17 2 0
+github.com\Chronokeeper\activego\session.go:1228.3,1228.21 1 0
+github.com\Chronokeeper\activego\session.go:1229.2,1231.17 2 0
+github.com\Chronokeeper\activego\session.go:1234.2,1235.13 1 0
+github.com\Chronokeeper\activego\session.go:1236.2,1237.36 1 0
+github.com\Chronokeeper\activego\session.go:1179.17,1181.4 1 0
+github.com\Chronokeeper\activego\session.go:1184.17,1186.4 1 0
+github.com\Chronokeeper\activego\session.go:1190.17,1192.4 1 0
+github.com\Chronokeeper\activego\session.go:1196.17,1198.4 1 0
+github.com\Chronokeeper\activego\session.go:1202.17,1204.4 1 0
+github.com\Chronokeeper\activego\session.go:1207.17,1209.4 1 0
+github.com\Chronokeeper\activego\session.go:1213.17,1215.4 1 0
+github.com\Chronokeeper\activego\session.go:1219.17,1221.4 1 0
+github.com\Chronokeeper\activego\session.go:1225.17,1227.4 1 0
+github.com\Chronokeeper\activego\session.go:1231.17,1233.4 1 0
+github.com\Chronokeeper\activego\session.go:1245.88,1247.25 2 0
+github.com\Chronokeeper\activego\session.go:1251.2,1252.76 2 0
+github.com\Chronokeeper\activego\session.go:1256.2,1258.39 3 0
+github.com\Chronokeeper\activego\session.go:1277.2,1277.24 1 0
+github.com\Chronokeeper\activego\session.go:1292.2,1294.36 3 0
+github.com\Chronokeeper\activego\session.go:1328.2,1329.37 2 0
+github.com\Chronokeeper\activego\session.go:1343.2,1343.38 1 0
+github.com\Chronokeeper\activego\session.go:1453.2,1453.12 1 0
+github.com\Chronokeeper\activego\session.go:1247.25,1249.3 1 0
+github.com\Chronokeeper\activego\session.go:1252.76,1254.3 1 0
+github.com\Chronokeeper\activego\session.go:1258.39,1259.45 1 0
+github.com\Chronokeeper\activego\session.go:1272.3,1272.37 1 0
+github.com\Chronokeeper\activego\session.go:1259.45,1260.56 1 0
+github.com\Chronokeeper\activego\session.go:1260.56,1263.5 2 0
+github.com\Chronokeeper\activego\session.go:1263.5,1265.5 1 0
+github.com\Chronokeeper\activego\session.go:1266.4,1266.55 1 0
+github.com\Chronokeeper\activego\session.go:1266.55,1269.4 2 0
+github.com\Chronokeeper\activego\session.go:1269.4,1271.4 1 0
+github.com\Chronokeeper\activego\session.go:1273.3,1275.3 1 0
+github.com\Chronokeeper\activego\session.go:1277.24,1283.3 3 0
+github.com\Chronokeeper\activego\session.go:1283.3,1286.78 1 0
+github.com\Chronokeeper\activego\session.go:1286.78,1289.4 1 0
+github.com\Chronokeeper\activego\session.go:1294.36,1296.38 2 0
+github.com\Chronokeeper\activego\session.go:1314.3,1320.24 5 0
+github.com\Chronokeeper\activego\session.go:1296.38,1297.23 1 0
+github.com\Chronokeeper\activego\session.go:1297.23,1298.43 1 0
+github.com\Chronokeeper\activego\session.go:1298.43,1300.6 1 0
+github.com\Chronokeeper\activego\session.go:1300.6,1302.6 1 0
+github.com\Chronokeeper\activego\session.go:1304.4,1305.23 1 0
+github.com\Chronokeeper\activego\session.go:1305.23,1306.43 1 0
+github.com\Chronokeeper\activego\session.go:1306.43,1308.6 1 0
+github.com\Chronokeeper\activego\session.go:1308.6,1310.6 1 0
+github.com\Chronokeeper\activego\session.go:1320.24,1322.4 1 0
+github.com\Chronokeeper\activego\session.go:1323.3,1326.3 2 0
+github.com\Chronokeeper\activego\session.go:1329.37,1333.32 1 0
+github.com\Chronokeeper\activego\session.go:1333.32,1335.29 2 0
+github.com\Chronokeeper\activego\session.go:1338.4,1339.47 2 0
+github.com\Chronokeeper\activego\session.go:1335.29,1337.5 1 0
+github.com\Chronokeeper\activego\session.go:1343.38,1349.27 4 0
+github.com\Chronokeeper\activego\session.go:1358.3,1358.17 1 0
+github.com\Chronokeeper\activego\session.go:1361.3,1364.17 3 0
+github.com\Chronokeeper\activego\session.go:1368.3,1371.45 3 0
+github.com\Chronokeeper\activego\session.go:1381.3,1383.41 2 0
+github.com\Chronokeeper\activego\session.go:1395.3,1397.42 3 0
+github.com\Chronokeeper\activego\session.go:1401.3,1403.97 2 0
+github.com\Chronokeeper\activego\session.go:1349.27,1351.18 2 0
+github.com\Chronokeeper\activego\session.go:1354.4,1354.38 1 0
+github.com\Chronokeeper\activego\session.go:1351.18,1353.5 1 0
+github.com\Chronokeeper\activego\session.go:1355.4,1357.4 1 0
+github.com\Chronokeeper\activego\session.go:1358.17,1360.4 1 0
+github.com\Chronokeeper\activego\session.go:1364.17,1366.4 1 0
+github.com\Chronokeeper\activego\session.go:1371.45,1372.39 1 0
+github.com\Chronokeeper\activego\session.go:1372.39,1374.5 1 0
+github.com\Chronokeeper\activego\session.go:1375.4,1376.39 1 0
+github.com\Chronokeeper\activego\session.go:1376.39,1378.5 1 0
+github.com\Chronokeeper\activego\session.go:1383.41,1384.46 1 0
+github.com\Chronokeeper\activego\session.go:1384.46,1385.55 1 0
+github.com\Chronokeeper\activego\session.go:1385.55,1387.6 1 0
+github.com\Chronokeeper\activego\session.go:1388.5,1389.55 1 0
+github.com\Chronokeeper\activego\session.go:1389.55,1391.6 1 0
+github.com\Chronokeeper\activego\session.go:1397.42,1399.4 1 0
+github.com\Chronokeeper\activego\session.go:1404.3,1406.17 2 0
+github.com\Chronokeeper\activego\session.go:1410.3,1412.40 2 0
+github.com\Chronokeeper\activego\session.go:1406.17,1408.4 1 0
+github.com\Chronokeeper\activego\session.go:1412.40,1414.46 2 0
+github.com\Chronokeeper\activego\session.go:1419.4,1420.18 2 0
+github.com\Chronokeeper\activego\session.go:1423.4,1425.35 2 0
+github.com\Chronokeeper\activego\session.go:1446.4,1446.46 1 0
+github.com\Chronokeeper\activego\session.go:1414.46,1416.5 1 0
+github.com\Chronokeeper\activego\session.go:1416.5,1418.5 1 0
+github.com\Chronokeeper\activego\session.go:1420.18,1422.5 1 0
+github.com\Chronokeeper\activego\session.go:1425.35,1427.19 2 0
+github.com\Chronokeeper\activego\session.go:1427.19,1429.6 1 0
+github.com\Chronokeeper\activego\session.go:1430.5,1431.40 1 0
+github.com\Chronokeeper\activego\session.go:1431.40,1433.6 1 0
+github.com\Chronokeeper\activego\session.go:1433.6,1435.43 2 0
+github.com\Chronokeeper\activego\session.go:1442.6,1442.16 1 0
+github.com\Chronokeeper\activego\session.go:1435.43,1437.21 2 0
+github.com\Chronokeeper\activego\session.go:1440.7,1440.32 1 0
+github.com\Chronokeeper\activego\session.go:1437.21,1439.8 1 0
+github.com\Chronokeeper\activego\session.go:1446.46,1448.5 1 0
+github.com\Chronokeeper\activego\session.go:1448.5,1450.5 1 0
+github.com\Chronokeeper\activego\session.go:1471.38,1473.25 2 0
+github.com\Chronokeeper\activego\session.go:1477.2,1477.28 1 0
+github.com\Chronokeeper\activego\session.go:1473.25,1475.3 1 0
+github.com\Chronokeeper\activego\session.go:1492.78,1494.39 2 0
+github.com\Chronokeeper\activego\session.go:1500.2,1500.68 1 0
+github.com\Chronokeeper\activego\session.go:1494.39,1496.3 1 0
+github.com\Chronokeeper\activego\session.go:1496.3,1496.46 1 0
+github.com\Chronokeeper\activego\session.go:1496.46,1499.3 2 0
+github.com\Chronokeeper\activego\session.go:1503.81,1505.16 2 0
+github.com\Chronokeeper\activego\session.go:1509.2,1509.40 1 0
+github.com\Chronokeeper\activego\session.go:1505.16,1507.3 1 0
+github.com\Chronokeeper\activego\session.go:1512.70,1514.25 2 0
+github.com\Chronokeeper\activego\session.go:1517.2,1519.30 3 0
+github.com\Chronokeeper\activego\session.go:1514.25,1516.3 1 0
+github.com\Chronokeeper\activego\session.go:1522.70,1526.32 3 0
+github.com\Chronokeeper\activego\session.go:1533.2,1533.71 1 0
+github.com\Chronokeeper\activego\session.go:1526.32,1528.3 1 0
+github.com\Chronokeeper\activego\session.go:1528.3,1528.39 1 0
+github.com\Chronokeeper\activego\session.go:1528.39,1532.3 3 0
+github.com\Chronokeeper\activego\session.go:1536.70,1538.25 2 0
+github.com\Chronokeeper\activego\session.go:1542.2,1546.16 5 0
+github.com\Chronokeeper\activego\session.go:1550.2,1550.24 1 0
+github.com\Chronokeeper\activego\session.go:1538.25,1540.3 1 0
+github.com\Chronokeeper\activego\session.go:1546.16,1548.3 1 0
+github.com\Chronokeeper\activego\session.go:1553.92,1555.25 2 0
+github.com\Chronokeeper\activego\session.go:1558.2,1559.12 2 0
+github.com\Chronokeeper\activego\session.go:1564.2,1566.30 3 0
+github.com\Chronokeeper\activego\session.go:1555.25,1557.3 1 0
+github.com\Chronokeeper\activego\session.go:1559.12,1561.3 1 0
+github.com\Chronokeeper\activego\session.go:1561.3,1563.3 1 0
+github.com\Chronokeeper\activego\session.go:1570.99,1572.25 2 0
+github.com\Chronokeeper\activego\session.go:1576.2,1577.16 2 0
+github.com\Chronokeeper\activego\session.go:1581.2,1581.32 1 0
+github.com\Chronokeeper\activego\session.go:1590.2,1590.19 1 0
+github.com\Chronokeeper\activego\session.go:1572.25,1574.3 1 0
+github.com\Chronokeeper\activego\session.go:1577.16,1579.3 1 0
+github.com\Chronokeeper\activego\session.go:1581.32,1582.32 1 0
+github.com\Chronokeeper\activego\session.go:1582.32,1583.14 1 0
+github.com\Chronokeeper\activego\session.go:1583.14,1585.5 1 0
+github.com\Chronokeeper\activego\session.go:1585.5,1587.5 1 0
+github.com\Chronokeeper\activego\session.go:1593.57,1595.25 2 0
+github.com\Chronokeeper\activego\session.go:1599.2,1602.12 4 0
+github.com\Chronokeeper\activego\session.go:1595.25,1597.3 1 0
+github.com\Chronokeeper\activego\session.go:1605.67,1607.25 2 0
+github.com\Chronokeeper\activego\session.go:1610.2,1614.12 4 0
+github.com\Chronokeeper\activego\session.go:1607.25,1609.3 1 0
+github.com\Chronokeeper\activego\session.go:1617.68,1619.25 2 0
+github.com\Chronokeeper\activego\session.go:1622.2,1625.12 4 0
+github.com\Chronokeeper\activego\session.go:1619.25,1621.3 1 0
+github.com\Chronokeeper\activego\session.go:1629.41,1631.25 2 0
+github.com\Chronokeeper\activego\session.go:1635.2,1635.46 1 0
+github.com\Chronokeeper\activego\session.go:1644.2,1644.12 1 0
+github.com\Chronokeeper\activego\session.go:1631.25,1633.3 1 0
+github.com\Chronokeeper\activego\session.go:1635.46,1640.17 5 0
+github.com\Chronokeeper\activego\session.go:1640.17,1642.4 1 0
+github.com\Chronokeeper\activego\session.go:1647.116,1649.52 2 1
+github.com\Chronokeeper\activego\session.go:1654.2,1655.16 2 1
+github.com\Chronokeeper\activego\session.go:1660.2,1660.51 1 1
+github.com\Chronokeeper\activego\session.go:1665.2,1665.19 1 1
+github.com\Chronokeeper\activego\session.go:1649.52,1652.3 2 0
+github.com\Chronokeeper\activego\session.go:1655.16,1658.3 2 0
+github.com\Chronokeeper\activego\session.go:1660.51,1664.3 2 0
+github.com\Chronokeeper\activego\session.go:1672.48,1674.18 1 0
+github.com\Chronokeeper\activego\session.go:1685.2,1685.12 1 0
+github.com\Chronokeeper\activego\session.go:1674.18,1679.17 5 0
+github.com\Chronokeeper\activego\session.go:1682.3,1682.31 1 0
+github.com\Chronokeeper\activego\session.go:1679.17,1681.4 1 0
+github.com\Chronokeeper\activego\session.go:1688.109,1690.41 2 1
+github.com\Chronokeeper\activego\session.go:1694.2,1695.79 2 1
+github.com\Chronokeeper\activego\session.go:1690.41,1692.3 1 0
+github.com\Chronokeeper\activego\session.go:1698.156,1700.35 2 1
+github.com\Chronokeeper\activego\session.go:1704.2,1704.50 1 1
+github.com\Chronokeeper\activego\session.go:1708.2,1708.64 1 1
+github.com\Chronokeeper\activego\session.go:1714.2,1715.30 2 1
+github.com\Chronokeeper\activego\session.go:2028.2,2028.12 1 1
+github.com\Chronokeeper\activego\session.go:1700.35,1703.3 2 1
+github.com\Chronokeeper\activego\session.go:1704.50,1706.3 1 0
+github.com\Chronokeeper\activego\session.go:1708.64,1709.31 1 0
+github.com\Chronokeeper\activego\session.go:1709.31,1711.4 1 0
+github.com\Chronokeeper\activego\session.go:1715.30,1718.51 3 1
+github.com\Chronokeeper\activego\session.go:1723.3,1725.85 2 1
+github.com\Chronokeeper\activego\session.go:1718.51,1720.4 1 1
+github.com\Chronokeeper\activego\session.go:1720.4,1722.4 1 0
+github.com\Chronokeeper\activego\session.go:1725.85,1729.35 2 1
+github.com\Chronokeeper\activego\session.go:1733.4,1733.28 1 1
+github.com\Chronokeeper\activego\session.go:1744.4,1744.61 1 1
+github.com\Chronokeeper\activego\session.go:1756.4,1762.28 5 1
+github.com\Chronokeeper\activego\session.go:2018.4,2018.20 1 1
+github.com\Chronokeeper\activego\session.go:1729.35,1730.13 1 0
+github.com\Chronokeeper\activego\session.go:1733.28,1734.81 1 1
+github.com\Chronokeeper\activego\session.go:1734.81,1735.57 1 0
+github.com\Chronokeeper\activego\session.go:1740.6,1740.14 1 0
+github.com\Chronokeeper\activego\session.go:1735.57,1737.7 1 0
+github.com\Chronokeeper\activego\session.go:1737.7,1739.7 1 0
+github.com\Chronokeeper\activego\session.go:1744.61,1745.56 1 0
+github.com\Chronokeeper\activego\session.go:1753.5,1753.13 1 0
+github.com\Chronokeeper\activego\session.go:1745.56,1746.64 1 0
+github.com\Chronokeeper\activego\session.go:1749.6,1749.59 1 0
+github.com\Chronokeeper\activego\session.go:1746.64,1748.7 1 0
+github.com\Chronokeeper\activego\session.go:1750.6,1752.6 1 0
+github.com\Chronokeeper\activego\session.go:1764.4,1765.46 1 0
+github.com\Chronokeeper\activego\session.go:1775.4,1776.32 1 0
+github.com\Chronokeeper\activego\session.go:1786.4,1787.46 1 1
+github.com\Chronokeeper\activego\session.go:1791.4,1792.44 1 0
+github.com\Chronokeeper\activego\session.go:1796.4,1797.32 1 1
+github.com\Chronokeeper\activego\session.go:1802.4,1803.32 1 0
+github.com\Chronokeeper\activego\session.go:1808.4,1809.32 1 0
+github.com\Chronokeeper\activego\session.go:1817.4,1818.47 1 1
+github.com\Chronokeeper\activego\session.go:1899.4,1902.22 1 0
+github.com\Chronokeeper\activego\session.go:1765.46,1769.20 4 0
+github.com\Chronokeeper\activego\session.go:1773.6,1773.30 1 0
+github.com\Chronokeeper\activego\session.go:1769.20,1772.7 2 0
+github.com\Chronokeeper\activego\session.go:1777.5,1778.40 1 0
+github.com\Chronokeeper\activego\session.go:1779.6,1780.51 1 0
+github.com\Chronokeeper\activego\session.go:1780.51,1783.8 2 0
+github.com\Chronokeeper\activego\session.go:1787.46,1790.6 2 0
+github.com\Chronokeeper\activego\session.go:1792.44,1795.6 2 0
+github.com\Chronokeeper\activego\session.go:1798.5,1800.33 2 1
+github.com\Chronokeeper\activego\session.go:1804.5,1806.37 2 0
+github.com\Chronokeeper\activego\session.go:1810.5,1812.35 2 0
+github.com\Chronokeeper\activego\session.go:1813.5,1815.42 2 0
+github.com\Chronokeeper\activego\session.go:1818.47,1819.39 1 1
+github.com\Chronokeeper\activego\session.go:1819.39,1824.39 4 1
+github.com\Chronokeeper\activego\session.go:1830.7,1831.60 2 1
+github.com\Chronokeeper\activego\session.go:1824.39,1828.8 2 1
+github.com\Chronokeeper\activego\session.go:1836.7,1837.38 1 0
+github.com\Chronokeeper\activego\session.go:1837.38,1842.7 4 0
+github.com\Chronokeeper\activego\session.go:1843.6,1843.44 1 0
+github.com\Chronokeeper\activego\session.go:1843.44,1845.22 2 0
+github.com\Chronokeeper\activego\session.go:1845.22,1846.37 1 0
+github.com\Chronokeeper\activego\session.go:1849.7,1850.34 2 0
+github.com\Chronokeeper\activego\session.go:1877.7,1877.24 1 0
+github.com\Chronokeeper\activego\session.go:1846.37,1848.8 1 0
+github.com\Chronokeeper\activego\session.go:1851.7,1852.24 1 0
+github.com\Chronokeeper\activego\session.go:1853.7,1854.29 1 0
+github.com\Chronokeeper\activego\session.go:1855.7,1856.31 1 0
+github.com\Chronokeeper\activego\session.go:1857.7,1858.31 1 0
+github.com\Chronokeeper\activego\session.go:1859.7,1860.30 1 0
+github.com\Chronokeeper\activego\session.go:1861.7,1862.25 1 0
+github.com\Chronokeeper\activego\session.go:1863.7,1864.31 1 0
+github.com\Chronokeeper\activego\session.go:1865.7,1866.33 1 0
+github.com\Chronokeeper\activego\session.go:1867.7,1868.33 1 0
+github.com\Chronokeeper\activego\session.go:1869.7,1870.32 1 0
+github.com\Chronokeeper\activego\session.go:1871.7,1872.27 1 0
+github.com\Chronokeeper\activego\session.go:1873.7,1874.53 1 0
+github.com\Chronokeeper\activego\session.go:1877.24,1885.22 5 0
+github.com\Chronokeeper\activego\session.go:1888.8,1888.15 1 0
+github.com\Chronokeeper\activego\session.go:1885.22,1887.9 1 0
+github.com\Chronokeeper\activego\session.go:1888.15,1891.9 2 0
+github.com\Chronokeeper\activego\session.go:1891.9,1893.9 1 0
+github.com\Chronokeeper\activego\session.go:1895.7,1897.7 1 0
+github.com\Chronokeeper\activego\session.go:1904.5,1905.47 1 0
+github.com\Chronokeeper\activego\session.go:1910.5,1911.45 1 0
+github.com\Chronokeeper\activego\session.go:1916.5,1917.42 1 0
+github.com\Chronokeeper\activego\session.go:1922.5,1923.48 1 0
+github.com\Chronokeeper\activego\session.go:1928.5,1929.46 1 0
+github.com\Chronokeeper\activego\session.go:1934.5,1935.46 1 0
+github.com\Chronokeeper\activego\session.go:1940.5,1941.48 1 0
+github.com\Chronokeeper\activego\session.go:1946.5,1947.46 1 0
+github.com\Chronokeeper\activego\session.go:1952.5,1953.46 1 0
+github.com\Chronokeeper\activego\session.go:1958.5,1959.46 1 0
+github.com\Chronokeeper\activego\session.go:1964.5,1965.46 1 0
+github.com\Chronokeeper\activego\session.go:1970.5,1971.46 1 0
+github.com\Chronokeeper\activego\session.go:1976.5,1977.46 1 0
+github.com\Chronokeeper\activego\session.go:1982.5,1983.46 1 0
+github.com\Chronokeeper\activego\session.go:1988.5,1989.46 1 0
+github.com\Chronokeeper\activego\session.go:1994.5,1997.20 3 0
+github.com\Chronokeeper\activego\session.go:2002.6,2002.24 1 0
+github.com\Chronokeeper\activego\session.go:2003.5,2006.20 3 0
+github.com\Chronokeeper\activego\session.go:2011.6,2011.24 1 0
+github.com\Chronokeeper\activego\session.go:1905.47,1909.7 3 0
+github.com\Chronokeeper\activego\session.go:1911.45,1915.7 3 0
+github.com\Chronokeeper\activego\session.go:1917.42,1921.7 3 0
+github.com\Chronokeeper\activego\session.go:1923.48,1927.7 3 0
+github.com\Chronokeeper\activego\session.go:1929.46,1933.7 3 0
+github.com\Chronokeeper\activego\session.go:1935.46,1939.7 3 0
+github.com\Chronokeeper\activego\session.go:1941.48,1945.7 3 0
+github.com\Chronokeeper\activego\session.go:1947.46,1951.7 3 0
+github.com\Chronokeeper\activego\session.go:1953.46,1957.7 3 0
+github.com\Chronokeeper\activego\session.go:1959.46,1963.7 3 0
+github.com\Chronokeeper\activego\session.go:1965.46,1969.7 3 0
+github.com\Chronokeeper\activego\session.go:1971.46,1975.7 3 0
+github.com\Chronokeeper\activego\session.go:1977.46,1981.7 3 0
+github.com\Chronokeeper\activego\session.go:1983.46,1987.7 3 0
+github.com\Chronokeeper\activego\session.go:1989.46,1993.7 3 0
+github.com\Chronokeeper\activego\session.go:1997.20,1999.7 1 0
+github.com\Chronokeeper\activego\session.go:1999.7,2001.7 1 0
+github.com\Chronokeeper\activego\session.go:2006.20,2008.7 1 0
+github.com\Chronokeeper\activego\session.go:2008.7,2010.7 1 0
+github.com\Chronokeeper\activego\session.go:2018.20,2020.19 2 1
+github.com\Chronokeeper\activego\session.go:2020.19,2022.6 1 1
+github.com\Chronokeeper\activego\session.go:2022.6,2024.6 1 0
+github.com\Chronokeeper\activego\session.go:2032.82,2033.58 1 1
+github.com\Chronokeeper\activego\session.go:2037.2,2037.45 1 1
+github.com\Chronokeeper\activego\session.go:2033.58,2035.3 1 1
+github.com\Chronokeeper\activego\session.go:2040.117,2044.26 2 0
+github.com\Chronokeeper\activego\session.go:2047.2,2047.57 1 0
+github.com\Chronokeeper\activego\session.go:2044.26,2046.3 1 0
+github.com\Chronokeeper\activego\session.go:2050.130,2052.16 2 0
+github.com\Chronokeeper\activego\session.go:2055.2,2057.24 2 0
+github.com\Chronokeeper\activego\session.go:2052.16,2054.3 1 0
+github.com\Chronokeeper\activego\session.go:2060.133,2061.107 1 0
+github.com\Chronokeeper\activego\session.go:2070.2,2070.17 1 0
+github.com\Chronokeeper\activego\session.go:2073.2,2073.17 1 0
+github.com\Chronokeeper\activego\session.go:2076.2,2076.16 1 0
+github.com\Chronokeeper\activego\session.go:2079.2,2079.24 1 0
+github.com\Chronokeeper\activego\session.go:2061.107,2063.17 2 0
+github.com\Chronokeeper\activego\session.go:2066.3,2068.25 2 0
+github.com\Chronokeeper\activego\session.go:2063.17,2065.4 1 0
+github.com\Chronokeeper\activego\session.go:2070.17,2072.3 1 0
+github.com\Chronokeeper\activego\session.go:2073.17,2075.3 1 0
+github.com\Chronokeeper\activego\session.go:2076.16,2078.3 1 0
+github.com\Chronokeeper\activego\session.go:2083.117,2085.25 2 0
+github.com\Chronokeeper\activego\session.go:2089.2,2089.43 1 0
+github.com\Chronokeeper\activego\session.go:2085.25,2087.3 1 0
+github.com\Chronokeeper\activego\session.go:2095.118,2098.26 2 0
+github.com\Chronokeeper\activego\session.go:2101.2,2101.50 1 0
+github.com\Chronokeeper\activego\session.go:2098.26,2100.3 1 0
+github.com\Chronokeeper\activego\session.go:2105.69,2109.25 4 0
+github.com\Chronokeeper\activego\session.go:2113.2,2113.29 1 0
+github.com\Chronokeeper\activego\session.go:2143.2,2143.22 1 0
+github.com\Chronokeeper\activego\session.go:2109.25,2111.3 1 0
+github.com\Chronokeeper\activego\session.go:2113.29,2115.41 2 0
+github.com\Chronokeeper\activego\session.go:2115.41,2117.16 2 0
+github.com\Chronokeeper\activego\session.go:2117.16,2118.43 1 0
+github.com\Chronokeeper\activego\session.go:2118.43,2120.20 2 0
+github.com\Chronokeeper\activego\session.go:2123.6,2123.21 1 0
+github.com\Chronokeeper\activego\session.go:2120.20,2122.7 1 0
+github.com\Chronokeeper\activego\session.go:2124.6,2125.32 1 0
+github.com\Chronokeeper\activego\session.go:2125.32,2127.21 2 0
+github.com\Chronokeeper\activego\session.go:2130.7,2130.22 1 0
+github.com\Chronokeeper\activego\session.go:2127.21,2129.8 1 0
+github.com\Chronokeeper\activego\session.go:2134.4,2136.18 2 0
+github.com\Chronokeeper\activego\session.go:2139.4,2139.19 1 0
+github.com\Chronokeeper\activego\session.go:2136.18,2138.5 1 0
+github.com\Chronokeeper\activego\session.go:2146.83,2148.40 2 0
+github.com\Chronokeeper\activego\session.go:2152.2,2166.28 10 0
+github.com\Chronokeeper\activego\session.go:2268.2,2280.16 4 0
+github.com\Chronokeeper\activego\session.go:2284.2,2284.93 1 0
+github.com\Chronokeeper\activego\session.go:2288.2,2289.28 2 0
+github.com\Chronokeeper\activego\session.go:2316.2,2317.27 2 0
+github.com\Chronokeeper\activego\session.go:2148.40,2150.3 1 0
+github.com\Chronokeeper\activego\session.go:2166.28,2172.50 3 0
+github.com\Chronokeeper\activego\session.go:2176.3,2176.74 1 0
+github.com\Chronokeeper\activego\session.go:2181.3,2181.13 1 0
+github.com\Chronokeeper\activego\session.go:2266.3,2266.73 1 0
+github.com\Chronokeeper\activego\session.go:2172.50,2174.4 1 0
+github.com\Chronokeeper\activego\session.go:2176.74,2178.4 1 0
+github.com\Chronokeeper\activego\session.go:2181.13,2182.40 1 0
+github.com\Chronokeeper\activego\session.go:2182.40,2184.53 2 0
+github.com\Chronokeeper\activego\session.go:2187.5,2187.39 1 0
+github.com\Chronokeeper\activego\session.go:2190.5,2190.22 1 0
+github.com\Chronokeeper\activego\session.go:2193.5,2193.42 1 0
+github.com\Chronokeeper\activego\session.go:2198.5,2198.40 1 0
+github.com\Chronokeeper\activego\session.go:2203.5,2203.74 1 0
+github.com\Chronokeeper\activego\session.go:2220.5,2222.39 3 0
+github.com\Chronokeeper\activego\session.go:2184.53,2185.14 1 0
+github.com\Chronokeeper\activego\session.go:2187.39,2188.14 1 0
+github.com\Chronokeeper\activego\session.go:2190.22,2191.14 1 0
+github.com\Chronokeeper\activego\session.go:2193.42,2194.61 1 0
+github.com\Chronokeeper\activego\session.go:2194.61,2195.15 1 0
+github.com\Chronokeeper\activego\session.go:2198.40,2199.60 1 0
+github.com\Chronokeeper\activego\session.go:2199.60,2200.15 1 0
+github.com\Chronokeeper\activego\session.go:2203.74,2208.83 4 0
+github.com\Chronokeeper\activego\session.go:2208.83,2211.7 2 0
+github.com\Chronokeeper\activego\session.go:2212.6,2214.20 2 0
+github.com\Chronokeeper\activego\session.go:2217.6,2217.30 1 0
+github.com\Chronokeeper\activego\session.go:2214.20,2216.7 1 0
+github.com\Chronokeeper\activego\session.go:2224.4,2225.29 1 0
+github.com\Chronokeeper\activego\session.go:2225.29,2227.53 2 0
+github.com\Chronokeeper\activego\session.go:2230.5,2230.39 1 0
+github.com\Chronokeeper\activego\session.go:2233.5,2233.22 1 0
+github.com\Chronokeeper\activego\session.go:2236.5,2236.42 1 0
+github.com\Chronokeeper\activego\session.go:2241.5,2241.40 1 0
+github.com\Chronokeeper\activego\session.go:2246.5,2246.74 1 0
+github.com\Chronokeeper\activego\session.go:2263.5,2263.39 1 0
+github.com\Chronokeeper\activego\session.go:2227.53,2228.14 1 0
+github.com\Chronokeeper\activego\session.go:2230.39,2231.14 1 0
+github.com\Chronokeeper\activego\session.go:2233.22,2234.14 1 0
+github.com\Chronokeeper\activego\session.go:2236.42,2237.61 1 0
+github.com\Chronokeeper\activego\session.go:2237.61,2238.15 1 0
+github.com\Chronokeeper\activego\session.go:2241.40,2242.60 1 0
+github.com\Chronokeeper\activego\session.go:2242.60,2243.15 1 0
+github.com\Chronokeeper\activego\session.go:2246.74,2251.83 4 0
+github.com\Chronokeeper\activego\session.go:2251.83,2254.7 2 0
+github.com\Chronokeeper\activego\session.go:2255.6,2257.20 2 0
+github.com\Chronokeeper\activego\session.go:2260.6,2260.30 1 0
+github.com\Chronokeeper\activego\session.go:2257.20,2259.7 1 0
+github.com\Chronokeeper\activego\session.go:2280.16,2282.3 1 0
+github.com\Chronokeeper\activego\session.go:2284.93,2286.3 1 0
+github.com\Chronokeeper\activego\session.go:2289.28,2292.27 2 0
+github.com\Chronokeeper\activego\session.go:2292.27,2294.50 1 0
+github.com\Chronokeeper\activego\session.go:2297.4,2297.74 1 0
+github.com\Chronokeeper\activego\session.go:2294.50,2296.5 1 0
+github.com\Chronokeeper\activego\session.go:2297.74,2299.5 1 0
+github.com\Chronokeeper\activego\session.go:2300.4,2301.28 1 0
+github.com\Chronokeeper\activego\session.go:2301.28,2302.79 1 0
+github.com\Chronokeeper\activego\session.go:2302.79,2304.6 1 0
+github.com\Chronokeeper\activego\session.go:2304.6,2308.6 3 0
+github.com\Chronokeeper\activego\session.go:2309.5,2310.67 1 0
+github.com\Chronokeeper\activego\session.go:2310.67,2312.6 1 0
+github.com\Chronokeeper\activego\session.go:2321.78,2323.40 2 0
+github.com\Chronokeeper\activego\session.go:2323.40,2324.27 1 0
+github.com\Chronokeeper\activego\session.go:2324.27,2326.27 2 0
+github.com\Chronokeeper\activego\session.go:2329.4,2329.49 1 0
+github.com\Chronokeeper\activego\session.go:2326.27,2328.5 1 0
+github.com\Chronokeeper\activego\session.go:2330.4,2332.4 1 0
+github.com\Chronokeeper\activego\session.go:2333.3,2335.3 1 0
+github.com\Chronokeeper\activego\session.go:2338.100,2344.34 4 0
+github.com\Chronokeeper\activego\session.go:2395.2,2395.16 1 0
+github.com\Chronokeeper\activego\session.go:2399.2,2400.8 2 0
+github.com\Chronokeeper\activego\session.go:2344.34,2345.3 0 0
+github.com\Chronokeeper\activego\session.go:2345.3,2345.47 1 0
+github.com\Chronokeeper\activego\session.go:2345.47,2348.17 2 0
+github.com\Chronokeeper\activego\session.go:2348.17,2355.4 4 0
+github.com\Chronokeeper\activego\session.go:2355.4,2357.4 1 0
+github.com\Chronokeeper\activego\session.go:2358.3,2358.28 1 0
+github.com\Chronokeeper\activego\session.go:2358.28,2362.17 3 0
+github.com\Chronokeeper\activego\session.go:2366.3,2366.17 1 0
+github.com\Chronokeeper\activego\session.go:2362.17,2365.4 2 0
+github.com\Chronokeeper\activego\session.go:2366.17,2369.4 2 0
+github.com\Chronokeeper\activego\session.go:2371.3,2371.29 1 0
+github.com\Chronokeeper\activego\session.go:2371.29,2374.3 2 0
+github.com\Chronokeeper\activego\session.go:2374.3,2374.67 1 0
+github.com\Chronokeeper\activego\session.go:2374.67,2377.3 2 0
+github.com\Chronokeeper\activego\session.go:2377.3,2377.42 1 0
+github.com\Chronokeeper\activego\session.go:2377.42,2378.35 1 0
+github.com\Chronokeeper\activego\session.go:2383.3,2384.70 2 0
+github.com\Chronokeeper\activego\session.go:2388.3,2390.92 3 0
+github.com\Chronokeeper\activego\session.go:2378.35,2381.4 2 0
+github.com\Chronokeeper\activego\session.go:2384.70,2386.4 1 0
+github.com\Chronokeeper\activego\session.go:2391.3,2394.3 2 0
+github.com\Chronokeeper\activego\session.go:2395.16,2398.3 2 0
+github.com\Chronokeeper\activego\session.go:2404.101,2405.78 1 1
+github.com\Chronokeeper\activego\session.go:2409.2,2409.71 1 1
+github.com\Chronokeeper\activego\session.go:2413.2,2417.26 4 1
+github.com\Chronokeeper\activego\session.go:2962.2,2962.12 1 1
+github.com\Chronokeeper\activego\session.go:2405.78,2407.3 1 0
+github.com\Chronokeeper\activego\session.go:2409.71,2411.3 1 0
+github.com\Chronokeeper\activego\session.go:2418.2,2422.17 3 0
+github.com\Chronokeeper\activego\session.go:2426.3,2426.27 1 0
+github.com\Chronokeeper\activego\session.go:2427.2,2431.27 4 0
+github.com\Chronokeeper\activego\session.go:2454.2,2455.37 1 1
+github.com\Chronokeeper\activego\session.go:2456.2,2459.17 3 0
+github.com\Chronokeeper\activego\session.go:2462.3,2462.37 1 0
+github.com\Chronokeeper\activego\session.go:2463.2,2469.50 4 0
+github.com\Chronokeeper\activego\session.go:2486.3,2486.17 1 0
+github.com\Chronokeeper\activego\session.go:2489.3,2489.23 1 0
+github.com\Chronokeeper\activego\session.go:2490.2,2492.17 2 0
+github.com\Chronokeeper\activego\session.go:2495.3,2495.25 1 0
+github.com\Chronokeeper\activego\session.go:2496.2,2498.17 2 0
+github.com\Chronokeeper\activego\session.go:2501.3,2501.24 1 0
+github.com\Chronokeeper\activego\session.go:2503.2,2504.45 1 0
+github.com\Chronokeeper\activego\session.go:2608.2,2611.20 1 0
+github.com\Chronokeeper\activego\session.go:2958.2,2959.80 1 0
+github.com\Chronokeeper\activego\session.go:2422.17,2425.4 2 0
+github.com\Chronokeeper\activego\session.go:2431.27,2434.18 3 0
+github.com\Chronokeeper\activego\session.go:2438.4,2438.28 1 0
+github.com\Chronokeeper\activego\session.go:2434.18,2437.5 2 0
+github.com\Chronokeeper\activego\session.go:2439.4,2439.34 1 0
+github.com\Chronokeeper\activego\session.go:2439.34,2440.26 1 0
+github.com\Chronokeeper\activego\session.go:2440.26,2442.5 1 0
+github.com\Chronokeeper\activego\session.go:2442.5,2445.19 3 0
+github.com\Chronokeeper\activego\session.go:2449.5,2449.29 1 0
+github.com\Chronokeeper\activego\session.go:2445.19,2448.6 2 0
+github.com\Chronokeeper\activego\session.go:2451.4,2453.4 1 0
+github.com\Chronokeeper\activego\session.go:2459.17,2461.4 1 0
+github.com\Chronokeeper\activego\session.go:2469.50,2470.22 1 0
+github.com\Chronokeeper\activego\session.go:2470.22,2472.5 1 0
+github.com\Chronokeeper\activego\session.go:2472.5,2474.5 1 0
+github.com\Chronokeeper\activego\session.go:2475.4,2475.44 1 0
+github.com\Chronokeeper\activego\session.go:2475.44,2477.4 1 0
+github.com\Chronokeeper\activego\session.go:2477.4,2477.43 1 0
+github.com\Chronokeeper\activego\session.go:2477.43,2479.4 1 0
+github.com\Chronokeeper\activego\session.go:2479.4,2479.46 1 0
+github.com\Chronokeeper\activego\session.go:2479.46,2481.4 1 0
+github.com\Chronokeeper\activego\session.go:2481.4,2481.47 1 0
+github.com\Chronokeeper\activego\session.go:2481.47,2483.4 1 0
+github.com\Chronokeeper\activego\session.go:2483.4,2485.4 1 0
+github.com\Chronokeeper\activego\session.go:2486.17,2488.4 1 0
+github.com\Chronokeeper\activego\session.go:2492.17,2494.4 1 0
+github.com\Chronokeeper\activego\session.go:2498.17,2500.4 1 0
+github.com\Chronokeeper\activego\session.go:2504.45,2506.18 2 0
+github.com\Chronokeeper\activego\session.go:2509.4,2510.57 2 0
+github.com\Chronokeeper\activego\session.go:2506.18,2508.5 1 0
+github.com\Chronokeeper\activego\session.go:2511.4,2511.42 1 0
+github.com\Chronokeeper\activego\session.go:2511.42,2513.20 2 0
+github.com\Chronokeeper\activego\session.go:2513.20,2514.35 1 0
+github.com\Chronokeeper\activego\session.go:2517.5,2519.32 3 0
+github.com\Chronokeeper\activego\session.go:2586.5,2586.22 1 0
+github.com\Chronokeeper\activego\session.go:2514.35,2516.6 1 0
+github.com\Chronokeeper\activego\session.go:2520.5,2522.20 2 0
+github.com\Chronokeeper\activego\session.go:2525.6,2525.15 1 0
+github.com\Chronokeeper\activego\session.go:2526.5,2528.20 2 0
+github.com\Chronokeeper\activego\session.go:2531.6,2531.20 1 0
+github.com\Chronokeeper\activego\session.go:2532.5,2534.20 2 0
+github.com\Chronokeeper\activego\session.go:2537.6,2537.22 1 0
+github.com\Chronokeeper\activego\session.go:2538.5,2540.20 2 0
+github.com\Chronokeeper\activego\session.go:2543.6,2543.22 1 0
+github.com\Chronokeeper\activego\session.go:2544.5,2546.20 2 0
+github.com\Chronokeeper\activego\session.go:2549.6,2549.21 1 0
+github.com\Chronokeeper\activego\session.go:2550.5,2552.20 2 0
+github.com\Chronokeeper\activego\session.go:2555.6,2555.15 1 0
+github.com\Chronokeeper\activego\session.go:2556.5,2558.20 2 0
+github.com\Chronokeeper\activego\session.go:2561.6,2561.21 1 0
+github.com\Chronokeeper\activego\session.go:2562.5,2564.20 2 0
+github.com\Chronokeeper\activego\session.go:2567.6,2567.23 1 0
+github.com\Chronokeeper\activego\session.go:2568.5,2570.20 2 0
+github.com\Chronokeeper\activego\session.go:2573.6,2573.23 1 0
+github.com\Chronokeeper\activego\session.go:2574.5,2576.20 2 0
+github.com\Chronokeeper\activego\session.go:2579.6,2579.22 1 0
+github.com\Chronokeeper\activego\session.go:2580.5,2581.26 1 0
+github.com\Chronokeeper\activego\session.go:2582.5,2583.51 1 0
+github.com\Chronokeeper\activego\session.go:2522.20,2524.7 1 0
+github.com\Chronokeeper\activego\session.go:2528.20,2530.7 1 0
+github.com\Chronokeeper\activego\session.go:2534.20,2536.7 1 0
+github.com\Chronokeeper\activego\session.go:2540.20,2542.7 1 0
+github.com\Chronokeeper\activego\session.go:2546.20,2548.7 1 0
+github.com\Chronokeeper\activego\session.go:2552.20,2554.7 1 0
+github.com\Chronokeeper\activego\session.go:2558.20,2560.7 1 0
+github.com\Chronokeeper\activego\session.go:2564.20,2566.7 1 0
+github.com\Chronokeeper\activego\session.go:2570.20,2572.7 1 0
+github.com\Chronokeeper\activego\session.go:2576.20,2578.7 1 0
+github.com\Chronokeeper\activego\session.go:2586.22,2594.20 5 0
+github.com\Chronokeeper\activego\session.go:2597.6,2597.13 1 0
+github.com\Chronokeeper\activego\session.go:2594.20,2596.7 1 0
+github.com\Chronokeeper\activego\session.go:2597.13,2600.7 2 0
+github.com\Chronokeeper\activego\session.go:2600.7,2602.7 1 0
+github.com\Chronokeeper\activego\session.go:2604.5,2606.5 1 0
+github.com\Chronokeeper\activego\session.go:2613.3,2615.39 2 0
+github.com\Chronokeeper\activego\session.go:2617.3,2620.18 3 0
+github.com\Chronokeeper\activego\session.go:2623.4,2623.39 1 0
+github.com\Chronokeeper\activego\session.go:2625.3,2628.18 3 0
+github.com\Chronokeeper\activego\session.go:2632.4,2632.39 1 0
+github.com\Chronokeeper\activego\session.go:2634.3,2637.18 3 0
+github.com\Chronokeeper\activego\session.go:2641.4,2641.39 1 0
+github.com\Chronokeeper\activego\session.go:2643.3,2645.18 2 0
+github.com\Chronokeeper\activego\session.go:2648.4,2648.39 1 0
+github.com\Chronokeeper\activego\session.go:2650.3,2653.18 3 0
+github.com\Chronokeeper\activego\session.go:2656.4,2657.39 2 0
+github.com\Chronokeeper\activego\session.go:2659.3,2661.18 2 0
+github.com\Chronokeeper\activego\session.go:2664.4,2665.39 2 0
+github.com\Chronokeeper\activego\session.go:2667.3,2670.18 3 0
+github.com\Chronokeeper\activego\session.go:2673.4,2673.39 1 0
+github.com\Chronokeeper\activego\session.go:2675.3,2678.18 3 0
+github.com\Chronokeeper\activego\session.go:2681.4,2682.39 2 0
+github.com\Chronokeeper\activego\session.go:2684.3,2687.18 3 0
+github.com\Chronokeeper\activego\session.go:2690.4,2691.39 2 0
+github.com\Chronokeeper\activego\session.go:2693.3,2696.18 3 0
+github.com\Chronokeeper\activego\session.go:2699.4,2700.39 2 0
+github.com\Chronokeeper\activego\session.go:2702.3,2705.18 3 0
+github.com\Chronokeeper\activego\session.go:2708.4,2709.39 2 0
+github.com\Chronokeeper\activego\session.go:2711.3,2717.60 4 0
+github.com\Chronokeeper\activego\session.go:2730.4,2730.18 1 0
+github.com\Chronokeeper\activego\session.go:2733.4,2733.39 1 0
+github.com\Chronokeeper\activego\session.go:2735.3,2742.60 5 0
+github.com\Chronokeeper\activego\session.go:2758.4,2758.18 1 0
+github.com\Chronokeeper\activego\session.go:2761.4,2761.39 1 0
+github.com\Chronokeeper\activego\session.go:2763.3,2770.51 5 0
+github.com\Chronokeeper\activego\session.go:2786.4,2786.18 1 0
+github.com\Chronokeeper\activego\session.go:2789.4,2789.39 1 0
+github.com\Chronokeeper\activego\session.go:2791.3,2798.60 5 0
+github.com\Chronokeeper\activego\session.go:2814.4,2814.18 1 0
+github.com\Chronokeeper\activego\session.go:2817.4,2817.39 1 0
+github.com\Chronokeeper\activego\session.go:2819.3,2826.60 5 0
+github.com\Chronokeeper\activego\session.go:2842.4,2842.18 1 0
+github.com\Chronokeeper\activego\session.go:2845.4,2845.39 1 0
+github.com\Chronokeeper\activego\session.go:2846.3,2847.49 1 0
+github.com\Chronokeeper\activego\session.go:2956.4,2956.81 1 0
+github.com\Chronokeeper\activego\session.go:2620.18,2622.5 1 0
+github.com\Chronokeeper\activego\session.go:2628.18,2631.5 2 0
+github.com\Chronokeeper\activego\session.go:2637.18,2640.5 2 0
+github.com\Chronokeeper\activego\session.go:2645.18,2647.5 1 0
+github.com\Chronokeeper\activego\session.go:2653.18,2655.5 1 0
+github.com\Chronokeeper\activego\session.go:2661.18,2663.5 1 0
+github.com\Chronokeeper\activego\session.go:2670.18,2672.5 1 0
+github.com\Chronokeeper\activego\session.go:2678.18,2680.5 1 0
+github.com\Chronokeeper\activego\session.go:2687.18,2689.5 1 0
+github.com\Chronokeeper\activego\session.go:2696.18,2698.5 1 0
+github.com\Chronokeeper\activego\session.go:2705.18,2707.5 1 0
+github.com\Chronokeeper\activego\session.go:2717.60,2718.23 1 0
+github.com\Chronokeeper\activego\session.go:2718.23,2720.6 1 0
+github.com\Chronokeeper\activego\session.go:2720.6,2722.6 1 0
+github.com\Chronokeeper\activego\session.go:2723.5,2723.45 1 0
+github.com\Chronokeeper\activego\session.go:2723.45,2725.5 1 0
+github.com\Chronokeeper\activego\session.go:2725.5,2725.44 1 0
+github.com\Chronokeeper\activego\session.go:2725.44,2727.5 1 0
+github.com\Chronokeeper\activego\session.go:2727.5,2729.5 1 0
+github.com\Chronokeeper\activego\session.go:2730.18,2732.5 1 0
+github.com\Chronokeeper\activego\session.go:2742.60,2743.23 1 0
+github.com\Chronokeeper\activego\session.go:2743.23,2745.6 1 0
+github.com\Chronokeeper\activego\session.go:2745.6,2747.6 1 0
+github.com\Chronokeeper\activego\session.go:2748.5,2748.45 1 0
+github.com\Chronokeeper\activego\session.go:2748.45,2751.5 2 0
+github.com\Chronokeeper\activego\session.go:2751.5,2751.44 1 0
+github.com\Chronokeeper\activego\session.go:2751.44,2754.5 2 0
+github.com\Chronokeeper\activego\session.go:2754.5,2757.5 2 0
+github.com\Chronokeeper\activego\session.go:2758.18,2760.5 1 0
+github.com\Chronokeeper\activego\session.go:2770.51,2771.23 1 0
+github.com\Chronokeeper\activego\session.go:2771.23,2773.6 1 0
+github.com\Chronokeeper\activego\session.go:2773.6,2775.6 1 0
+github.com\Chronokeeper\activego\session.go:2776.5,2776.45 1 0
+github.com\Chronokeeper\activego\session.go:2776.45,2779.5 2 0
+github.com\Chronokeeper\activego\session.go:2779.5,2779.44 1 0
+github.com\Chronokeeper\activego\session.go:2779.44,2782.5 2 0
+github.com\Chronokeeper\activego\session.go:2782.5,2785.5 2 0
+github.com\Chronokeeper\activego\session.go:2786.18,2788.5 1 0
+github.com\Chronokeeper\activego\session.go:2798.60,2799.23 1 0
+github.com\Chronokeeper\activego\session.go:2799.23,2801.6 1 0
+github.com\Chronokeeper\activego\session.go:2801.6,2803.6 1 0
+github.com\Chronokeeper\activego\session.go:2804.5,2804.45 1 0
+github.com\Chronokeeper\activego\session.go:2804.45,2807.5 2 0
+github.com\Chronokeeper\activego\session.go:2807.5,2807.44 1 0
+github.com\Chronokeeper\activego\session.go:2807.44,2810.5 2 0
+github.com\Chronokeeper\activego\session.go:2810.5,2813.5 2 0
+github.com\Chronokeeper\activego\session.go:2814.18,2816.5 1 0
+github.com\Chronokeeper\activego\session.go:2826.60,2827.23 1 0
+github.com\Chronokeeper\activego\session.go:2827.23,2829.6 1 0
+github.com\Chronokeeper\activego\session.go:2829.6,2831.6 1 0
+github.com\Chronokeeper\activego\session.go:2832.5,2832.45 1 0
+github.com\Chronokeeper\activego\session.go:2832.45,2835.5 2 0
+github.com\Chronokeeper\activego\session.go:2835.5,2835.44 1 0
+github.com\Chronokeeper\activego\session.go:2835.44,2838.5 2 0
+github.com\Chronokeeper\activego\session.go:2838.5,2841.5 2 0
+github.com\Chronokeeper\activego\session.go:2842.18,2844.5 1 0
+github.com\Chronokeeper\activego\session.go:2847.49,2848.37 1 0
+github.com\Chronokeeper\activego\session.go:2848.37,2851.22 3 0
+github.com\Chronokeeper\activego\session.go:2851.22,2852.37 1 0
+github.com\Chronokeeper\activego\session.go:2855.7,2857.34 3 0
+github.com\Chronokeeper\activego\session.go:2934.7,2934.24 1 0
+github.com\Chronokeeper\activego\session.go:2852.37,2854.8 1 0
+github.com\Chronokeeper\activego\session.go:2858.7,2860.22 2 0
+github.com\Chronokeeper\activego\session.go:2864.8,2864.17 1 0
+github.com\Chronokeeper\activego\session.go:2865.7,2867.22 2 0
+github.com\Chronokeeper\activego\session.go:2871.8,2871.22 1 0
+github.com\Chronokeeper\activego\session.go:2872.7,2874.22 2 0
+github.com\Chronokeeper\activego\session.go:2878.8,2878.24 1 0
+github.com\Chronokeeper\activego\session.go:2879.7,2881.22 2 0
+github.com\Chronokeeper\activego\session.go:2885.8,2885.24 1 0
+github.com\Chronokeeper\activego\session.go:2886.7,2888.22 2 0
+github.com\Chronokeeper\activego\session.go:2892.8,2892.17 1 0
+github.com\Chronokeeper\activego\session.go:2893.7,2895.22 2 0
+github.com\Chronokeeper\activego\session.go:2899.8,2899.17 1 0
+github.com\Chronokeeper\activego\session.go:2900.7,2902.22 2 0
+github.com\Chronokeeper\activego\session.go:2906.8,2906.23 1 0
+github.com\Chronokeeper\activego\session.go:2907.7,2909.22 2 0
+github.com\Chronokeeper\activego\session.go:2913.8,2913.25 1 0
+github.com\Chronokeeper\activego\session.go:2914.7,2916.22 2 0
+github.com\Chronokeeper\activego\session.go:2920.8,2920.25 1 0
+github.com\Chronokeeper\activego\session.go:2921.7,2923.22 2 0
+github.com\Chronokeeper\activego\session.go:2927.8,2927.24 1 0
+github.com\Chronokeeper\activego\session.go:2928.7,2929.28 1 0
+github.com\Chronokeeper\activego\session.go:2930.7,2931.53 1 0
+github.com\Chronokeeper\activego\session.go:2860.22,2862.9 1 0
+github.com\Chronokeeper\activego\session.go:2867.22,2869.9 1 0
+github.com\Chronokeeper\activego\session.go:2874.22,2876.9 1 0
+github.com\Chronokeeper\activego\session.go:2881.22,2883.9 1 0
+github.com\Chronokeeper\activego\session.go:2888.22,2890.9 1 0
+github.com\Chronokeeper\activego\session.go:2895.22,2897.9 1 0
+github.com\Chronokeeper\activego\session.go:2902.22,2904.9 1 0
+github.com\Chronokeeper\activego\session.go:2909.22,2911.9 1 0
+github.com\Chronokeeper\activego\session.go:2916.22,2918.9 1 0
+github.com\Chronokeeper\activego\session.go:2923.22,2925.9 1 0
+github.com\Chronokeeper\activego\session.go:2934.24,2941.22 4 0
+github.com\Chronokeeper\activego\session.go:2944.8,2944.15 1 0
+github.com\Chronokeeper\activego\session.go:2941.22,2943.9 1 0
+github.com\Chronokeeper\activego\session.go:2944.15,2947.9 2 0
+github.com\Chronokeeper\activego\session.go:2947.9,2949.9 1 0
+github.com\Chronokeeper\activego\session.go:2952.6,2954.6 1 0
+github.com\Chronokeeper\activego\session.go:2966.106,2967.26 1 0
+github.com\Chronokeeper\activego\session.go:2978.2,2978.70 1 0
+github.com\Chronokeeper\activego\session.go:2987.2,2989.22 3 0
+github.com\Chronokeeper\activego\session.go:3003.2,3003.11 1 0
+github.com\Chronokeeper\activego\session.go:2967.26,2968.78 1 0
+github.com\Chronokeeper\activego\session.go:2968.78,2970.18 2 0
+github.com\Chronokeeper\activego\session.go:2970.18,2972.5 1 0
+github.com\Chronokeeper\activego\session.go:2972.5,2974.5 1 0
+github.com\Chronokeeper\activego\session.go:2978.70,2980.17 2 0
+github.com\Chronokeeper\activego\session.go:2980.17,2982.4 1 0
+github.com\Chronokeeper\activego\session.go:2982.4,2984.4 1 0
+github.com\Chronokeeper\activego\session.go:2989.22,2990.25 1 0
+github.com\Chronokeeper\activego\session.go:2990.25,2992.4 1 0
+github.com\Chronokeeper\activego\session.go:2992.4,2992.35 1 0
+github.com\Chronokeeper\activego\session.go:2992.35,2995.4 2 0
+github.com\Chronokeeper\activego\session.go:2995.4,3000.4 3 0
+github.com\Chronokeeper\activego\session.go:3004.2,3005.32 1 0
+github.com\Chronokeeper\activego\session.go:3006.2,3007.34 1 0
+github.com\Chronokeeper\activego\session.go:3008.2,3009.33 1 0
+github.com\Chronokeeper\activego\session.go:3024.3,3024.69 1 0
+github.com\Chronokeeper\activego\session.go:3034.2,3036.17 2 0
+github.com\Chronokeeper\activego\session.go:3040.3,3040.28 1 0
+github.com\Chronokeeper\activego\session.go:3041.2,3042.28 1 0
+github.com\Chronokeeper\activego\session.go:3046.3,3046.27 1 0
+github.com\Chronokeeper\activego\session.go:3070.2,3071.39 1 0
+github.com\Chronokeeper\activego\session.go:3072.2,3073.37 1 0
+github.com\Chronokeeper\activego\session.go:3009.33,3010.41 1 0
+github.com\Chronokeeper\activego\session.go:3011.4,3013.54 2 0
+github.com\Chronokeeper\activego\session.go:3018.5,3019.19 2 0
+github.com\Chronokeeper\activego\session.go:3020.4,3021.39 1 0
+github.com\Chronokeeper\activego\session.go:3013.54,3014.20 1 0
+github.com\Chronokeeper\activego\session.go:3014.20,3016.7 1 0
+github.com\Chronokeeper\activego\session.go:3024.69,3025.40 1 0
+github.com\Chronokeeper\activego\session.go:3025.40,3028.5 2 0
+github.com\Chronokeeper\activego\session.go:3028.5,3030.5 1 0
+github.com\Chronokeeper\activego\session.go:3031.4,3033.4 1 0
+github.com\Chronokeeper\activego\session.go:3036.17,3039.4 2 0
+github.com\Chronokeeper\activego\session.go:3042.28,3044.4 1 0
+github.com\Chronokeeper\activego\session.go:3046.27,3048.18 2 0
+github.com\Chronokeeper\activego\session.go:3052.4,3052.29 1 0
+github.com\Chronokeeper\activego\session.go:3048.18,3051.5 2 0
+github.com\Chronokeeper\activego\session.go:3053.4,3053.34 1 0
+github.com\Chronokeeper\activego\session.go:3053.34,3057.56 3 0
+github.com\Chronokeeper\activego\session.go:3066.4,3066.21 1 0
+github.com\Chronokeeper\activego\session.go:3057.56,3059.5 1 0
+github.com\Chronokeeper\activego\session.go:3059.5,3061.19 2 0
+github.com\Chronokeeper\activego\session.go:3061.19,3064.6 2 0
+github.com\Chronokeeper\activego\session.go:3067.4,3069.4 1 0
+github.com\Chronokeeper\activego\session.go:3077.70,3082.49 3 0
+github.com\Chronokeeper\activego\session.go:3085.2,3087.68 2 0
+github.com\Chronokeeper\activego\session.go:3092.2,3093.16 2 0
+github.com\Chronokeeper\activego\session.go:3098.2,3100.32 3 0
+github.com\Chronokeeper\activego\session.go:3114.2,3115.26 2 0
+github.com\Chronokeeper\activego\session.go:3121.2,3130.59 2 0
+github.com\Chronokeeper\activego\session.go:3162.2,3162.79 1 0
+github.com\Chronokeeper\activego\session.go:3082.49,3084.3 1 0
+github.com\Chronokeeper\activego\session.go:3087.68,3089.3 1 0
+github.com\Chronokeeper\activego\session.go:3093.16,3095.3 1 0
+github.com\Chronokeeper\activego\session.go:3100.32,3102.36 1 0
+github.com\Chronokeeper\activego\session.go:3110.3,3111.44 2 0
+github.com\Chronokeeper\activego\session.go:3102.36,3103.28 1 0
+github.com\Chronokeeper\activego\session.go:3103.28,3106.5 2 0
+github.com\Chronokeeper\activego\session.go:3115.26,3117.3 1 0
+github.com\Chronokeeper\activego\session.go:3117.3,3119.3 1 0
+github.com\Chronokeeper\activego\session.go:3130.59,3132.27 1 0
+github.com\Chronokeeper\activego\session.go:3156.3,3156.52 1 0
+github.com\Chronokeeper\activego\session.go:3132.27,3133.50 1 0
+github.com\Chronokeeper\activego\session.go:3136.4,3136.69 1 0
+github.com\Chronokeeper\activego\session.go:3133.50,3135.5 1 0
+github.com\Chronokeeper\activego\session.go:3136.69,3138.5 1 0
+github.com\Chronokeeper\activego\session.go:3139.4,3141.28 2 0
+github.com\Chronokeeper\activego\session.go:3141.28,3142.74 1 0
+github.com\Chronokeeper\activego\session.go:3142.74,3144.6 1 0
+github.com\Chronokeeper\activego\session.go:3144.6,3148.6 3 0
+github.com\Chronokeeper\activego\session.go:3150.5,3151.62 1 0
+github.com\Chronokeeper\activego\session.go:3151.62,3153.6 1 0
+github.com\Chronokeeper\activego\session.go:3162.79,3164.17 2 0
+github.com\Chronokeeper\activego\session.go:3170.3,3170.94 1 0
+github.com\Chronokeeper\activego\session.go:3174.3,3174.60 1 0
+github.com\Chronokeeper\activego\session.go:3183.3,3183.32 1 0
+github.com\Chronokeeper\activego\session.go:3187.3,3189.28 3 0
+github.com\Chronokeeper\activego\session.go:3193.3,3194.17 2 0
+github.com\Chronokeeper\activego\session.go:3198.3,3198.90 1 0
+github.com\Chronokeeper\activego\session.go:3202.3,3203.32 2 0
+github.com\Chronokeeper\activego\session.go:3215.3,3217.28 2 0
+github.com\Chronokeeper\activego\session.go:3164.17,3166.4 1 0
+github.com\Chronokeeper\activego\session.go:3166.4,3168.4 1 0
+github.com\Chronokeeper\activego\session.go:3170.94,3172.4 1 0
+github.com\Chronokeeper\activego\session.go:3174.60,3176.18 2 0
+github.com\Chronokeeper\activego\session.go:3176.18,3178.5 1 0
+github.com\Chronokeeper\activego\session.go:3178.5,3178.54 1 0
+github.com\Chronokeeper\activego\session.go:3178.54,3180.5 1 0
+github.com\Chronokeeper\activego\session.go:3183.32,3185.4 1 0
+github.com\Chronokeeper\activego\session.go:3189.28,3191.4 1 0
+github.com\Chronokeeper\activego\session.go:3194.17,3196.4 1 0
+github.com\Chronokeeper\activego\session.go:3198.90,3200.4 1 0
+github.com\Chronokeeper\activego\session.go:3204.3,3205.17 1 0
+github.com\Chronokeeper\activego\session.go:3206.3,3207.15 1 0
+github.com\Chronokeeper\activego\session.go:3208.3,3209.18 1 0
+github.com\Chronokeeper\activego\session.go:3210.3,3211.18 1 0
+github.com\Chronokeeper\activego\session.go:3212.3,3213.16 1 0
+github.com\Chronokeeper\activego\session.go:3218.3,3223.17 3 0
+github.com\Chronokeeper\activego\session.go:3229.3,3229.94 1 0
+github.com\Chronokeeper\activego\session.go:3233.3,3233.60 1 0
+github.com\Chronokeeper\activego\session.go:3242.3,3242.19 1 0
+github.com\Chronokeeper\activego\session.go:3246.3,3248.17 3 0
+github.com\Chronokeeper\activego\session.go:3252.3,3253.17 2 0
+github.com\Chronokeeper\activego\session.go:3257.3,3257.85 1 0
+github.com\Chronokeeper\activego\session.go:3261.3,3262.32 2 0
+github.com\Chronokeeper\activego\session.go:3274.3,3276.16 2 0
+github.com\Chronokeeper\activego\session.go:3223.17,3225.4 1 0
+github.com\Chronokeeper\activego\session.go:3225.4,3227.4 1 0
+github.com\Chronokeeper\activego\session.go:3229.94,3231.4 1 0
+github.com\Chronokeeper\activego\session.go:3233.60,3235.18 2 0
+github.com\Chronokeeper\activego\session.go:3235.18,3237.5 1 0
+github.com\Chronokeeper\activego\session.go:3237.5,3237.54 1 0
+github.com\Chronokeeper\activego\session.go:3237.54,3239.5 1 0
+github.com\Chronokeeper\activego\session.go:3242.19,3244.4 1 0
+github.com\Chronokeeper\activego\session.go:3248.17,3250.4 1 0
+github.com\Chronokeeper\activego\session.go:3253.17,3255.4 1 0
+github.com\Chronokeeper\activego\session.go:3257.85,3259.4 1 0
+github.com\Chronokeeper\activego\session.go:3263.3,3264.17 1 0
+github.com\Chronokeeper\activego\session.go:3265.3,3266.15 1 0
+github.com\Chronokeeper\activego\session.go:3267.3,3268.18 1 0
+github.com\Chronokeeper\activego\session.go:3269.3,3270.18 1 0
+github.com\Chronokeeper\activego\session.go:3271.3,3272.16 1 0
+github.com\Chronokeeper\activego\session.go:3283.68,3285.25 2 0
+github.com\Chronokeeper\activego\session.go:3289.2,3289.34 1 0
+github.com\Chronokeeper\activego\session.go:3285.25,3287.3 1 0
+github.com\Chronokeeper\activego\session.go:3292.78,3293.75 1 0
+github.com\Chronokeeper\activego\session.go:3297.2,3299.20 3 0
+github.com\Chronokeeper\activego\session.go:3307.2,3311.56 3 0
+github.com\Chronokeeper\activego\session.go:3317.2,3317.19 1 0
+github.com\Chronokeeper\activego\session.go:3328.2,3330.12 1 0
+github.com\Chronokeeper\activego\session.go:3293.75,3295.3 1 0
+github.com\Chronokeeper\activego\session.go:3299.20,3300.21 1 0
+github.com\Chronokeeper\activego\session.go:3304.3,3304.16 1 0
+github.com\Chronokeeper\activego\session.go:3300.21,3303.4 1 0
+github.com\Chronokeeper\activego\session.go:3311.56,3313.3 1 0
+github.com\Chronokeeper\activego\session.go:3313.3,3313.60 1 0
+github.com\Chronokeeper\activego\session.go:3313.60,3315.3 1 0
+github.com\Chronokeeper\activego\session.go:3317.19,3318.41 1 0
+github.com\Chronokeeper\activego\session.go:3318.41,3321.34 3 0
+github.com\Chronokeeper\activego\session.go:3321.34,3324.5 2 0
+github.com\Chronokeeper\activego\session.go:3333.61,3334.39 1 0
+github.com\Chronokeeper\activego\session.go:3338.2,3341.27 3 0
+github.com\Chronokeeper\activego\session.go:3346.2,3346.12 1 0
+github.com\Chronokeeper\activego\session.go:3334.39,3336.3 1 0
+github.com\Chronokeeper\activego\session.go:3341.27,3344.3 2 0
+github.com\Chronokeeper\activego\session.go:3349.79,3351.21 1 0
+github.com\Chronokeeper\activego\session.go:3355.2,3356.18 2 0
+github.com\Chronokeeper\activego\session.go:3359.2,3359.58 1 0
+github.com\Chronokeeper\activego\session.go:3362.2,3365.19 3 0
+github.com\Chronokeeper\activego\session.go:3373.2,3378.16 6 0
+github.com\Chronokeeper\activego\session.go:3415.2,3415.25 1 0
+github.com\Chronokeeper\activego\session.go:3466.2,3468.12 3 0
+github.com\Chronokeeper\activego\session.go:3351.21,3353.3 1 0
+github.com\Chronokeeper\activego\session.go:3356.18,3358.3 1 0
+github.com\Chronokeeper\activego\session.go:3359.58,3361.3 1 0
+github.com\Chronokeeper\activego\session.go:3365.19,3366.38 1 0
+github.com\Chronokeeper\activego\session.go:3366.38,3368.4 1 0
+github.com\Chronokeeper\activego\session.go:3368.4,3371.4 1 0
+github.com\Chronokeeper\activego\session.go:3378.16,3380.17 2 0
+github.com\Chronokeeper\activego\session.go:3383.3,3386.19 3 0
+github.com\Chronokeeper\activego\session.go:3409.3,3409.64 1 0
+github.com\Chronokeeper\activego\session.go:3380.17,3382.4 1 0
+github.com\Chronokeeper\activego\session.go:3386.19,3389.18 3 0
+github.com\Chronokeeper\activego\session.go:3392.4,3393.42 2 0
+github.com\Chronokeeper\activego\session.go:3407.4,3407.25 1 0
+github.com\Chronokeeper\activego\session.go:3389.18,3391.5 1 0
+github.com\Chronokeeper\activego\session.go:3393.42,3394.32 1 0
+github.com\Chronokeeper\activego\session.go:3394.32,3396.20 2 0
+github.com\Chronokeeper\activego\session.go:3399.6,3399.15 1 0
+github.com\Chronokeeper\activego\session.go:3396.20,3398.7 1 0
+github.com\Chronokeeper\activego\session.go:3400.6,3400.36 1 0
+github.com\Chronokeeper\activego\session.go:3400.36,3402.6 1 0
+github.com\Chronokeeper\activego\session.go:3402.6,3404.6 1 0
+github.com\Chronokeeper\activego\session.go:3415.25,3417.17 2 0
+github.com\Chronokeeper\activego\session.go:3420.3,3420.58 1 0
+github.com\Chronokeeper\activego\session.go:3417.17,3419.4 1 0
+github.com\Chronokeeper\activego\session.go:3420.58,3422.39 2 0
+github.com\Chronokeeper\activego\session.go:3426.4,3427.22 2 0
+github.com\Chronokeeper\activego\session.go:3430.4,3431.29 2 0
+github.com\Chronokeeper\activego\session.go:3462.4,3463.40 2 0
+github.com\Chronokeeper\activego\session.go:3422.39,3424.5 1 0
+github.com\Chronokeeper\activego\session.go:3427.22,3429.5 1 0
+github.com\Chronokeeper\activego\session.go:3431.29,3435.39 4 0
+github.com\Chronokeeper\activego\session.go:3444.5,3444.52 1 0
+github.com\Chronokeeper\activego\session.go:3435.39,3437.6 1 0
+github.com\Chronokeeper\activego\session.go:3437.6,3437.68 1 0
+github.com\Chronokeeper\activego\session.go:3437.68,3439.6 1 0
+github.com\Chronokeeper\activego\session.go:3439.6,3442.6 2 0
+github.com\Chronokeeper\activego\session.go:3444.52,3446.20 2 0
+github.com\Chronokeeper\activego\session.go:3446.20,3448.7 1 0
+github.com\Chronokeeper\activego\session.go:3448.7,3450.58 2 0
+github.com\Chronokeeper\activego\session.go:3450.58,3452.8 1 0
+github.com\Chronokeeper\activego\session.go:3452.8,3454.8 1 0
+github.com\Chronokeeper\activego\session.go:3456.6,3459.6 1 0
+github.com\Chronokeeper\activego\session.go:3477.91,3479.25 2 0
+github.com\Chronokeeper\activego\session.go:3483.2,3490.49 5 0
+github.com\Chronokeeper\activego\session.go:3493.2,3494.68 2 0
+github.com\Chronokeeper\activego\session.go:3499.2,3500.32 2 0
+github.com\Chronokeeper\activego\session.go:3531.2,3531.58 1 0
+github.com\Chronokeeper\activego\session.go:3545.2,3546.31 2 0
+github.com\Chronokeeper\activego\session.go:3551.2,3552.31 2 0
+github.com\Chronokeeper\activego\session.go:3557.2,3558.32 2 0
+github.com\Chronokeeper\activego\session.go:3562.2,3565.24 3 0
+github.com\Chronokeeper\activego\session.go:3571.2,3575.23 5 0
+github.com\Chronokeeper\activego\session.go:3579.2,3579.21 1 0
+github.com\Chronokeeper\activego\session.go:3590.2,3594.59 5 0
+github.com\Chronokeeper\activego\session.go:3650.2,3655.16 5 0
+github.com\Chronokeeper\activego\session.go:3663.2,3663.93 1 0
+github.com\Chronokeeper\activego\session.go:3669.2,3669.26 1 0
+github.com\Chronokeeper\activego\session.go:3694.2,3697.27 2 0
+github.com\Chronokeeper\activego\session.go:3479.25,3481.3 1 0
+github.com\Chronokeeper\activego\session.go:3490.49,3492.3 1 0
+github.com\Chronokeeper\activego\session.go:3494.68,3496.3 1 0
+github.com\Chronokeeper\activego\session.go:3500.32,3504.40 3 0
+github.com\Chronokeeper\activego\session.go:3504.40,3508.4 1 0
+github.com\Chronokeeper\activego\session.go:3508.4,3510.18 2 0
+github.com\Chronokeeper\activego\session.go:3510.18,3512.5 1 0
+github.com\Chronokeeper\activego\session.go:3514.3,3514.36 1 0
+github.com\Chronokeeper\activego\session.go:3514.36,3515.40 1 0
+github.com\Chronokeeper\activego\session.go:3518.3,3523.38 5 0
+github.com\Chronokeeper\activego\session.go:3515.40,3517.4 1 0
+github.com\Chronokeeper\activego\session.go:3523.38,3526.4 2 0
+github.com\Chronokeeper\activego\session.go:3527.3,3529.3 1 0
+github.com\Chronokeeper\activego\session.go:3531.58,3538.80 6 0
+github.com\Chronokeeper\activego\session.go:3538.80,3541.4 2 0
+github.com\Chronokeeper\activego\session.go:3546.31,3549.3 2 0
+github.com\Chronokeeper\activego\session.go:3552.31,3555.3 2 0
+github.com\Chronokeeper\activego\session.go:3558.32,3560.3 1 0
+github.com\Chronokeeper\activego\session.go:3565.24,3569.3 1 0
+github.com\Chronokeeper\activego\session.go:3575.23,3577.3 1 0
+github.com\Chronokeeper\activego\session.go:3579.21,3580.29 1 0
+github.com\Chronokeeper\activego\session.go:3580.29,3582.4 1 0
+github.com\Chronokeeper\activego\session.go:3583.3,3584.29 1 0
+github.com\Chronokeeper\activego\session.go:3584.29,3587.4 1 0
+github.com\Chronokeeper\activego\session.go:3594.59,3595.22 1 0
+github.com\Chronokeeper\activego\session.go:3601.3,3602.21 2 0
+github.com\Chronokeeper\activego\session.go:3610.3,3610.20 1 0
+github.com\Chronokeeper\activego\session.go:3614.3,3621.17 3 0
+github.com\Chronokeeper\activego\session.go:3625.3,3626.18 2 0
+github.com\Chronokeeper\activego\session.go:3595.22,3598.4 1 0
+github.com\Chronokeeper\activego\session.go:3598.4,3600.4 1 0
+github.com\Chronokeeper\activego\session.go:3602.21,3603.23 1 0
+github.com\Chronokeeper\activego\session.go:3603.23,3605.5 1 0
+github.com\Chronokeeper\activego\session.go:3605.5,3607.5 1 0
+github.com\Chronokeeper\activego\session.go:3610.20,3612.4 1 0
+github.com\Chronokeeper\activego\session.go:3621.17,3623.4 1 0
+github.com\Chronokeeper\activego\session.go:3627.3,3628.22 1 0
+github.com\Chronokeeper\activego\session.go:3631.3,3632.21 2 0
+github.com\Chronokeeper\activego\session.go:3640.3,3640.20 1 0
+github.com\Chronokeeper\activego\session.go:3644.3,3647.14 1 0
+github.com\Chronokeeper\activego\session.go:3628.22,3630.4 1 0
+github.com\Chronokeeper\activego\session.go:3632.21,3633.23 1 0
+github.com\Chronokeeper\activego\session.go:3633.23,3635.5 1 0
+github.com\Chronokeeper\activego\session.go:3635.5,3637.5 1 0
+github.com\Chronokeeper\activego\session.go:3640.20,3642.4 1 0
+github.com\Chronokeeper\activego\session.go:3655.16,3657.3 1 0
+github.com\Chronokeeper\activego\session.go:3657.3,3657.21 1 0
+github.com\Chronokeeper\activego\session.go:3657.21,3658.65 1 0
+github.com\Chronokeeper\activego\session.go:3658.65,3660.4 1 0
+github.com\Chronokeeper\activego\session.go:3663.93,3666.3 2 0
+github.com\Chronokeeper\activego\session.go:3669.26,3670.49 1 0
+github.com\Chronokeeper\activego\session.go:3673.3,3673.68 1 0
+github.com\Chronokeeper\activego\session.go:3670.49,3672.4 1 0
+github.com\Chronokeeper\activego\session.go:3673.68,3676.4 2 0
+github.com\Chronokeeper\activego\session.go:3677.3,3679.27 2 0
+github.com\Chronokeeper\activego\session.go:3679.27,3680.73 1 0
+github.com\Chronokeeper\activego\session.go:3680.73,3682.5 1 0
+github.com\Chronokeeper\activego\session.go:3682.5,3686.5 3 0
+github.com\Chronokeeper\activego\session.go:3688.4,3689.61 1 0
+github.com\Chronokeeper\activego\session.go:3689.61,3691.5 1 0
+github.com\Chronokeeper\activego\session.go:3700.79,3702.21 1 0
+github.com\Chronokeeper\activego\session.go:3706.2,3706.58 1 0
+github.com\Chronokeeper\activego\session.go:3710.2,3711.18 2 0
+github.com\Chronokeeper\activego\session.go:3715.2,3718.16 4 0
+github.com\Chronokeeper\activego\session.go:3753.2,3753.25 1 0
+github.com\Chronokeeper\activego\session.go:3761.2,3763.12 3 0
+github.com\Chronokeeper\activego\session.go:3702.21,3704.3 1 0
+github.com\Chronokeeper\activego\session.go:3706.58,3708.3 1 0
+github.com\Chronokeeper\activego\session.go:3711.18,3713.3 1 0
+github.com\Chronokeeper\activego\session.go:3718.16,3720.17 2 0
+github.com\Chronokeeper\activego\session.go:3723.3,3724.28 2 0
+github.com\Chronokeeper\activego\session.go:3720.17,3722.4 1 0
+github.com\Chronokeeper\activego\session.go:3724.28,3725.38 1 0
+github.com\Chronokeeper\activego\session.go:3725.38,3728.64 3 0
+github.com\Chronokeeper\activego\session.go:3745.5,3745.26 1 0
+github.com\Chronokeeper\activego\session.go:3728.64,3729.38 1 0
+github.com\Chronokeeper\activego\session.go:3729.38,3731.7 1 0
+github.com\Chronokeeper\activego\session.go:3731.7,3732.31 1 0
+github.com\Chronokeeper\activego\session.go:3732.31,3734.8 1 0
+github.com\Chronokeeper\activego\session.go:3734.8,3734.41 1 0
+github.com\Chronokeeper\activego\session.go:3734.41,3736.22 2 0
+github.com\Chronokeeper\activego\session.go:3739.8,3739.27 1 0
+github.com\Chronokeeper\activego\session.go:3736.22,3738.9 1 0
+github.com\Chronokeeper\activego\session.go:3740.8,3742.8 1 0
+github.com\Chronokeeper\activego\session.go:3753.25,3756.17 3 0
+github.com\Chronokeeper\activego\session.go:3759.3,3759.33 1 0
+github.com\Chronokeeper\activego\session.go:3756.17,3758.4 1 0
+github.com\Chronokeeper\activego\session.go:3767.65,3769.25 2 0
+github.com\Chronokeeper\activego\session.go:3774.2,3774.49 1 0
+github.com\Chronokeeper\activego\session.go:3777.2,3779.68 2 0
+github.com\Chronokeeper\activego\session.go:3784.2,3794.38 7 0
+github.com\Chronokeeper\activego\session.go:3802.2,3803.20 2 0
+github.com\Chronokeeper\activego\session.go:3810.2,3810.25 1 0
+github.com\Chronokeeper\activego\session.go:3814.2,3816.64 3 0
+github.com\Chronokeeper\activego\session.go:3851.2,3853.114 2 0
+github.com\Chronokeeper\activego\session.go:3857.2,3858.16 2 0
+github.com\Chronokeeper\activego\session.go:3863.2,3863.26 1 0
+github.com\Chronokeeper\activego\session.go:3886.2,3889.27 2 0
+github.com\Chronokeeper\activego\session.go:3769.25,3771.3 1 0
+github.com\Chronokeeper\activego\session.go:3774.49,3776.3 1 0
+github.com\Chronokeeper\activego\session.go:3779.68,3781.3 1 0
+github.com\Chronokeeper\activego\session.go:3794.38,3796.24 2 0
+github.com\Chronokeeper\activego\session.go:3796.24,3798.4 1 0
+github.com\Chronokeeper\activego\session.go:3799.3,3801.3 1 0
+github.com\Chronokeeper\activego\session.go:3803.20,3804.25 1 0
+github.com\Chronokeeper\activego\session.go:3807.3,3808.33 2 0
+github.com\Chronokeeper\activego\session.go:3804.25,3806.4 1 0
+github.com\Chronokeeper\activego\session.go:3810.25,3812.3 1 0
+github.com\Chronokeeper\activego\session.go:3816.64,3823.3 4 0
+github.com\Chronokeeper\activego\session.go:3823.3,3845.80 12 0
+github.com\Chronokeeper\activego\session.go:3845.80,3848.4 2 0
+github.com\Chronokeeper\activego\session.go:3853.114,3855.3 1 0
+github.com\Chronokeeper\activego\session.go:3858.16,3860.3 1 0
+github.com\Chronokeeper\activego\session.go:3863.26,3864.49 1 0
+github.com\Chronokeeper\activego\session.go:3867.3,3867.68 1 0
+github.com\Chronokeeper\activego\session.go:3864.49,3866.4 1 0
+github.com\Chronokeeper\activego\session.go:3867.68,3869.4 1 0
+github.com\Chronokeeper\activego\session.go:3870.3,3872.27 2 0
+github.com\Chronokeeper\activego\session.go:3872.27,3873.73 1 0
+github.com\Chronokeeper\activego\session.go:3873.73,3875.5 1 0
+github.com\Chronokeeper\activego\session.go:3875.5,3879.5 3 0
+github.com\Chronokeeper\activego\session.go:3880.4,3881.61 1 0
+github.com\Chronokeeper\activego\session.go:3881.61,3883.5 1 0
+github.com\Chronokeeper\activego\session.go:3892.53,3896.16 3 0
+github.com\Chronokeeper\activego\session.go:3900.2,3902.29 2 0
+github.com\Chronokeeper\activego\session.go:4032.2,4032.31 1 0
+github.com\Chronokeeper\activego\session.go:4053.2,4053.12 1 0
+github.com\Chronokeeper\activego\session.go:3896.16,3898.3 1 0
+github.com\Chronokeeper\activego\session.go:3902.29,3907.29 4 0
+github.com\Chronokeeper\activego\session.go:3914.3,3914.22 1 0
+github.com\Chronokeeper\activego\session.go:3907.29,3908.29 1 0
+github.com\Chronokeeper\activego\session.go:3908.29,3910.10 2 0
+github.com\Chronokeeper\activego\session.go:3914.22,3916.18 2 0
+github.com\Chronokeeper\activego\session.go:3920.4,3921.18 2 0
+github.com\Chronokeeper\activego\session.go:3925.4,3926.18 2 0
+github.com\Chronokeeper\activego\session.go:3916.18,3918.5 1 0
+github.com\Chronokeeper\activego\session.go:3921.18,3923.5 1 0
+github.com\Chronokeeper\activego\session.go:3926.18,3928.5 1 0
+github.com\Chronokeeper\activego\session.go:3929.4,3930.40 1 0
+github.com\Chronokeeper\activego\session.go:3979.4,3981.43 2 0
+github.com\Chronokeeper\activego\session.go:4020.4,4020.48 1 0
+github.com\Chronokeeper\activego\session.go:3930.40,3932.45 2 0
+github.com\Chronokeeper\activego\session.go:3939.5,3939.22 1 0
+github.com\Chronokeeper\activego\session.go:3974.5,3974.19 1 0
+github.com\Chronokeeper\activego\session.go:3932.45,3933.31 1 0
+github.com\Chronokeeper\activego\session.go:3933.31,3935.12 2 0
+github.com\Chronokeeper\activego\session.go:3939.22,3942.33 3 0
+github.com\Chronokeeper\activego\session.go:3960.6,3960.39 1 0
+github.com\Chronokeeper\activego\session.go:3964.6,3964.41 1 0
+github.com\Chronokeeper\activego\session.go:3942.33,3944.49 1 0
+github.com\Chronokeeper\activego\session.go:3944.49,3947.50 1 0
+github.com\Chronokeeper\activego\session.go:3947.50,3951.9 2 0
+github.com\Chronokeeper\activego\session.go:3951.9,3954.9 1 0
+github.com\Chronokeeper\activego\session.go:3955.8,3958.8 1 0
+github.com\Chronokeeper\activego\session.go:3960.39,3963.7 1 0
+github.com\Chronokeeper\activego\session.go:3964.41,3967.7 1 0
+github.com\Chronokeeper\activego\session.go:3968.6,3973.6 4 0
+github.com\Chronokeeper\activego\session.go:3974.19,3976.6 1 0
+github.com\Chronokeeper\activego\session.go:3981.43,3983.49 2 0
+github.com\Chronokeeper\activego\session.go:3991.5,3991.24 1 0
+github.com\Chronokeeper\activego\session.go:4002.5,4002.24 1 0
+github.com\Chronokeeper\activego\session.go:3983.49,3984.29 1 0
+github.com\Chronokeeper\activego\session.go:3984.29,3987.12 3 0
+github.com\Chronokeeper\activego\session.go:3991.24,3992.37 1 0
+github.com\Chronokeeper\activego\session.go:3992.37,3995.21 3 0
+github.com\Chronokeeper\activego\session.go:3998.7,3998.21 1 0
+github.com\Chronokeeper\activego\session.go:3995.21,3997.8 1 0
+github.com\Chronokeeper\activego\session.go:4002.24,4003.39 1 0
+github.com\Chronokeeper\activego\session.go:4014.6,4014.20 1 0
+github.com\Chronokeeper\activego\session.go:4003.39,4008.7 4 0
+github.com\Chronokeeper\activego\session.go:4008.7,4008.45 1 0
+github.com\Chronokeeper\activego\session.go:4008.45,4013.7 4 0
+github.com\Chronokeeper\activego\session.go:4014.20,4016.7 1 0
+github.com\Chronokeeper\activego\session.go:4020.48,4021.45 1 0
+github.com\Chronokeeper\activego\session.go:4021.45,4024.20 3 0
+github.com\Chronokeeper\activego\session.go:4024.20,4026.7 1 0
+github.com\Chronokeeper\activego\session.go:4032.31,4034.44 2 0
+github.com\Chronokeeper\activego\session.go:4041.3,4041.22 1 0
+github.com\Chronokeeper\activego\session.go:4046.3,4046.46 1 0
+github.com\Chronokeeper\activego\session.go:4034.44,4035.38 1 0
+github.com\Chronokeeper\activego\session.go:4035.38,4037.10 2 0
+github.com\Chronokeeper\activego\session.go:4041.22,4043.12 2 0
+github.com\Chronokeeper\activego\session.go:4046.46,4047.42 1 0
+github.com\Chronokeeper\activego\session.go:4047.42,4050.5 1 0
+github.com\Chronokeeper\activego\session.go:4057.45,4060.2 2 0
+github.com\Chronokeeper\activego\engineplus.go:11.79,15.2 3 0
+github.com\Chronokeeper\activego\engineplus.go:17.78,21.2 3 0
+github.com\Chronokeeper\activego\engineplus.go:23.133,27.2 3 0
+github.com\Chronokeeper\activego\engineplus.go:30.119,34.2 3 0
+github.com\Chronokeeper\activego\engineplus.go:37.121,41.2 3 0
+github.com\Chronokeeper\activego\engineplus.go:43.98,47.16 4 0
+github.com\Chronokeeper\activego\engineplus.go:50.2,50.34 1 0
+github.com\Chronokeeper\activego\engineplus.go:47.16,49.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:53.131,57.16 4 0
+github.com\Chronokeeper\activego\engineplus.go:60.2,60.34 1 0
+github.com\Chronokeeper\activego\engineplus.go:57.16,59.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:63.96,67.16 4 0
+github.com\Chronokeeper\activego\engineplus.go:70.2,70.34 1 0
+github.com\Chronokeeper\activego\engineplus.go:67.16,69.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:73.129,77.16 4 0
+github.com\Chronokeeper\activego\engineplus.go:80.2,80.34 1 0
+github.com\Chronokeeper\activego\engineplus.go:77.16,79.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:83.95,87.16 4 1
+github.com\Chronokeeper\activego\engineplus.go:91.2,92.16 2 1
+github.com\Chronokeeper\activego\engineplus.go:95.2,95.29 1 1
+github.com\Chronokeeper\activego\engineplus.go:87.16,89.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:92.16,94.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:98.131,102.16 4 1
+github.com\Chronokeeper\activego\engineplus.go:105.2,106.16 2 1
+github.com\Chronokeeper\activego\engineplus.go:109.2,109.29 1 1
+github.com\Chronokeeper\activego\engineplus.go:102.16,104.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:106.16,108.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:112.128,116.16 4 1
+github.com\Chronokeeper\activego\engineplus.go:119.2,120.16 2 1
+github.com\Chronokeeper\activego\engineplus.go:123.2,123.29 1 1
+github.com\Chronokeeper\activego\engineplus.go:116.16,118.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:120.16,122.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:126.164,130.16 4 1
+github.com\Chronokeeper\activego\engineplus.go:133.2,135.16 2 1
+github.com\Chronokeeper\activego\engineplus.go:138.2,138.29 1 1
+github.com\Chronokeeper\activego\engineplus.go:130.16,132.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:135.16,137.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:141.65,144.16 3 1
+github.com\Chronokeeper\activego\engineplus.go:149.2,149.16 1 1
+github.com\Chronokeeper\activego\engineplus.go:152.2,152.28 1 1
+github.com\Chronokeeper\activego\engineplus.go:144.16,146.3 1 1
+github.com\Chronokeeper\activego\engineplus.go:146.3,148.3 1 0
+github.com\Chronokeeper\activego\engineplus.go:149.16,151.3 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:29.73,31.2 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:33.97,42.2 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:49.29,50.38 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:50.38,53.3 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:57.26,63.39 4 0
+github.com\Chronokeeper\activego\lru_cacher.go:78.2,79.40 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:63.39,65.60 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:65.60,72.4 5 0
+github.com\Chronokeeper\activego\lru_cacher.go:72.4,74.9 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:79.40,81.61 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:81.61,88.4 5 0
+github.com\Chronokeeper\activego\lru_cacher.go:88.4,90.9 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:96.63,99.41 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:102.2,102.44 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:121.2,121.12 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:99.41,101.3 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:102.44,103.48 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:116.3,116.11 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:103.48,106.4 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:106.4,109.44 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:113.4,114.46 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:109.44,112.5 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:117.3,119.3 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:125.70,128.40 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:131.2,132.44 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:128.40,130.3 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:132.44,133.45 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:147.3,147.11 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:133.45,136.44 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:141.4,142.45 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:136.44,140.5 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:143.4,146.4 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:148.3,153.3 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:157.48,158.42 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:164.2,164.56 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:158.42,159.27 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:159.27,162.4 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:167.48,171.2 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:173.50,174.41 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:181.2,181.55 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:174.41,175.26 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:175.26,179.4 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:184.50,188.2 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:190.68,193.41 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:196.2,196.47 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:202.2,203.40 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:193.41,195.3 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:196.47,199.3 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:199.3,201.3 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:203.40,207.3 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:210.75,216.44 5 0
+github.com\Chronokeeper\activego\lru_cacher.go:223.2,224.39 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:216.44,219.3 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:219.3,221.3 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:224.39,228.3 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:231.51,232.40 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:238.2,238.18 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:232.40,233.47 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:233.47,236.4 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:241.51,245.2 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:247.58,249.44 2 0
+github.com\Chronokeeper\activego\lru_cacher.go:254.2,254.18 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:249.44,253.3 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:257.58,261.2 3 0
+github.com\Chronokeeper\activego\lru_cacher.go:275.53,277.2 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:279.45,281.2 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:283.50,285.2 1 0
+github.com\Chronokeeper\activego\lru_cacher.go:287.46,289.2 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:775.94,777.2 1 1
+github.com\Chronokeeper\activego\postgres_dialect.go:779.52,781.32 2 1
+github.com\Chronokeeper\activego\postgres_dialect.go:819.2,821.13 3 0
+github.com\Chronokeeper\activego\postgres_dialect.go:826.2,826.12 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:782.2,784.13 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:785.2,786.24 1 1
+github.com\Chronokeeper\activego\postgres_dialect.go:789.3,789.22 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:790.2,793.10 3 0
+github.com\Chronokeeper\activego\postgres_dialect.go:794.2,795.20 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:796.2,797.23 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:798.2,799.36 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:800.2,801.18 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:802.2,803.18 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:804.2,805.21 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:806.2,807.18 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:808.2,809.20 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:810.2,811.28 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:812.2,813.24 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:816.3,816.10 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:786.24,788.4 1 1
+github.com\Chronokeeper\activego\postgres_dialect.go:813.24,815.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:821.13,823.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:823.3,823.20 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:823.20,825.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:829.46,831.2 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:833.50,836.2 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:838.47,840.2 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:842.39,844.2 1 1
+github.com\Chronokeeper\activego\postgres_dialect.go:846.42,848.2 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:850.42,852.2 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:854.43,856.2 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:858.41,860.2 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:862.86,866.2 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:868.77,871.2 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:879.80,882.2 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:884.78,889.39 3 0
+github.com\Chronokeeper\activego\postgres_dialect.go:896.2,896.53 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:889.39,890.36 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:890.36,892.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:892.4,894.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:899.85,904.22 4 0
+github.com\Chronokeeper\activego\postgres_dialect.go:907.2,907.16 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:910.2,912.25 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:904.22,906.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:907.16,909.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:915.93,930.22 4 0
+github.com\Chronokeeper\activego\postgres_dialect.go:933.2,933.16 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:936.2,941.18 4 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1013.2,1013.26 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:930.22,932.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:933.16,935.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:941.18,949.17 7 0
+github.com\Chronokeeper\activego\postgres_dialect.go:954.3,955.23 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:962.3,964.32 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:972.3,972.70 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:976.3,978.19 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:994.3,994.52 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:998.3,1000.51 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1009.3,1010.36 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:949.17,951.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:955.23,957.18 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:957.18,959.5 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:964.32,965.12 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:965.12,967.5 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:967.5,969.5 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:972.70,974.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:979.3,980.50 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:981.3,982.51 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:983.3,984.53 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:985.3,986.49 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:987.3,988.47 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:989.3,990.47 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:991.3,992.63 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:994.52,996.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1000.51,1001.25 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1001.25,1003.5 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1003.5,1004.27 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1004.27,1006.6 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1016.56,1021.22 4 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1024.2,1024.16 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1027.2,1030.18 3 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1040.2,1040.20 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1021.22,1023.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1024.16,1026.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1030.18,1034.17 4 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1037.3,1038.33 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1034.17,1036.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1043.82,1048.22 4 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1051.2,1051.16 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1054.2,1057.18 3 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1090.2,1090.21 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1048.22,1050.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1051.16,1053.3 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1057.18,1062.17 5 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1065.3,1066.44 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1069.3,1069.57 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1074.3,1077.103 3 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1084.3,1085.36 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1088.3,1088.30 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1062.17,1064.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1066.44,1067.12 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1069.57,1071.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1071.4,1073.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1077.103,1079.24 2 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1079.24,1081.5 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1085.36,1087.4 1 0
+github.com\Chronokeeper\activego\postgres_dialect.go:1093.45,1095.2 1 1
+github.com\Chronokeeper\activego\sessionplus.go:19.81,21.24 2 1
+github.com\Chronokeeper\activego\sessionplus.go:24.2,25.17 2 1
+github.com\Chronokeeper\activego\sessionplus.go:28.2,28.26 1 1
+github.com\Chronokeeper\activego\sessionplus.go:21.24,23.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:25.17,27.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:31.80,34.24 2 0
+github.com\Chronokeeper\activego\sessionplus.go:38.2,41.16 4 0
+github.com\Chronokeeper\activego\sessionplus.go:45.2,47.17 2 0
+github.com\Chronokeeper\activego\sessionplus.go:50.2,50.34 1 0
+github.com\Chronokeeper\activego\sessionplus.go:34.24,36.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:41.16,43.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:47.17,49.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:53.135,56.24 2 0
+github.com\Chronokeeper\activego\sessionplus.go:60.2,63.16 4 0
+github.com\Chronokeeper\activego\sessionplus.go:67.2,68.17 2 0
+github.com\Chronokeeper\activego\sessionplus.go:71.2,71.34 1 0
+github.com\Chronokeeper\activego\sessionplus.go:56.24,58.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:63.16,65.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:68.17,70.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:96.124,99.26 2 1
+github.com\Chronokeeper\activego\sessionplus.go:102.2,102.50 1 0
+github.com\Chronokeeper\activego\sessionplus.go:99.26,101.3 1 1
+github.com\Chronokeeper\activego\sessionplus.go:105.126,110.26 3 0
+github.com\Chronokeeper\activego\sessionplus.go:113.2,113.48 1 0
+github.com\Chronokeeper\activego\sessionplus.go:110.26,112.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:116.159,121.26 3 0
+github.com\Chronokeeper\activego\sessionplus.go:124.2,124.74 1 0
+github.com\Chronokeeper\activego\sessionplus.go:121.26,123.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:127.157,130.26 2 0
+github.com\Chronokeeper\activego\sessionplus.go:133.2,133.76 1 0
+github.com\Chronokeeper\activego\sessionplus.go:130.26,132.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:136.98,138.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:141.2,141.34 1 0
+github.com\Chronokeeper\activego\sessionplus.go:138.16,140.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:144.97,147.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:150.2,151.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:154.2,154.29 1 0
+github.com\Chronokeeper\activego\sessionplus.go:147.16,149.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:151.16,153.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:157.133,159.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:162.2,163.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:166.2,166.29 1 0
+github.com\Chronokeeper\activego\sessionplus.go:159.16,161.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:163.16,165.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:169.130,171.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:174.2,175.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:178.2,178.29 1 0
+github.com\Chronokeeper\activego\sessionplus.go:171.16,173.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:175.16,177.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:181.166,183.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:186.2,188.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:191.2,191.29 1 0
+github.com\Chronokeeper\activego\sessionplus.go:183.16,185.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:188.16,190.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:194.100,196.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:199.2,199.34 1 0
+github.com\Chronokeeper\activego\sessionplus.go:196.16,198.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:202.133,204.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:207.2,207.34 1 0
+github.com\Chronokeeper\activego\sessionplus.go:204.16,206.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:210.131,212.16 2 0
+github.com\Chronokeeper\activego\sessionplus.go:215.2,215.34 1 0
+github.com\Chronokeeper\activego\sessionplus.go:212.16,214.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:218.142,220.41 2 0
+github.com\Chronokeeper\activego\sessionplus.go:224.2,225.105 2 0
+github.com\Chronokeeper\activego\sessionplus.go:220.41,222.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:228.189,230.35 2 0
+github.com\Chronokeeper\activego\sessionplus.go:234.2,234.50 1 0
+github.com\Chronokeeper\activego\sessionplus.go:238.2,238.64 1 0
+github.com\Chronokeeper\activego\sessionplus.go:244.2,245.30 2 0
+github.com\Chronokeeper\activego\sessionplus.go:562.2,562.12 1 0
+github.com\Chronokeeper\activego\sessionplus.go:230.35,233.3 2 0
+github.com\Chronokeeper\activego\sessionplus.go:234.50,236.3 1 0
+github.com\Chronokeeper\activego\sessionplus.go:238.64,239.31 1 0
+github.com\Chronokeeper\activego\sessionplus.go:239.31,241.4 1 0
+github.com\Chronokeeper\activego\sessionplus.go:245.30,248.51 3 0
+github.com\Chronokeeper\activego\sessionplus.go:253.3,255.85 2 0
+github.com\Chronokeeper\activego\sessionplus.go:248.51,250.4 1 0
+github.com\Chronokeeper\activego\sessionplus.go:250.4,252.4 1 0
+github.com\Chronokeeper\activego\sessionplus.go:255.85,259.35 2 0
+github.com\Chronokeeper\activego\sessionplus.go:263.4,263.28 1 0
+github.com\Chronokeeper\activego\sessionplus.go:274.4,274.61 1 0
+github.com\Chronokeeper\activego\sessionplus.go:286.4,292.28 5 0
+github.com\Chronokeeper\activego\sessionplus.go:552.4,552.20 1 0
+github.com\Chronokeeper\activego\sessionplus.go:259.35,260.13 1 0
+github.com\Chronokeeper\activego\sessionplus.go:263.28,264.81 1 0
+github.com\Chronokeeper\activego\sessionplus.go:264.81,265.57 1 0
+github.com\Chronokeeper\activego\sessionplus.go:270.6,270.14 1 0
+github.com\Chronokeeper\activego\sessionplus.go:265.57,267.7 1 0
+github.com\Chronokeeper\activego\sessionplus.go:267.7,269.7 1 0
+github.com\Chronokeeper\activego\sessionplus.go:274.61,275.56 1 0
+github.com\Chronokeeper\activego\sessionplus.go:283.5,283.13 1 0
+github.com\Chronokeeper\activego\sessionplus.go:275.56,276.64 1 0
+github.com\Chronokeeper\activego\sessionplus.go:279.6,279.59 1 0
+github.com\Chronokeeper\activego\sessionplus.go:276.64,278.7 1 0
+github.com\Chronokeeper\activego\sessionplus.go:280.6,282.6 1 0
+github.com\Chronokeeper\activego\sessionplus.go:294.4,295.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:305.4,306.32 1 0
+github.com\Chronokeeper\activego\sessionplus.go:316.4,317.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:321.4,322.44 1 0
+github.com\Chronokeeper\activego\sessionplus.go:326.4,327.32 1 0
+github.com\Chronokeeper\activego\sessionplus.go:332.4,333.32 1 0
+github.com\Chronokeeper\activego\sessionplus.go:338.4,339.32 1 0
+github.com\Chronokeeper\activego\sessionplus.go:347.4,348.47 1 0
+github.com\Chronokeeper\activego\sessionplus.go:433.4,436.22 1 0
+github.com\Chronokeeper\activego\sessionplus.go:295.46,299.20 4 0
+github.com\Chronokeeper\activego\sessionplus.go:303.6,303.30 1 0
+github.com\Chronokeeper\activego\sessionplus.go:299.20,302.7 2 0
+github.com\Chronokeeper\activego\sessionplus.go:307.5,308.40 1 0
+github.com\Chronokeeper\activego\sessionplus.go:309.6,310.51 1 0
+github.com\Chronokeeper\activego\sessionplus.go:310.51,313.8 2 0
+github.com\Chronokeeper\activego\sessionplus.go:317.46,320.6 2 0
+github.com\Chronokeeper\activego\sessionplus.go:322.44,325.6 2 0
+github.com\Chronokeeper\activego\sessionplus.go:328.5,330.33 2 0
+github.com\Chronokeeper\activego\sessionplus.go:334.5,336.37 2 0
+github.com\Chronokeeper\activego\sessionplus.go:340.5,342.35 2 0
+github.com\Chronokeeper\activego\sessionplus.go:343.5,345.42 2 0
+github.com\Chronokeeper\activego\sessionplus.go:348.47,349.39 1 0
+github.com\Chronokeeper\activego\sessionplus.go:349.39,354.39 4 0
+github.com\Chronokeeper\activego\sessionplus.go:360.7,365.60 4 0
+github.com\Chronokeeper\activego\sessionplus.go:354.39,358.8 2 0
+github.com\Chronokeeper\activego\sessionplus.go:370.7,371.38 1 0
+github.com\Chronokeeper\activego\sessionplus.go:371.38,376.7 4 0
+github.com\Chronokeeper\activego\sessionplus.go:377.6,377.44 1 0
+github.com\Chronokeeper\activego\sessionplus.go:377.44,379.22 2 0
+github.com\Chronokeeper\activego\sessionplus.go:379.22,380.37 1 0
+github.com\Chronokeeper\activego\sessionplus.go:383.7,384.34 2 0
+github.com\Chronokeeper\activego\sessionplus.go:411.7,411.24 1 0
+github.com\Chronokeeper\activego\sessionplus.go:380.37,382.8 1 0
+github.com\Chronokeeper\activego\sessionplus.go:385.7,386.24 1 0
+github.com\Chronokeeper\activego\sessionplus.go:387.7,388.29 1 0
+github.com\Chronokeeper\activego\sessionplus.go:389.7,390.31 1 0
+github.com\Chronokeeper\activego\sessionplus.go:391.7,392.31 1 0
+github.com\Chronokeeper\activego\sessionplus.go:393.7,394.30 1 0
+github.com\Chronokeeper\activego\sessionplus.go:395.7,396.25 1 0
+github.com\Chronokeeper\activego\sessionplus.go:397.7,398.31 1 0
+github.com\Chronokeeper\activego\sessionplus.go:399.7,400.33 1 0
+github.com\Chronokeeper\activego\sessionplus.go:401.7,402.33 1 0
+github.com\Chronokeeper\activego\sessionplus.go:403.7,404.32 1 0
+github.com\Chronokeeper\activego\sessionplus.go:405.7,406.27 1 0
+github.com\Chronokeeper\activego\sessionplus.go:407.7,408.53 1 0
+github.com\Chronokeeper\activego\sessionplus.go:411.24,419.22 5 0
+github.com\Chronokeeper\activego\sessionplus.go:422.8,422.15 1 0
+github.com\Chronokeeper\activego\sessionplus.go:419.22,421.9 1 0
+github.com\Chronokeeper\activego\sessionplus.go:422.15,425.9 2 0
+github.com\Chronokeeper\activego\sessionplus.go:425.9,427.9 1 0
+github.com\Chronokeeper\activego\sessionplus.go:429.7,431.7 1 0
+github.com\Chronokeeper\activego\sessionplus.go:438.5,439.47 1 0
+github.com\Chronokeeper\activego\sessionplus.go:444.5,445.45 1 0
+github.com\Chronokeeper\activego\sessionplus.go:450.5,451.42 1 0
+github.com\Chronokeeper\activego\sessionplus.go:456.5,457.48 1 0
+github.com\Chronokeeper\activego\sessionplus.go:462.5,463.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:468.5,469.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:474.5,475.48 1 0
+github.com\Chronokeeper\activego\sessionplus.go:480.5,481.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:486.5,487.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:492.5,493.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:498.5,499.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:504.5,505.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:510.5,511.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:516.5,517.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:522.5,523.46 1 0
+github.com\Chronokeeper\activego\sessionplus.go:528.5,531.20 3 0
+github.com\Chronokeeper\activego\sessionplus.go:536.6,536.24 1 0
+github.com\Chronokeeper\activego\sessionplus.go:537.5,540.20 3 0
+github.com\Chronokeeper\activego\sessionplus.go:545.6,545.24 1 0
+github.com\Chronokeeper\activego\sessionplus.go:439.47,443.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:445.45,449.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:451.42,455.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:457.48,461.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:463.46,467.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:469.46,473.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:475.48,479.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:481.46,485.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:487.46,491.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:493.46,497.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:499.46,503.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:505.46,509.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:511.46,515.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:517.46,521.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:523.46,527.7 3 0
+github.com\Chronokeeper\activego\sessionplus.go:531.20,533.7 1 0
+github.com\Chronokeeper\activego\sessionplus.go:533.7,535.7 1 0
+github.com\Chronokeeper\activego\sessionplus.go:540.20,542.7 1 0
+github.com\Chronokeeper\activego\sessionplus.go:542.7,544.7 1 0
+github.com\Chronokeeper\activego\sessionplus.go:552.20,554.19 2 0
+github.com\Chronokeeper\activego\sessionplus.go:554.19,556.6 1 0
+github.com\Chronokeeper\activego\sessionplus.go:556.6,558.6 1 0
+github.com\Chronokeeper\activego\sessionplus.go:566.84,571.65 5 0
+github.com\Chronokeeper\activego\sessionplus.go:577.2,577.58 1 0
+github.com\Chronokeeper\activego\sessionplus.go:581.2,582.42 2 0
+github.com\Chronokeeper\activego\sessionplus.go:571.65,575.3 3 0
+github.com\Chronokeeper\activego\sessionplus.go:577.58,579.3 1 0
+github.com\Chronokeeper\activego\goracle_driver.go:21.87,32.32 5 0
+github.com\Chronokeeper\activego\goracle_driver.go:38.2,38.21 1 0
+github.com\Chronokeeper\activego\goracle_driver.go:41.2,41.16 1 0
+github.com\Chronokeeper\activego\goracle_driver.go:32.32,33.19 1 0
+github.com\Chronokeeper\activego\goracle_driver.go:34.3,35.21 1 0
+github.com\Chronokeeper\activego\goracle_driver.go:38.21,40.3 1 0
+github.com\Chronokeeper\activego\helpers.go:18.33,19.18 1 0
+github.com\Chronokeeper\activego\helpers.go:43.2,43.14 1 0
+github.com\Chronokeeper\activego\helpers.go:20.2,21.22 1 0
+github.com\Chronokeeper\activego\helpers.go:22.2,23.23 1 0
+github.com\Chronokeeper\activego\helpers.go:24.2,25.24 1 0
+github.com\Chronokeeper\activego\helpers.go:26.2,27.24 1 0
+github.com\Chronokeeper\activego\helpers.go:28.2,29.24 1 0
+github.com\Chronokeeper\activego\helpers.go:30.2,31.23 1 0
+github.com\Chronokeeper\activego\helpers.go:32.2,33.24 1 0
+github.com\Chronokeeper\activego\helpers.go:34.2,35.25 1 0
+github.com\Chronokeeper\activego\helpers.go:36.2,37.25 1 0
+github.com\Chronokeeper\activego\helpers.go:38.2,39.25 1 0
+github.com\Chronokeeper\activego\helpers.go:40.2,41.26 1 0
+github.com\Chronokeeper\activego\helpers.go:46.32,47.23 1 0
+github.com\Chronokeeper\activego\helpers.go:52.2,52.14 1 0
+github.com\Chronokeeper\activego\helpers.go:47.23,48.16 1 0
+github.com\Chronokeeper\activego\helpers.go:48.16,50.4 1 0
+github.com\Chronokeeper\activego\helpers.go:55.37,57.2 1 0
+github.com\Chronokeeper\activego\helpers.go:59.42,61.13 2 0
+github.com\Chronokeeper\activego\helpers.go:64.2,64.46 1 0
+github.com\Chronokeeper\activego\helpers.go:61.13,63.3 1 0
+github.com\Chronokeeper\activego\helpers.go:67.50,69.13 2 0
+github.com\Chronokeeper\activego\helpers.go:72.2,72.50 1 0
+github.com\Chronokeeper\activego\helpers.go:69.13,71.3 1 0
+github.com\Chronokeeper\activego\helpers.go:75.49,77.29 2 0
+github.com\Chronokeeper\activego\helpers.go:80.2,80.12 1 0
+github.com\Chronokeeper\activego\helpers.go:77.29,79.3 1 0
+github.com\Chronokeeper\activego\helpers.go:83.45,85.2 1 1
+github.com\Chronokeeper\activego\helpers.go:87.43,91.2 2 0
+github.com\Chronokeeper\activego\helpers.go:93.40,94.30 1 0
+github.com\Chronokeeper\activego\helpers.go:97.2,97.17 1 0
+github.com\Chronokeeper\activego\helpers.go:94.30,96.3 1 0
+github.com\Chronokeeper\activego\helpers.go:100.41,101.29 1 0
+github.com\Chronokeeper\activego\helpers.go:104.2,106.33 3 0
+github.com\Chronokeeper\activego\helpers.go:111.2,111.13 1 0
+github.com\Chronokeeper\activego\helpers.go:101.29,103.3 1 0
+github.com\Chronokeeper\activego\helpers.go:106.33,107.26 1 0
+github.com\Chronokeeper\activego\helpers.go:107.26,109.4 1 0
+github.com\Chronokeeper\activego\helpers.go:116.77,119.19 3 1
+github.com\Chronokeeper\activego\helpers.go:159.2,159.8 1 1
+github.com\Chronokeeper\activego\helpers.go:120.2,121.19 1 1
+github.com\Chronokeeper\activego\helpers.go:122.2,123.20 1 0
+github.com\Chronokeeper\activego\helpers.go:124.2,125.21 1 0
+github.com\Chronokeeper\activego\helpers.go:126.2,127.22 1 0
+github.com\Chronokeeper\activego\helpers.go:128.2,129.27 1 1
+github.com\Chronokeeper\activego\helpers.go:139.2,140.26 1 1
+github.com\Chronokeeper\activego\helpers.go:145.2,146.20 1 0
+github.com\Chronokeeper\activego\helpers.go:147.2,148.23 1 0
+github.com\Chronokeeper\activego\helpers.go:156.2,157.67 1 0
+github.com\Chronokeeper\activego\helpers.go:130.3,134.24 2 1
+github.com\Chronokeeper\activego\helpers.go:135.3,136.68 1 0
+github.com\Chronokeeper\activego\helpers.go:140.26,142.4 1 1
+github.com\Chronokeeper\activego\helpers.go:142.4,144.4 1 0
+github.com\Chronokeeper\activego\helpers.go:162.69,165.19 3 1
+github.com\Chronokeeper\activego\helpers.go:203.2,203.8 1 1
+github.com\Chronokeeper\activego\helpers.go:166.2,167.40 1 0
+github.com\Chronokeeper\activego\helpers.go:168.2,169.42 1 0
+github.com\Chronokeeper\activego\helpers.go:170.2,171.53 1 0
+github.com\Chronokeeper\activego\helpers.go:172.2,173.20 1 0
+github.com\Chronokeeper\activego\helpers.go:174.2,175.27 1 1
+github.com\Chronokeeper\activego\helpers.go:183.2,184.26 1 0
+github.com\Chronokeeper\activego\helpers.go:189.2,190.38 1 0
+github.com\Chronokeeper\activego\helpers.go:191.2,192.40 1 0
+github.com\Chronokeeper\activego\helpers.go:200.2,201.67 1 0
+github.com\Chronokeeper\activego\helpers.go:176.3,178.22 2 1
+github.com\Chronokeeper\activego\helpers.go:179.3,180.68 1 0
+github.com\Chronokeeper\activego\helpers.go:184.26,186.4 1 0
+github.com\Chronokeeper\activego\helpers.go:186.4,188.4 1 0
+github.com\Chronokeeper\activego\helpers.go:206.74,208.16 2 1
+github.com\Chronokeeper\activego\helpers.go:211.2,211.8 1 1
+github.com\Chronokeeper\activego\helpers.go:208.16,210.3 1 0
+github.com\Chronokeeper\activego\helpers.go:214.68,217.16 3 1
+github.com\Chronokeeper\activego\helpers.go:220.2,221.8 2 1
+github.com\Chronokeeper\activego\helpers.go:217.16,219.3 1 0
+github.com\Chronokeeper\activego\helpers.go:224.69,226.16 2 0
+github.com\Chronokeeper\activego\helpers.go:229.2,229.8 1 0
+github.com\Chronokeeper\activego\helpers.go:226.16,228.3 1 0
+github.com\Chronokeeper\activego\helpers.go:232.82,234.16 2 0
+github.com\Chronokeeper\activego\helpers.go:237.2,237.18 1 0
+github.com\Chronokeeper\activego\helpers.go:245.2,245.26 1 0
+github.com\Chronokeeper\activego\helpers.go:234.16,236.3 1 0
+github.com\Chronokeeper\activego\helpers.go:237.18,239.17 2 0
+github.com\Chronokeeper\activego\helpers.go:242.3,242.46 1 0
+github.com\Chronokeeper\activego\helpers.go:239.17,241.4 1 0
+github.com\Chronokeeper\activego\helpers.go:248.79,250.16 2 0
+github.com\Chronokeeper\activego\helpers.go:253.2,253.18 1 0
+github.com\Chronokeeper\activego\helpers.go:261.2,261.26 1 0
+github.com\Chronokeeper\activego\helpers.go:250.16,252.3 1 0
+github.com\Chronokeeper\activego\helpers.go:253.18,255.17 2 0
+github.com\Chronokeeper\activego\helpers.go:258.3,258.46 1 0
+github.com\Chronokeeper\activego\helpers.go:255.17,257.4 1 0
+github.com\Chronokeeper\activego\helpers.go:264.90,266.16 2 1
+github.com\Chronokeeper\activego\helpers.go:269.2,269.18 1 1
+github.com\Chronokeeper\activego\helpers.go:277.2,277.26 1 1
+github.com\Chronokeeper\activego\helpers.go:266.16,268.3 1 0
+github.com\Chronokeeper\activego\helpers.go:269.18,271.17 2 1
+github.com\Chronokeeper\activego\helpers.go:274.3,274.46 1 1
+github.com\Chronokeeper\activego\helpers.go:271.17,273.4 1 0
+github.com\Chronokeeper\activego\helpers.go:280.102,283.35 3 1
+github.com\Chronokeeper\activego\helpers.go:287.2,287.59 1 1
+github.com\Chronokeeper\activego\helpers.go:291.2,291.30 1 1
+github.com\Chronokeeper\activego\helpers.go:307.2,307.20 1 1
+github.com\Chronokeeper\activego\helpers.go:283.35,286.3 2 1
+github.com\Chronokeeper\activego\helpers.go:287.59,289.3 1 0
+github.com\Chronokeeper\activego\helpers.go:291.30,294.34 2 1
+github.com\Chronokeeper\activego\helpers.go:299.3,299.55 1 1
+github.com\Chronokeeper\activego\helpers.go:294.34,296.12 1 0
+github.com\Chronokeeper\activego\helpers.go:299.55,302.4 1 1
+github.com\Chronokeeper\activego\helpers.go:302.4,304.4 1 0
+github.com\Chronokeeper\activego\helpers.go:310.90,313.35 3 0
+github.com\Chronokeeper\activego\helpers.go:317.2,317.59 1 0
+github.com\Chronokeeper\activego\helpers.go:321.2,321.30 1 0
+github.com\Chronokeeper\activego\helpers.go:335.2,335.20 1 0
+github.com\Chronokeeper\activego\helpers.go:313.35,316.3 2 0
+github.com\Chronokeeper\activego\helpers.go:317.59,319.3 1 0
+github.com\Chronokeeper\activego\helpers.go:321.30,324.34 2 0
+github.com\Chronokeeper\activego\helpers.go:329.3,329.54 1 0
+github.com\Chronokeeper\activego\helpers.go:324.34,326.12 1 0
+github.com\Chronokeeper\activego\helpers.go:329.54,331.4 1 0
+github.com\Chronokeeper\activego\helpers.go:331.4,333.4 1 0
+github.com\Chronokeeper\activego\helpers.go:338.93,341.35 3 0
+github.com\Chronokeeper\activego\helpers.go:345.2,345.59 1 0
+github.com\Chronokeeper\activego\helpers.go:349.2,349.30 1 0
+github.com\Chronokeeper\activego\helpers.go:363.2,363.20 1 0
+github.com\Chronokeeper\activego\helpers.go:341.35,344.3 2 0
+github.com\Chronokeeper\activego\helpers.go:345.59,347.3 1 0
+github.com\Chronokeeper\activego\helpers.go:349.30,352.34 2 0
+github.com\Chronokeeper\activego\helpers.go:357.3,357.55 1 0
+github.com\Chronokeeper\activego\helpers.go:352.34,354.12 1 0
+github.com\Chronokeeper\activego\helpers.go:357.55,359.4 1 0
+github.com\Chronokeeper\activego\helpers.go:359.4,361.4 1 0
+github.com\Chronokeeper\activego\helpers.go:366.112,368.16 2 0
+github.com\Chronokeeper\activego\helpers.go:371.2,373.27 2 0
+github.com\Chronokeeper\activego\helpers.go:368.16,370.3 1 0
+github.com\Chronokeeper\activego\helpers.go:376.117,378.16 2 0
+github.com\Chronokeeper\activego\helpers.go:381.2,383.30 2 0
+github.com\Chronokeeper\activego\helpers.go:378.16,380.3 1 0
+github.com\Chronokeeper\activego\helpers.go:386.110,388.16 2 0
+github.com\Chronokeeper\activego\helpers.go:391.2,393.16 3 0
+github.com\Chronokeeper\activego\helpers.go:396.2,397.27 2 0
+github.com\Chronokeeper\activego\helpers.go:388.16,390.3 1 0
+github.com\Chronokeeper\activego\helpers.go:393.16,395.3 1 0
+github.com\Chronokeeper\activego\helpers.go:400.115,402.16 2 1
+github.com\Chronokeeper\activego\helpers.go:405.2,407.16 3 1
+github.com\Chronokeeper\activego\helpers.go:410.2,411.30 2 1
+github.com\Chronokeeper\activego\helpers.go:402.16,404.3 1 0
+github.com\Chronokeeper\activego\helpers.go:407.16,409.3 1 0
+github.com\Chronokeeper\activego\helpers.go:414.69,416.16 2 0
+github.com\Chronokeeper\activego\helpers.go:419.2,419.16 1 0
+github.com\Chronokeeper\activego\helpers.go:416.16,418.3 1 0
+github.com\Chronokeeper\activego\helpers.go:419.16,420.26 1 0
+github.com\Chronokeeper\activego\helpers.go:421.3,422.47 1 0
+github.com\Chronokeeper\activego\helpers.go:423.3,424.22 1 0
+github.com\Chronokeeper\activego\helpers.go:425.3,426.31 1 0
+github.com\Chronokeeper\activego\helpers.go:431.134,435.38 3 0
+github.com\Chronokeeper\activego\helpers.go:510.2,510.28 1 0
+github.com\Chronokeeper\activego\helpers.go:435.38,437.67 2 0
+github.com\Chronokeeper\activego\helpers.go:442.3,442.37 1 0
+github.com\Chronokeeper\activego\helpers.go:446.3,447.17 2 0
+github.com\Chronokeeper\activego\helpers.go:451.3,453.26 2 0
+github.com\Chronokeeper\activego\helpers.go:470.3,470.20 1 0
+github.com\Chronokeeper\activego\helpers.go:474.3,474.40 1 0
+github.com\Chronokeeper\activego\helpers.go:479.3,479.38 1 0
+github.com\Chronokeeper\activego\helpers.go:485.3,485.72 1 0
+github.com\Chronokeeper\activego\helpers.go:504.3,504.19 1 0
+github.com\Chronokeeper\activego\helpers.go:437.67,438.59 1 0
+github.com\Chronokeeper\activego\helpers.go:438.59,439.13 1 0
+github.com\Chronokeeper\activego\helpers.go:442.37,443.12 1 0
+github.com\Chronokeeper\activego\helpers.go:447.17,449.12 2 0
+github.com\Chronokeeper\activego\helpers.go:453.26,454.36 1 0
+github.com\Chronokeeper\activego\helpers.go:455.4,456.30 1 0
+github.com\Chronokeeper\activego\helpers.go:459.4,460.31 1 0
+github.com\Chronokeeper\activego\helpers.go:463.4,464.38 1 0
+github.com\Chronokeeper\activego\helpers.go:456.30,457.14 1 0
+github.com\Chronokeeper\activego\helpers.go:460.31,461.14 1 0
+github.com\Chronokeeper\activego\helpers.go:464.38,465.14 1 0
+github.com\Chronokeeper\activego\helpers.go:470.20,471.12 1 0
+github.com\Chronokeeper\activego\helpers.go:474.40,475.59 1 0
+github.com\Chronokeeper\activego\helpers.go:475.59,476.13 1 0
+github.com\Chronokeeper\activego\helpers.go:479.38,480.58 1 0
+github.com\Chronokeeper\activego\helpers.go:480.58,481.13 1 0
+github.com\Chronokeeper\activego\helpers.go:485.72,490.81 4 0
+github.com\Chronokeeper\activego\helpers.go:490.81,493.5 2 0
+github.com\Chronokeeper\activego\helpers.go:494.4,494.61 1 0
+github.com\Chronokeeper\activego\helpers.go:494.61,496.4 1 0
+github.com\Chronokeeper\activego\helpers.go:496.4,498.18 2 0
+github.com\Chronokeeper\activego\helpers.go:501.4,501.28 1 0
+github.com\Chronokeeper\activego\helpers.go:498.18,500.5 1 0
+github.com\Chronokeeper\activego\helpers.go:504.19,506.4 1 0
+github.com\Chronokeeper\activego\helpers.go:506.4,508.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:153.93,155.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:157.51,158.32 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:159.2,160.23 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:161.2,162.19 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:163.2,165.19 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:166.2,167.22 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:168.2,169.19 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:170.2,171.22 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:172.2,173.19 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:174.2,178.22 4 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:179.2,180.11 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:184.50,186.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:188.45,190.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:192.49,195.2 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:197.46,199.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:201.38,203.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:205.41,207.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:209.41,211.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:213.42,215.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:217.40,219.2 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:221.85,224.2 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:226.76,229.2 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:231.77,236.39 3 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:243.2,243.53 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:236.39,237.36 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:237.36,239.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:239.4,241.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:252.84,256.22 4 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:259.2,259.16 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:262.2,264.17 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:267.2,267.19 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:256.22,258.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:259.16,261.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:264.17,266.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:270.92,275.22 4 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:278.2,278.16 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:281.2,284.18 3 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:292.2,292.16 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:296.2,301.36 6 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:336.2,336.26 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:275.22,277.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:278.16,280.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:284.18,286.17 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:289.3,289.8 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:286.17,288.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:292.16,294.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:301.36,307.34 6 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:330.3,330.54 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:333.3,334.36 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:307.34,308.16 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:314.4,314.17 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:308.16,310.13 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:311.5,311.23 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:311.23,313.5 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:315.4,316.28 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:317.4,318.31 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:319.4,320.31 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:325.4,327.31 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:320.31,322.6 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:322.6,324.6 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:330.54,332.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:339.55,344.22 4 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:347.2,347.16 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:350.2,353.18 3 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:364.2,364.20 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:344.22,346.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:347.16,349.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:353.18,356.17 3 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:359.3,359.38 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:362.3,362.33 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:356.17,358.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:359.38,360.12 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:367.81,372.22 4 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:375.2,375.16 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:378.2,381.18 3 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:424.2,424.21 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:372.22,374.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:375.16,377.3 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:381.18,384.17 3 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:388.3,388.20 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:391.3,396.35 5 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:400.3,401.103 2 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:407.3,407.52 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:413.3,418.34 5 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:421.3,421.30 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:384.17,386.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:388.20,389.12 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:396.35,397.12 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:401.103,403.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:403.4,405.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:407.52,409.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:409.4,411.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:418.34,420.4 1 0
+github.com\Chronokeeper\activego\sqlite3_dialect.go:427.44,429.2 1 0
+github.com\Chronokeeper\activego\statement.go:79.36,112.2 32 1
+github.com\Chronokeeper\activego\statement.go:115.85,119.2 3 0
+github.com\Chronokeeper\activego\statement.go:122.60,125.2 2 0
+github.com\Chronokeeper\activego\statement.go:128.87,129.70 1 0
+github.com\Chronokeeper\activego\statement.go:132.2,134.18 3 0
+github.com\Chronokeeper\activego\statement.go:129.70,131.3 1 0
+github.com\Chronokeeper\activego\statement.go:138.85,139.30 1 1
+github.com\Chronokeeper\activego\statement.go:145.2,146.18 2 1
+github.com\Chronokeeper\activego\statement.go:139.30,142.3 1 0
+github.com\Chronokeeper\activego\statement.go:142.3,144.3 1 1
+github.com\Chronokeeper\activego\statement.go:150.84,151.30 1 0
+github.com\Chronokeeper\activego\statement.go:157.2,158.18 2 0
+github.com\Chronokeeper\activego\statement.go:151.30,154.3 1 0
+github.com\Chronokeeper\activego\statement.go:154.3,156.3 1 0
+github.com\Chronokeeper\activego\statement.go:162.75,165.32 3 0
+github.com\Chronokeeper\activego\statement.go:170.2,170.18 1 0
+github.com\Chronokeeper\activego\statement.go:165.32,167.3 1 0
+github.com\Chronokeeper\activego\statement.go:167.3,167.39 1 0
+github.com\Chronokeeper\activego\statement.go:167.39,169.3 1 0
+github.com\Chronokeeper\activego\statement.go:293.99,297.38 3 0
+github.com\Chronokeeper\activego\statement.go:492.2,492.23 1 0
+github.com\Chronokeeper\activego\statement.go:297.38,298.39 1 0
+github.com\Chronokeeper\activego\statement.go:301.3,301.20 1 0
+github.com\Chronokeeper\activego\statement.go:304.3,304.39 1 0
+github.com\Chronokeeper\activego\statement.go:307.3,307.46 1 0
+github.com\Chronokeeper\activego\statement.go:310.3,310.20 1 0
+github.com\Chronokeeper\activego\statement.go:313.3,313.49 1 0
+github.com\Chronokeeper\activego\statement.go:317.3,317.77 1 0
+github.com\Chronokeeper\activego\statement.go:321.3,322.17 2 0
+github.com\Chronokeeper\activego\statement.go:327.3,332.60 5 0
+github.com\Chronokeeper\activego\statement.go:340.3,342.27 2 0
+github.com\Chronokeeper\activego\statement.go:354.3,354.72 1 0
+github.com\Chronokeeper\activego\statement.go:364.3,364.38 1 0
+github.com\Chronokeeper\activego\statement.go:381.3,381.27 1 0
+github.com\Chronokeeper\activego\statement.go:483.2,486.58 2 0
+github.com\Chronokeeper\activego\statement.go:489.3,489.77 1 0
+github.com\Chronokeeper\activego\statement.go:298.39,299.12 1 0
+github.com\Chronokeeper\activego\statement.go:301.20,302.12 1 0
+github.com\Chronokeeper\activego\statement.go:304.39,305.12 1 0
+github.com\Chronokeeper\activego\statement.go:307.46,308.12 1 0
+github.com\Chronokeeper\activego\statement.go:310.20,311.12 1 0
+github.com\Chronokeeper\activego\statement.go:313.49,314.12 1 0
+github.com\Chronokeeper\activego\statement.go:317.77,318.12 1 0
+github.com\Chronokeeper\activego\statement.go:322.17,324.12 2 0
+github.com\Chronokeeper\activego\statement.go:332.60,333.9 1 0
+github.com\Chronokeeper\activego\statement.go:333.9,335.5 1 0
+github.com\Chronokeeper\activego\statement.go:335.5,336.13 1 0
+github.com\Chronokeeper\activego\statement.go:342.27,343.80 1 0
+github.com\Chronokeeper\activego\statement.go:343.80,345.19 2 0
+github.com\Chronokeeper\activego\statement.go:350.5,350.16 1 0
+github.com\Chronokeeper\activego\statement.go:345.19,347.6 1 0
+github.com\Chronokeeper\activego\statement.go:347.6,349.6 1 0
+github.com\Chronokeeper\activego\statement.go:354.72,356.18 2 0
+github.com\Chronokeeper\activego\statement.go:361.4,361.15 1 0
+github.com\Chronokeeper\activego\statement.go:356.18,358.5 1 0
+github.com\Chronokeeper\activego\statement.go:358.5,360.5 1 0
+github.com\Chronokeeper\activego\statement.go:364.38,365.26 1 0
+github.com\Chronokeeper\activego\statement.go:365.26,366.19 1 0
+github.com\Chronokeeper\activego\statement.go:370.5,370.13 1 0
+github.com\Chronokeeper\activego\statement.go:366.19,369.6 2 0
+github.com\Chronokeeper\activego\statement.go:371.5,371.36 1 0
+github.com\Chronokeeper\activego\statement.go:371.36,372.13 1 0
+github.com\Chronokeeper\activego\statement.go:373.5,378.5 3 0
+github.com\Chronokeeper\activego\statement.go:382.3,383.35 1 0
+github.com\Chronokeeper\activego\statement.go:390.3,391.51 1 0
+github.com\Chronokeeper\activego\statement.go:395.4,395.53 1 0
+github.com\Chronokeeper\activego\statement.go:400.3,401.47 1 0
+github.com\Chronokeeper\activego\statement.go:404.4,404.32 1 0
+github.com\Chronokeeper\activego\statement.go:405.3,406.51 1 0
+github.com\Chronokeeper\activego\statement.go:409.4,409.32 1 0
+github.com\Chronokeeper\activego\statement.go:410.3,411.48 1 0
+github.com\Chronokeeper\activego\statement.go:414.4,415.41 2 0
+github.com\Chronokeeper\activego\statement.go:416.3,417.47 1 0
+github.com\Chronokeeper\activego\statement.go:443.3,444.45 1 0
+github.com\Chronokeeper\activego\statement.go:447.4,447.76 1 0
+github.com\Chronokeeper\activego\statement.go:451.4,451.28 1 0
+github.com\Chronokeeper\activego\statement.go:479.3,480.32 1 0
+github.com\Chronokeeper\activego\statement.go:383.35,385.5 1 0
+github.com\Chronokeeper\activego\statement.go:385.5,388.13 1 0
+github.com\Chronokeeper\activego\statement.go:391.51,392.13 1 0
+github.com\Chronokeeper\activego\statement.go:395.53,397.5 1 0
+github.com\Chronokeeper\activego\statement.go:397.5,399.5 1 0
+github.com\Chronokeeper\activego\statement.go:401.47,402.13 1 0
+github.com\Chronokeeper\activego\statement.go:406.51,407.13 1 0
+github.com\Chronokeeper\activego\statement.go:411.48,412.13 1 0
+github.com\Chronokeeper\activego\statement.go:417.47,419.64 2 0
+github.com\Chronokeeper\activego\statement.go:422.5,422.49 1 0
+github.com\Chronokeeper\activego\statement.go:419.64,420.14 1 0
+github.com\Chronokeeper\activego\statement.go:423.5,425.58 2 0
+github.com\Chronokeeper\activego\statement.go:425.58,426.37 1 0
+github.com\Chronokeeper\activego\statement.go:426.37,430.60 2 0
+github.com\Chronokeeper\activego\statement.go:430.60,432.8 1 0
+github.com\Chronokeeper\activego\statement.go:432.8,433.16 1 0
+github.com\Chronokeeper\activego\statement.go:435.7,438.7 1 0
+github.com\Chronokeeper\activego\statement.go:439.6,441.6 1 0
+github.com\Chronokeeper\activego\statement.go:444.45,445.13 1 0
+github.com\Chronokeeper\activego\statement.go:447.76,448.13 1 0
+github.com\Chronokeeper\activego\statement.go:451.28,453.19 2 0
+github.com\Chronokeeper\activego\statement.go:457.5,457.24 1 0
+github.com\Chronokeeper\activego\statement.go:453.19,455.14 2 0
+github.com\Chronokeeper\activego\statement.go:458.5,458.35 1 0
+github.com\Chronokeeper\activego\statement.go:458.35,462.47 3 0
+github.com\Chronokeeper\activego\statement.go:462.47,463.30 1 0
+github.com\Chronokeeper\activego\statement.go:463.30,465.7 1 0
+github.com\Chronokeeper\activego\statement.go:465.7,466.15 1 0
+github.com\Chronokeeper\activego\statement.go:468.6,470.20 2 0
+github.com\Chronokeeper\activego\statement.go:474.6,474.17 1 0
+github.com\Chronokeeper\activego\statement.go:470.20,472.15 2 0
+github.com\Chronokeeper\activego\statement.go:476.5,477.13 1 0
+github.com\Chronokeeper\activego\statement.go:486.58,487.12 1 0
+github.com\Chronokeeper\activego\statement.go:499.59,503.38 3 1
+github.com\Chronokeeper\activego\statement.go:674.2,674.23 1 1
+github.com\Chronokeeper\activego\statement.go:503.38,504.39 1 1
+github.com\Chronokeeper\activego\statement.go:507.3,507.39 1 1
+github.com\Chronokeeper\activego\statement.go:510.3,510.46 1 1
+github.com\Chronokeeper\activego\statement.go:514.3,514.77 1 1
+github.com\Chronokeeper\activego\statement.go:517.3,518.17 2 1
+github.com\Chronokeeper\activego\statement.go:523.3,523.33 1 1
+github.com\Chronokeeper\activego\statement.go:527.3,528.36 2 1
+github.com\Chronokeeper\activego\statement.go:532.3,534.60 3 1
+github.com\Chronokeeper\activego\statement.go:542.3,542.38 1 1
+github.com\Chronokeeper\activego\statement.go:559.3,560.27 2 1
+github.com\Chronokeeper\activego\statement.go:664.3,666.58 3 0
+github.com\Chronokeeper\activego\statement.go:671.3,671.37 1 0
+github.com\Chronokeeper\activego\statement.go:504.39,505.12 1 0
+github.com\Chronokeeper\activego\statement.go:507.39,508.12 1 0
+github.com\Chronokeeper\activego\statement.go:510.46,511.12 1 0
+github.com\Chronokeeper\activego\statement.go:514.77,515.12 1 0
+github.com\Chronokeeper\activego\statement.go:518.17,520.12 2 0
+github.com\Chronokeeper\activego\statement.go:523.33,525.4 1 0
+github.com\Chronokeeper\activego\statement.go:528.36,529.12 1 0
+github.com\Chronokeeper\activego\statement.go:534.60,535.9 1 0
+github.com\Chronokeeper\activego\statement.go:535.9,537.5 1 0
+github.com\Chronokeeper\activego\statement.go:537.5,538.13 1 0
+github.com\Chronokeeper\activego\statement.go:542.38,543.26 1 0
+github.com\Chronokeeper\activego\statement.go:543.26,544.19 1 0
+github.com\Chronokeeper\activego\statement.go:548.5,548.13 1 0
+github.com\Chronokeeper\activego\statement.go:544.19,547.6 2 0
+github.com\Chronokeeper\activego\statement.go:549.5,549.36 1 0
+github.com\Chronokeeper\activego\statement.go:549.36,550.13 1 0
+github.com\Chronokeeper\activego\statement.go:551.5,556.5 3 0
+github.com\Chronokeeper\activego\statement.go:561.3,562.35 1 0
+github.com\Chronokeeper\activego\statement.go:569.3,570.51 1 1
+github.com\Chronokeeper\activego\statement.go:574.4,574.53 1 0
+github.com\Chronokeeper\activego\statement.go:579.3,580.47 1 1
+github.com\Chronokeeper\activego\statement.go:583.4,583.32 1 0
+github.com\Chronokeeper\activego\statement.go:584.3,585.51 1 0
+github.com\Chronokeeper\activego\statement.go:588.4,588.32 1 0
+github.com\Chronokeeper\activego\statement.go:589.3,590.48 1 0
+github.com\Chronokeeper\activego\statement.go:593.4,594.41 2 0
+github.com\Chronokeeper\activego\statement.go:595.3,596.46 1 1
+github.com\Chronokeeper\activego\statement.go:624.3,625.45 1 0
+github.com\Chronokeeper\activego\statement.go:628.4,628.76 1 0
+github.com\Chronokeeper\activego\statement.go:632.4,632.28 1 0
+github.com\Chronokeeper\activego\statement.go:660.3,661.32 1 0
+github.com\Chronokeeper\activego\statement.go:562.35,564.5 1 0
+github.com\Chronokeeper\activego\statement.go:564.5,567.13 1 0
+github.com\Chronokeeper\activego\statement.go:570.51,571.13 1 1
+github.com\Chronokeeper\activego\statement.go:574.53,576.5 1 0
+github.com\Chronokeeper\activego\statement.go:576.5,578.5 1 0
+github.com\Chronokeeper\activego\statement.go:580.47,581.13 1 1
+github.com\Chronokeeper\activego\statement.go:585.51,586.13 1 0
+github.com\Chronokeeper\activego\statement.go:590.48,591.13 1 0
+github.com\Chronokeeper\activego\statement.go:596.46,598.64 2 1
+github.com\Chronokeeper\activego\statement.go:601.5,601.49 1 0
+github.com\Chronokeeper\activego\statement.go:598.64,599.14 1 1
+github.com\Chronokeeper\activego\statement.go:602.5,602.80 1 0
+github.com\Chronokeeper\activego\statement.go:602.80,603.13 1 0
+github.com\Chronokeeper\activego\statement.go:604.5,606.58 2 0
+github.com\Chronokeeper\activego\statement.go:606.58,607.37 1 0
+github.com\Chronokeeper\activego\statement.go:607.37,611.60 2 0
+github.com\Chronokeeper\activego\statement.go:611.60,613.8 1 0
+github.com\Chronokeeper\activego\statement.go:613.8,614.16 1 0
+github.com\Chronokeeper\activego\statement.go:616.7,619.7 1 0
+github.com\Chronokeeper\activego\statement.go:620.6,622.6 1 0
+github.com\Chronokeeper\activego\statement.go:625.45,626.13 1 0
+github.com\Chronokeeper\activego\statement.go:628.76,629.13 1 0
+github.com\Chronokeeper\activego\statement.go:632.28,634.19 2 0
+github.com\Chronokeeper\activego\statement.go:638.5,638.24 1 0
+github.com\Chronokeeper\activego\statement.go:634.19,636.14 2 0
+github.com\Chronokeeper\activego\statement.go:639.5,639.35 1 0
+github.com\Chronokeeper\activego\statement.go:639.35,643.47 3 0
+github.com\Chronokeeper\activego\statement.go:643.47,644.30 1 0
+github.com\Chronokeeper\activego\statement.go:644.30,646.7 1 0
+github.com\Chronokeeper\activego\statement.go:646.7,647.15 1 0
+github.com\Chronokeeper\activego\statement.go:649.6,651.20 2 0
+github.com\Chronokeeper\activego\statement.go:655.6,655.17 1 0
+github.com\Chronokeeper\activego\statement.go:651.20,653.15 2 0
+github.com\Chronokeeper\activego\statement.go:657.5,658.13 1 0
+github.com\Chronokeeper\activego\statement.go:666.58,668.4 1 0
+github.com\Chronokeeper\activego\statement.go:668.4,670.4 1 0
+github.com\Chronokeeper\activego\statement.go:678.48,679.34 1 1
+github.com\Chronokeeper\activego\statement.go:683.2,683.31 1 1
+github.com\Chronokeeper\activego\statement.go:686.2,686.11 1 0
+github.com\Chronokeeper\activego\statement.go:679.34,681.3 1 0
+github.com\Chronokeeper\activego\statement.go:683.31,685.3 1 1
+github.com\Chronokeeper\activego\statement.go:695.59,699.16 3 1
+github.com\Chronokeeper\activego\statement.go:713.2,713.18 1 1
+github.com\Chronokeeper\activego\statement.go:700.2,701.39 1 0
+github.com\Chronokeeper\activego\statement.go:704.2,705.35 1 0
+github.com\Chronokeeper\activego\statement.go:708.2,710.35 1 1
+github.com\Chronokeeper\activego\statement.go:701.39,703.4 1 0
+github.com\Chronokeeper\activego\statement.go:705.35,707.4 1 0
+github.com\Chronokeeper\activego\statement.go:717.80,719.18 2 0
+github.com\Chronokeeper\activego\statement.go:724.2,724.18 1 0
+github.com\Chronokeeper\activego\statement.go:719.18,721.3 1 0
+github.com\Chronokeeper\activego\statement.go:721.3,723.3 1 0
+github.com\Chronokeeper\activego\statement.go:728.80,730.18 2 0
+github.com\Chronokeeper\activego\statement.go:735.2,735.18 1 0
+github.com\Chronokeeper\activego\statement.go:730.18,732.3 1 0
+github.com\Chronokeeper\activego\statement.go:732.3,734.3 1 0
+github.com\Chronokeeper\activego\statement.go:739.82,743.2 3 0
+github.com\Chronokeeper\activego\statement.go:746.59,748.2 1 0
+github.com\Chronokeeper\activego\statement.go:751.59,753.2 1 0
+github.com\Chronokeeper\activego\statement.go:756.60,758.2 1 0
+github.com\Chronokeeper\activego\statement.go:761.79,765.51 3 0
+github.com\Chronokeeper\activego\statement.go:775.2,775.41 1 0
+github.com\Chronokeeper\activego\statement.go:780.2,780.18 1 0
+github.com\Chronokeeper\activego\statement.go:765.51,768.32 3 0
+github.com\Chronokeeper\activego\statement.go:768.32,770.4 1 0
+github.com\Chronokeeper\activego\statement.go:771.3,773.3 1 0
+github.com\Chronokeeper\activego\statement.go:775.41,777.3 1 0
+github.com\Chronokeeper\activego\statement.go:777.3,779.3 1 0
+github.com\Chronokeeper\activego\statement.go:783.64,784.35 1 1
+github.com\Chronokeeper\activego\statement.go:788.2,790.45 3 0
+github.com\Chronokeeper\activego\statement.go:797.2,797.35 1 0
+github.com\Chronokeeper\activego\statement.go:800.2,800.99 1 0
+github.com\Chronokeeper\activego\statement.go:784.35,786.3 1 1
+github.com\Chronokeeper\activego\statement.go:790.45,795.3 2 0
+github.com\Chronokeeper\activego\statement.go:797.35,799.3 1 0
+github.com\Chronokeeper\activego\statement.go:803.43,805.20 2 1
+github.com\Chronokeeper\activego\statement.go:805.20,806.35 1 0
+github.com\Chronokeeper\activego\statement.go:809.3,810.57 2 0
+github.com\Chronokeeper\activego\statement.go:806.35,808.4 1 0
+github.com\Chronokeeper\activego\statement.go:814.46,816.30 2 0
+github.com\Chronokeeper\activego\statement.go:824.2,824.19 1 0
+github.com\Chronokeeper\activego\statement.go:816.30,820.27 4 0
+github.com\Chronokeeper\activego\statement.go:820.27,822.4 1 0
+github.com\Chronokeeper\activego\statement.go:827.52,831.31 4 0
+github.com\Chronokeeper\activego\statement.go:834.2,834.34 1 0
+github.com\Chronokeeper\activego\statement.go:831.31,833.3 1 0
+github.com\Chronokeeper\activego\statement.go:837.78,839.30 2 0
+github.com\Chronokeeper\activego\statement.go:855.2,855.19 1 0
+github.com\Chronokeeper\activego\statement.go:839.30,843.27 4 0
+github.com\Chronokeeper\activego\statement.go:843.27,845.24 2 0
+github.com\Chronokeeper\activego\statement.go:845.24,847.5 1 0
+github.com\Chronokeeper\activego\statement.go:847.5,847.31 1 0
+github.com\Chronokeeper\activego\statement.go:847.31,850.5 1 0
+github.com\Chronokeeper\activego\statement.go:850.5,852.5 1 0
+github.com\Chronokeeper\activego\statement.go:859.68,863.2 3 0
+github.com\Chronokeeper\activego\statement.go:866.64,868.32 2 0
+github.com\Chronokeeper\activego\statement.go:871.2,872.48 2 0
+github.com\Chronokeeper\activego\statement.go:875.2,875.18 1 0
+github.com\Chronokeeper\activego\statement.go:868.32,870.3 1 0
+github.com\Chronokeeper\activego\statement.go:872.48,874.3 1 0
+github.com\Chronokeeper\activego\statement.go:879.50,882.2 2 0
+github.com\Chronokeeper\activego\statement.go:885.68,887.32 2 0
+github.com\Chronokeeper\activego\statement.go:890.2,890.18 1 0
+github.com\Chronokeeper\activego\statement.go:887.32,889.3 1 0
+github.com\Chronokeeper\activego\statement.go:903.67,904.22 1 0
+github.com\Chronokeeper\activego\statement.go:909.2,909.18 1 0
+github.com\Chronokeeper\activego\statement.go:904.22,906.3 1 0
+github.com\Chronokeeper\activego\statement.go:906.3,908.3 1 0
+github.com\Chronokeeper\activego\statement.go:913.53,915.32 2 0
+github.com\Chronokeeper\activego\statement.go:918.2,918.100 1 0
+github.com\Chronokeeper\activego\statement.go:915.32,917.3 1 0
+github.com\Chronokeeper\activego\statement.go:922.55,925.2 2 0
+github.com\Chronokeeper\activego\statement.go:928.71,930.20 2 1
+github.com\Chronokeeper\activego\statement.go:933.2,933.18 1 1
+github.com\Chronokeeper\activego\statement.go:930.20,932.3 1 0
+github.com\Chronokeeper\activego\statement.go:937.62,938.30 1 0
+github.com\Chronokeeper\activego\statement.go:941.2,942.18 2 0
+github.com\Chronokeeper\activego\statement.go:938.30,940.3 1 0
+github.com\Chronokeeper\activego\statement.go:945.65,946.30 1 0
+github.com\Chronokeeper\activego\statement.go:949.2,952.18 4 0
+github.com\Chronokeeper\activego\statement.go:946.30,948.3 1 0
+github.com\Chronokeeper\activego\statement.go:956.64,957.30 1 0
+github.com\Chronokeeper\activego\statement.go:960.2,963.18 4 0
+github.com\Chronokeeper\activego\statement.go:957.30,959.3 1 0
+github.com\Chronokeeper\activego\statement.go:967.108,969.26 2 0
+github.com\Chronokeeper\activego\statement.go:1004.2,1004.29 1 0
+github.com\Chronokeeper\activego\statement.go:1011.2,1011.18 1 0
+github.com\Chronokeeper\activego\statement.go:970.2,973.12 3 0
+github.com\Chronokeeper\activego\statement.go:980.2,984.12 4 0
+github.com\Chronokeeper\activego\statement.go:995.3,995.12 1 0
+github.com\Chronokeeper\activego\statement.go:1000.2,1002.40 2 0
+github.com\Chronokeeper\activego\statement.go:973.12,976.4 2 0
+github.com\Chronokeeper\activego\statement.go:976.4,976.20 1 0
+github.com\Chronokeeper\activego\statement.go:976.20,979.4 2 0
+github.com\Chronokeeper\activego\statement.go:984.12,988.34 4 0
+github.com\Chronokeeper\activego\statement.go:988.34,990.5 1 0
+github.com\Chronokeeper\activego\statement.go:990.5,990.41 1 0
+github.com\Chronokeeper\activego\statement.go:990.41,993.5 2 0
+github.com\Chronokeeper\activego\statement.go:995.12,997.4 1 0
+github.com\Chronokeeper\activego\statement.go:997.4,997.20 1 0
+github.com\Chronokeeper\activego\statement.go:997.20,999.4 1 0
+github.com\Chronokeeper\activego\statement.go:1004.29,1007.3 1 0
+github.com\Chronokeeper\activego\statement.go:1007.3,1010.3 1 0
+github.com\Chronokeeper\activego\statement.go:1015.61,1018.2 2 0
+github.com\Chronokeeper\activego\statement.go:1021.66,1024.2 2 0
+github.com\Chronokeeper\activego\statement.go:1027.51,1030.2 2 0
+github.com\Chronokeeper\activego\statement.go:1032.51,1035.38 3 1
+github.com\Chronokeeper\activego\statement.go:1067.2,1067.37 1 1
+github.com\Chronokeeper\activego\statement.go:1035.38,1036.30 1 1
+github.com\Chronokeeper\activego\statement.go:1041.3,1041.35 1 1
+github.com\Chronokeeper\activego\statement.go:1045.3,1045.30 1 1
+github.com\Chronokeeper\activego\statement.go:1036.30,1037.67 1 0
+github.com\Chronokeeper\activego\statement.go:1037.67,1038.13 1 0
+github.com\Chronokeeper\activego\statement.go:1041.35,1042.12 1 0
+github.com\Chronokeeper\activego\statement.go:1045.30,1047.34 2 0
+github.com\Chronokeeper\activego\statement.go:1052.4,1053.71 2 0
+github.com\Chronokeeper\activego\statement.go:1047.34,1049.5 1 0
+github.com\Chronokeeper\activego\statement.go:1049.5,1051.5 1 0
+github.com\Chronokeeper\activego\statement.go:1053.71,1055.5 1 0
+github.com\Chronokeeper\activego\statement.go:1055.5,1057.5 1 0
+github.com\Chronokeeper\activego\statement.go:1058.4,1060.71 2 1
+github.com\Chronokeeper\activego\statement.go:1060.71,1062.5 1 0
+github.com\Chronokeeper\activego\statement.go:1062.5,1064.5 1 1
+github.com\Chronokeeper\activego\statement.go:1070.56,1073.2 1 0
+github.com\Chronokeeper\activego\statement.go:1075.50,1077.2 1 0
+github.com\Chronokeeper\activego\statement.go:1079.44,1083.49 4 0
+github.com\Chronokeeper\activego\statement.go:1090.2,1090.13 1 0
+github.com\Chronokeeper\activego\statement.go:1083.49,1084.35 1 0
+github.com\Chronokeeper\activego\statement.go:1084.35,1088.4 2 0
+github.com\Chronokeeper\activego\statement.go:1093.51,1095.2 1 0
+github.com\Chronokeeper\activego\statement.go:1097.45,1100.43 3 0
+github.com\Chronokeeper\activego\statement.go:1106.2,1106.13 1 0
+github.com\Chronokeeper\activego\statement.go:1100.43,1101.36 1 0
+github.com\Chronokeeper\activego\statement.go:1101.36,1104.4 2 0
+github.com\Chronokeeper\activego\statement.go:1109.47,1111.49 2 0
+github.com\Chronokeeper\activego\statement.go:1124.2,1124.13 1 0
+github.com\Chronokeeper\activego\statement.go:1111.49,1113.36 2 0
+github.com\Chronokeeper\activego\statement.go:1118.3,1119.38 2 0
+github.com\Chronokeeper\activego\statement.go:1122.3,1122.27 1 0
+github.com\Chronokeeper\activego\statement.go:1113.36,1115.4 1 0
+github.com\Chronokeeper\activego\statement.go:1115.4,1115.42 1 0
+github.com\Chronokeeper\activego\statement.go:1115.42,1117.4 1 0
+github.com\Chronokeeper\activego\statement.go:1119.38,1121.4 1 0
+github.com\Chronokeeper\activego\statement.go:1132.81,1134.31 2 1
+github.com\Chronokeeper\activego\statement.go:1141.2,1149.33 5 1
+github.com\Chronokeeper\activego\statement.go:1167.2,1168.91 2 1
+github.com\Chronokeeper\activego\statement.go:1134.31,1137.3 2 0
+github.com\Chronokeeper\activego\statement.go:1137.3,1139.3 1 1
+github.com\Chronokeeper\activego\statement.go:1149.33,1150.26 1 1
+github.com\Chronokeeper\activego\statement.go:1150.26,1151.34 1 1
+github.com\Chronokeeper\activego\statement.go:1151.34,1153.5 1 0
+github.com\Chronokeeper\activego\statement.go:1153.5,1155.5 1 1
+github.com\Chronokeeper\activego\statement.go:1157.3,1158.26 1 0
+github.com\Chronokeeper\activego\statement.go:1158.26,1159.34 1 0
+github.com\Chronokeeper\activego\statement.go:1159.34,1161.5 1 0
+github.com\Chronokeeper\activego\statement.go:1161.5,1163.5 1 0
+github.com\Chronokeeper\activego\statement.go:1171.79,1176.2 3 0
+github.com\Chronokeeper\activego\statement.go:1192.83,1205.49 7 0
+github.com\Chronokeeper\activego\statement.go:1208.2,1209.110 2 0
+github.com\Chronokeeper\activego\statement.go:1205.49,1207.3 1 0
+github.com\Chronokeeper\activego\statement.go:1212.71,1220.26 2 1
+github.com\Chronokeeper\activego\statement.go:1224.2,1232.30 5 1
+github.com\Chronokeeper\activego\statement.go:1241.2,1242.32 2 1
+github.com\Chronokeeper\activego\statement.go:1249.2,1249.29 1 1
+github.com\Chronokeeper\activego\statement.go:1253.2,1253.53 1 1
+github.com\Chronokeeper\activego\statement.go:1284.2,1286.22 2 1
+github.com\Chronokeeper\activego\statement.go:1294.2,1294.32 1 1
+github.com\Chronokeeper\activego\statement.go:1297.2,1297.31 1 1
+github.com\Chronokeeper\activego\statement.go:1300.2,1300.30 1 1
+github.com\Chronokeeper\activego\statement.go:1303.2,1303.105 1 1
+github.com\Chronokeeper\activego\statement.go:1315.2,1315.8 1 1
+github.com\Chronokeeper\activego\statement.go:1220.26,1222.3 1 0
+github.com\Chronokeeper\activego\statement.go:1232.30,1234.35 2 1
+github.com\Chronokeeper\activego\statement.go:1234.35,1237.4 1 0
+github.com\Chronokeeper\activego\statement.go:1238.3,1238.41 1 0
+github.com\Chronokeeper\activego\statement.go:1238.41,1240.3 1 0
+github.com\Chronokeeper\activego\statement.go:1242.32,1243.55 1 0
+github.com\Chronokeeper\activego\statement.go:1243.55,1245.4 1 0
+github.com\Chronokeeper\activego\statement.go:1245.4,1247.4 1 0
+github.com\Chronokeeper\activego\statement.go:1249.29,1251.3 1 0
+github.com\Chronokeeper\activego\statement.go:1253.53,1254.27 1 0
+github.com\Chronokeeper\activego\statement.go:1257.3,1257.26 1 0
+github.com\Chronokeeper\activego\statement.go:1254.27,1256.4 1 0
+github.com\Chronokeeper\activego\statement.go:1257.26,1259.48 2 0
+github.com\Chronokeeper\activego\statement.go:1270.4,1271.35 2 0
+github.com\Chronokeeper\activego\statement.go:1274.4,1275.37 2 0
+github.com\Chronokeeper\activego\statement.go:1278.4,1279.76 1 0
+github.com\Chronokeeper\activego\statement.go:1259.48,1260.54 1 0
+github.com\Chronokeeper\activego\statement.go:1266.5,1266.25 1 0
+github.com\Chronokeeper\activego\statement.go:1260.54,1261.30 1 0
+github.com\Chronokeeper\activego\statement.go:1261.30,1263.12 2 0
+github.com\Chronokeeper\activego\statement.go:1266.25,1268.6 1 0
+github.com\Chronokeeper\activego\statement.go:1271.35,1273.5 1 0
+github.com\Chronokeeper\activego\statement.go:1275.37,1277.5 1 0
+github.com\Chronokeeper\activego\statement.go:1286.22,1287.21 1 0
+github.com\Chronokeeper\activego\statement.go:1287.21,1289.4 1 0
+github.com\Chronokeeper\activego\statement.go:1289.4,1291.4 1 0
+github.com\Chronokeeper\activego\statement.go:1294.32,1296.3 1 0
+github.com\Chronokeeper\activego\statement.go:1297.31,1299.3 1 0
+github.com\Chronokeeper\activego\statement.go:1300.30,1302.3 1 0
+github.com\Chronokeeper\activego\statement.go:1303.105,1304.26 1 1
+github.com\Chronokeeper\activego\statement.go:1304.26,1306.4 1 0
+github.com\Chronokeeper\activego\statement.go:1306.4,1306.34 1 1
+github.com\Chronokeeper\activego\statement.go:1306.34,1308.4 1 1
+github.com\Chronokeeper\activego\statement.go:1309.3,1309.61 1 0
+github.com\Chronokeeper\activego\statement.go:1309.61,1310.52 1 0
+github.com\Chronokeeper\activego\statement.go:1310.52,1312.4 1 0
+github.com\Chronokeeper\activego\statement.go:1318.46,1319.30 1 1
+github.com\Chronokeeper\activego\statement.go:1319.30,1320.48 1 1
+github.com\Chronokeeper\activego\statement.go:1320.48,1321.55 1 1
+github.com\Chronokeeper\activego\statement.go:1321.55,1322.38 1 1
+github.com\Chronokeeper\activego\statement.go:1322.38,1325.6 1 1
+github.com\Chronokeeper\activego\statement.go:1325.6,1328.6 1 0
+github.com\Chronokeeper\activego\statement.go:1330.4,1331.38 1 0
+github.com\Chronokeeper\activego\statement.go:1331.38,1333.5 1 0
+github.com\Chronokeeper\activego\xorm.go:27.75,30.19 3 1
+github.com\Chronokeeper\activego\xorm.go:34.2,35.16 2 1
+github.com\Chronokeeper\activego\xorm.go:39.2,40.20 2 1
+github.com\Chronokeeper\activego\xorm.go:44.2,45.16 2 1
+github.com\Chronokeeper\activego\xorm.go:49.2,50.16 2 1
+github.com\Chronokeeper\activego\xorm.go:54.2,70.20 5 1
+github.com\Chronokeeper\activego\xorm.go:30.19,32.3 1 0
+github.com\Chronokeeper\activego\xorm.go:35.16,37.3 1 0
+github.com\Chronokeeper\activego\xorm.go:40.20,42.3 1 0
+github.com\Chronokeeper\activego\xorm.go:45.16,47.3 1 0
+github.com\Chronokeeper\activego\xorm.go:50.16,52.3 1 0
+github.com\Chronokeeper\activego\xorm.go:73.30,79.44 1 1
+github.com\Chronokeeper\activego\xorm.go:89.2,89.51 1 1
+github.com\Chronokeeper\activego\xorm.go:95.2,95.13 1 1
+github.com\Chronokeeper\activego\xorm.go:79.44,79.68 1 1
+github.com\Chronokeeper\activego\xorm.go:79.90,79.109 1 1
+github.com\Chronokeeper\activego\xorm.go:80.44,80.68 1 1
+github.com\Chronokeeper\activego\xorm.go:80.90,80.109 1 1
+github.com\Chronokeeper\activego\xorm.go:81.44,81.69 1 1
+github.com\Chronokeeper\activego\xorm.go:81.91,81.110 1 1
+github.com\Chronokeeper\activego\xorm.go:82.44,82.71 1 1
+github.com\Chronokeeper\activego\xorm.go:82.93,82.112 1 1
+github.com\Chronokeeper\activego\xorm.go:83.47,83.69 1 1
+github.com\Chronokeeper\activego\xorm.go:83.91,83.113 1 1
+github.com\Chronokeeper\activego\xorm.go:84.46,84.73 1 1
+github.com\Chronokeeper\activego\xorm.go:84.95,84.116 1 1
+github.com\Chronokeeper\activego\xorm.go:85.45,85.69 1 1
+github.com\Chronokeeper\activego\xorm.go:85.91,85.111 1 1
+github.com\Chronokeeper\activego\xorm.go:86.45,86.72 1 1
+github.com\Chronokeeper\activego\xorm.go:86.94,86.114 1 1
+github.com\Chronokeeper\activego\xorm.go:89.51,90.60 1 1
+github.com\Chronokeeper\activego\xorm.go:90.60,93.4 2 1
+github.com\Chronokeeper\activego\xorm.go:98.28,100.2 1 1
+github.com\Chronokeeper\activego\xorm.go:103.48,105.2 1 0
+github.com\Chronokeeper\activego\engine.go:54.54,57.2 2 0
+github.com\Chronokeeper\activego\engine.go:59.59,60.42 1 0
+github.com\Chronokeeper\activego\engine.go:60.42,62.3 1 0
+github.com\Chronokeeper\activego\engine.go:65.43,67.2 1 0
+github.com\Chronokeeper\activego\engine.go:69.47,71.2 1 0
+github.com\Chronokeeper\activego\engine.go:73.54,76.2 2 1
+github.com\Chronokeeper\activego\engine.go:78.59,80.2 1 1
+github.com\Chronokeeper\activego\engine.go:82.60,84.2 1 1
+github.com\Chronokeeper\activego\engine.go:90.48,92.2 1 0
+github.com\Chronokeeper\activego\engine.go:96.41,98.2 1 0
+github.com\Chronokeeper\activego\engine.go:101.48,102.19 1 1
+github.com\Chronokeeper\activego\engine.go:105.2,105.66 1 1
+github.com\Chronokeeper\activego\engine.go:108.2,108.68 1 1
+github.com\Chronokeeper\activego\engine.go:102.19,104.3 1 0
+github.com\Chronokeeper\activego\engine.go:105.66,107.3 1 0
+github.com\Chronokeeper\activego\engine.go:112.54,114.2 1 0
+github.com\Chronokeeper\activego\engine.go:117.44,119.2 1 0
+github.com\Chronokeeper\activego\engine.go:122.50,124.2 1 0
+github.com\Chronokeeper\activego\engine.go:127.46,129.2 1 0
+github.com\Chronokeeper\activego\engine.go:132.50,134.2 1 0
+github.com\Chronokeeper\activego\engine.go:137.60,139.2 1 0
+github.com\Chronokeeper\activego\engine.go:143.42,147.2 3 0
+github.com\Chronokeeper\activego\engine.go:149.44,153.2 3 0
+github.com\Chronokeeper\activego\engine.go:156.71,160.2 3 0
+github.com\Chronokeeper\activego\engine.go:163.49,165.2 1 0
+github.com\Chronokeeper\activego\engine.go:167.37,169.2 1 0
+github.com\Chronokeeper\activego\engine.go:171.46,173.2 1 1
+github.com\Chronokeeper\activego\engine.go:176.45,180.2 3 1
+github.com\Chronokeeper\activego\engine.go:183.37,185.2 1 1
+github.com\Chronokeeper\activego\engine.go:188.36,193.2 4 0
+github.com\Chronokeeper\activego\engine.go:196.69,197.20 1 1
+github.com\Chronokeeper\activego\engine.go:197.20,199.23 2 0
+github.com\Chronokeeper\activego\engine.go:199.23,201.4 1 0
+github.com\Chronokeeper\activego\engine.go:201.4,203.4 1 0
+github.com\Chronokeeper\activego\engine.go:207.159,208.22 1 0
+github.com\Chronokeeper\activego\engine.go:208.22,214.3 5 0
+github.com\Chronokeeper\activego\engine.go:214.3,216.3 1 0
+github.com\Chronokeeper\activego\engine.go:219.139,220.22 1 0
+github.com\Chronokeeper\activego\engine.go:220.22,226.3 5 0
+github.com\Chronokeeper\activego\engine.go:226.3,228.3 1 0
+github.com\Chronokeeper\activego\engine.go:232.69,234.34 2 0
+github.com\Chronokeeper\activego\engine.go:234.34,236.3 0 0
+github.com\Chronokeeper\activego\engine.go:236.3,236.37 1 0
+github.com\Chronokeeper\activego\engine.go:236.37,238.3 1 0
+github.com\Chronokeeper\activego\engine.go:242.57,243.20 1 0
+github.com\Chronokeeper\activego\engine.go:243.20,246.3 2 0
+github.com\Chronokeeper\activego\engine.go:249.73,250.20 1 0
+github.com\Chronokeeper\activego\engine.go:250.20,253.3 2 0
+github.com\Chronokeeper\activego\engine.go:257.56,258.21 1 0
+github.com\Chronokeeper\activego\engine.go:258.21,261.3 2 0
+github.com\Chronokeeper\activego\engine.go:264.72,265.20 1 0
+github.com\Chronokeeper\activego\engine.go:265.20,268.3 2 0
+github.com\Chronokeeper\activego\engine.go:272.57,273.22 1 1
+github.com\Chronokeeper\activego\engine.go:273.22,276.3 2 0
+github.com\Chronokeeper\activego\engine.go:279.73,280.22 1 0
+github.com\Chronokeeper\activego\engine.go:280.22,283.3 2 0
+github.com\Chronokeeper\activego\engine.go:287.56,288.21 1 0
+github.com\Chronokeeper\activego\engine.go:288.21,291.3 2 0
+github.com\Chronokeeper\activego\engine.go:294.72,295.21 1 0
+github.com\Chronokeeper\activego\engine.go:295.21,298.3 2 0
+github.com\Chronokeeper\activego\engine.go:308.77,312.2 3 0
+github.com\Chronokeeper\activego\engine.go:317.45,321.2 3 0
+github.com\Chronokeeper\activego\engine.go:324.56,326.16 2 0
+github.com\Chronokeeper\activego\engine.go:330.2,330.31 1 0
+github.com\Chronokeeper\activego\engine.go:356.2,356.20 1 0
+github.com\Chronokeeper\activego\engine.go:326.16,328.3 1 0
+github.com\Chronokeeper\activego\engine.go:330.31,332.17 2 0
+github.com\Chronokeeper\activego\engine.go:335.3,335.31 1 0
+github.com\Chronokeeper\activego\engine.go:340.3,341.17 2 0
+github.com\Chronokeeper\activego\engine.go:344.3,346.33 2 0
+github.com\Chronokeeper\activego\engine.go:332.17,334.4 1 0
+github.com\Chronokeeper\activego\engine.go:335.31,337.4 1 0
+github.com\Chronokeeper\activego\engine.go:341.17,343.4 1 0
+github.com\Chronokeeper\activego\engine.go:346.33,347.36 1 0
+github.com\Chronokeeper\activego\engine.go:347.36,348.49 1 0
+github.com\Chronokeeper\activego\engine.go:348.49,350.6 1 0
+github.com\Chronokeeper\activego\engine.go:350.6,352.6 1 0
+github.com\Chronokeeper\activego\engine.go:362.54,364.16 2 0
+github.com\Chronokeeper\activego\engine.go:367.2,368.26 2 0
+github.com\Chronokeeper\activego\engine.go:364.16,366.3 1 0
+github.com\Chronokeeper\activego\engine.go:374.50,376.16 2 0
+github.com\Chronokeeper\activego\engine.go:380.2,380.31 1 0
+github.com\Chronokeeper\activego\engine.go:452.2,452.12 1 0
+github.com\Chronokeeper\activego\engine.go:376.16,378.3 1 0
+github.com\Chronokeeper\activego\engine.go:380.31,382.17 2 0
+github.com\Chronokeeper\activego\engine.go:385.3,385.39 1 0
+github.com\Chronokeeper\activego\engine.go:392.3,393.17 2 0
+github.com\Chronokeeper\activego\engine.go:397.3,398.17 2 0
+github.com\Chronokeeper\activego\engine.go:401.3,401.21 1 0
+github.com\Chronokeeper\activego\engine.go:404.3,404.19 1 0
+github.com\Chronokeeper\activego\engine.go:382.17,384.4 1 0
+github.com\Chronokeeper\activego\engine.go:385.39,387.18 2 0
+github.com\Chronokeeper\activego\engine.go:387.18,389.5 1 0
+github.com\Chronokeeper\activego\engine.go:393.17,395.4 1 0
+github.com\Chronokeeper\activego\engine.go:398.17,400.4 1 0
+github.com\Chronokeeper\activego\engine.go:401.21,402.12 1 0
+github.com\Chronokeeper\activego\engine.go:404.19,407.18 3 0
+github.com\Chronokeeper\activego\engine.go:411.4,412.18 2 0
+github.com\Chronokeeper\activego\engine.go:416.4,417.27 2 0
+github.com\Chronokeeper\activego\engine.go:446.4,447.18 2 0
+github.com\Chronokeeper\activego\engine.go:407.18,409.5 1 0
+github.com\Chronokeeper\activego\engine.go:412.18,414.5 1 0
+github.com\Chronokeeper\activego\engine.go:417.27,419.17 2 0
+github.com\Chronokeeper\activego\engine.go:419.17,421.6 1 0
+github.com\Chronokeeper\activego\engine.go:421.6,421.60 1 0
+github.com\Chronokeeper\activego\engine.go:421.60,424.6 2 0
+github.com\Chronokeeper\activego\engine.go:424.6,424.36 1 0
+github.com\Chronokeeper\activego\engine.go:424.36,425.51 1 0
+github.com\Chronokeeper\activego\engine.go:425.51,427.7 1 0
+github.com\Chronokeeper\activego\engine.go:427.7,427.59 1 0
+github.com\Chronokeeper\activego\engine.go:427.59,429.7 1 0
+github.com\Chronokeeper\activego\engine.go:430.6,430.39 1 0
+github.com\Chronokeeper\activego\engine.go:430.39,431.38 1 0
+github.com\Chronokeeper\activego\engine.go:432.6,433.54 1 0
+github.com\Chronokeeper\activego\engine.go:434.6,435.37 1 0
+github.com\Chronokeeper\activego\engine.go:437.6,439.62 2 0
+github.com\Chronokeeper\activego\engine.go:439.62,441.7 1 0
+github.com\Chronokeeper\activego\engine.go:441.7,443.7 1 0
+github.com\Chronokeeper\activego\engine.go:447.18,449.5 1 0
+github.com\Chronokeeper\activego\engine.go:456.61,460.2 3 0
+github.com\Chronokeeper\activego\engine.go:463.79,467.2 3 0
+github.com\Chronokeeper\activego\engine.go:470.51,474.2 3 1
+github.com\Chronokeeper\activego\engine.go:477.67,481.2 3 0
+github.com\Chronokeeper\activego\engine.go:484.66,488.2 3 0
+github.com\Chronokeeper\activego\engine.go:491.56,495.2 3 0
+github.com\Chronokeeper\activego\engine.go:498.64,502.2 3 0
+github.com\Chronokeeper\activego\engine.go:507.60,511.2 3 0
+github.com\Chronokeeper\activego\engine.go:514.56,518.2 3 0
+github.com\Chronokeeper\activego\engine.go:520.42,524.2 3 0
+github.com\Chronokeeper\activego\engine.go:526.60,530.2 3 0
+github.com\Chronokeeper\activego\engine.go:537.59,541.2 3 0
+github.com\Chronokeeper\activego\engine.go:544.56,548.2 3 0
+github.com\Chronokeeper\activego\engine.go:551.71,555.2 3 0
+github.com\Chronokeeper\activego\engine.go:558.72,562.2 3 0
+github.com\Chronokeeper\activego\engine.go:565.72,569.2 3 0
+github.com\Chronokeeper\activego\engine.go:572.74,576.2 3 0
+github.com\Chronokeeper\activego\engine.go:579.67,583.2 3 0
+github.com\Chronokeeper\activego\engine.go:586.52,590.2 3 0
+github.com\Chronokeeper\activego\engine.go:593.63,597.2 3 0
+github.com\Chronokeeper\activego\engine.go:601.57,605.2 3 0
+github.com\Chronokeeper\activego\engine.go:613.56,617.2 3 0
+github.com\Chronokeeper\activego\engine.go:620.54,624.2 3 0
+github.com\Chronokeeper\activego\engine.go:627.100,631.2 3 0
+github.com\Chronokeeper\activego\engine.go:634.53,638.2 3 0
+github.com\Chronokeeper\activego\engine.go:641.58,645.2 3 0
+github.com\Chronokeeper\activego\engine.go:647.64,652.9 5 1
+github.com\Chronokeeper\activego\engine.go:663.2,663.14 1 1
+github.com\Chronokeeper\activego\engine.go:652.9,656.18 4 1
+github.com\Chronokeeper\activego\engine.go:661.3,661.24 1 1
+github.com\Chronokeeper\activego\engine.go:656.18,658.4 1 1
+github.com\Chronokeeper\activego\engine.go:658.4,660.4 1 0
+github.com\Chronokeeper\activego\engine.go:666.58,670.2 2 1
+github.com\Chronokeeper\activego\engine.go:672.63,675.2 2 1
+github.com\Chronokeeper\activego\engine.go:677.85,678.47 1 1
+github.com\Chronokeeper\activego\engine.go:678.47,681.3 2 0
+github.com\Chronokeeper\activego\engine.go:681.3,686.3 4 1
+github.com\Chronokeeper\activego\engine.go:689.46,692.32 2 1
+github.com\Chronokeeper\activego\engine.go:695.2,695.14 1 1
+github.com\Chronokeeper\activego\engine.go:692.32,694.3 1 1
+github.com\Chronokeeper\activego\engine.go:698.60,702.23 4 1
+github.com\Chronokeeper\activego\engine.go:707.2,707.22 1 1
+github.com\Chronokeeper\activego\engine.go:715.2,715.22 1 1
+github.com\Chronokeeper\activego\engine.go:718.2,726.36 6 1
+github.com\Chronokeeper\activego\engine.go:945.2,945.57 1 1
+github.com\Chronokeeper\activego\engine.go:954.2,954.17 1 1
+github.com\Chronokeeper\activego\engine.go:963.2,963.19 1 1
+github.com\Chronokeeper\activego\engine.go:968.2,968.14 1 1
+github.com\Chronokeeper\activego\engine.go:702.23,703.18 1 1
+github.com\Chronokeeper\activego\engine.go:703.18,705.4 1 1
+github.com\Chronokeeper\activego\engine.go:707.22,710.24 3 0
+github.com\Chronokeeper\activego\engine.go:710.24,712.4 1 0
+github.com\Chronokeeper\activego\engine.go:715.22,717.3 1 1
+github.com\Chronokeeper\activego\engine.go:726.36,734.22 6 1
+github.com\Chronokeeper\activego\engine.go:934.3,934.26 1 1
+github.com\Chronokeeper\activego\engine.go:938.3,940.144 2 1
+github.com\Chronokeeper\activego\engine.go:734.22,739.21 3 1
+github.com\Chronokeeper\activego\engine.go:739.21,740.23 1 1
+github.com\Chronokeeper\activego\engine.go:743.5,743.46 1 1
+github.com\Chronokeeper\activego\engine.go:772.5,775.30 4 1
+github.com\Chronokeeper\activego\engine.go:894.5,894.31 1 1
+github.com\Chronokeeper\activego\engine.go:897.5,897.24 1 1
+github.com\Chronokeeper\activego\engine.go:900.5,900.25 1 1
+github.com\Chronokeeper\activego\engine.go:904.5,904.23 1 1
+github.com\Chronokeeper\activego\engine.go:908.5,908.17 1 1
+github.com\Chronokeeper\activego\engine.go:914.5,914.50 1 1
+github.com\Chronokeeper\activego\engine.go:740.23,741.14 1 0
+github.com\Chronokeeper\activego\engine.go:743.46,744.45 1 0
+github.com\Chronokeeper\activego\engine.go:744.45,746.49 2 0
+github.com\Chronokeeper\activego\engine.go:751.7,751.15 1 0
+github.com\Chronokeeper\activego\engine.go:746.49,749.8 2 0
+github.com\Chronokeeper\activego\engine.go:752.7,752.49 1 0
+github.com\Chronokeeper\activego\engine.go:752.49,754.37 2 0
+github.com\Chronokeeper\activego\engine.go:761.7,762.49 2 0
+github.com\Chronokeeper\activego\engine.go:767.7,767.15 1 0
+github.com\Chronokeeper\activego\engine.go:754.37,756.55 2 0
+github.com\Chronokeeper\activego\engine.go:756.55,758.9 1 0
+github.com\Chronokeeper\activego\engine.go:762.49,765.8 2 0
+github.com\Chronokeeper\activego\engine.go:775.30,777.13 2 1
+github.com\Chronokeeper\activego\engine.go:892.6,892.16 1 1
+github.com\Chronokeeper\activego\engine.go:778.6,779.36 1 0
+github.com\Chronokeeper\activego\engine.go:780.6,781.34 1 0
+github.com\Chronokeeper\activego\engine.go:782.6,784.27 2 1
+github.com\Chronokeeper\activego\engine.go:785.6,786.17 1 1
+github.com\Chronokeeper\activego\engine.go:801.6,802.33 1 1
+github.com\Chronokeeper\activego\engine.go:804.6,805.30 1 0
+github.com\Chronokeeper\activego\engine.go:806.6,807.27 1 0
+github.com\Chronokeeper\activego\engine.go:808.6,810.24 2 0
+github.com\Chronokeeper\activego\engine.go:811.6,812.27 1 0
+github.com\Chronokeeper\activego\engine.go:813.6,814.27 1 0
+github.com\Chronokeeper\activego\engine.go:815.6,817.45 2 0
+github.com\Chronokeeper\activego\engine.go:818.6,819.21 1 0
+github.com\Chronokeeper\activego\engine.go:820.6,822.46 2 0
+github.com\Chronokeeper\activego\engine.go:823.6,824.22 1 1
+github.com\Chronokeeper\activego\engine.go:825.6,826.27 1 0
+github.com\Chronokeeper\activego\engine.go:827.6,828.23 1 0
+github.com\Chronokeeper\activego\engine.go:831.6,832.25 1 0
+github.com\Chronokeeper\activego\engine.go:835.6,835.22 0 1
+github.com\Chronokeeper\activego\engine.go:836.6,837.65 1 1
+github.com\Chronokeeper\activego\engine.go:890.7,890.34 1 1
+github.com\Chronokeeper\activego\engine.go:786.17,788.8 1 0
+github.com\Chronokeeper\activego\engine.go:788.8,790.8 1 1
+github.com\Chronokeeper\activego\engine.go:828.23,830.8 1 0
+github.com\Chronokeeper\activego\engine.go:832.25,834.8 1 0
+github.com\Chronokeeper\activego\engine.go:837.65,838.31 1 0
+github.com\Chronokeeper\activego\engine.go:838.31,840.9 1 0
+github.com\Chronokeeper\activego\engine.go:841.8,841.71 1 1
+github.com\Chronokeeper\activego\engine.go:841.71,844.46 2 0
+github.com\Chronokeeper\activego\engine.go:848.8,849.50 2 0
+github.com\Chronokeeper\activego\engine.go:844.46,846.17 2 0
+github.com\Chronokeeper\activego\engine.go:849.50,852.35 3 0
+github.com\Chronokeeper\activego\engine.go:852.35,856.10 3 0
+github.com\Chronokeeper\activego\engine.go:857.9,857.56 1 0
+github.com\Chronokeeper\activego\engine.go:857.56,860.35 3 0
+github.com\Chronokeeper\activego\engine.go:860.35,864.10 3 0
+github.com\Chronokeeper\activego\engine.go:865.9,867.26 2 0
+github.com\Chronokeeper\activego\engine.go:867.26,869.24 2 0
+github.com\Chronokeeper\activego\engine.go:872.10,873.24 2 0
+github.com\Chronokeeper\activego\engine.go:869.24,871.11 1 0
+github.com\Chronokeeper\activego\engine.go:873.24,875.11 1 0
+github.com\Chronokeeper\activego\engine.go:876.10,876.33 1 0
+github.com\Chronokeeper\activego\engine.go:876.33,878.24 2 0
+github.com\Chronokeeper\activego\engine.go:878.24,880.11 1 0
+github.com\Chronokeeper\activego\engine.go:883.8,884.41 1 1
+github.com\Chronokeeper\activego\engine.go:884.41,886.9 1 1
+github.com\Chronokeeper\activego\engine.go:886.9,886.37 1 0
+github.com\Chronokeeper\activego\engine.go:886.37,888.9 1 0
+github.com\Chronokeeper\activego\engine.go:894.31,896.6 1 0
+github.com\Chronokeeper\activego\engine.go:897.24,899.6 1 1
+github.com\Chronokeeper\activego\engine.go:900.25,902.6 1 1
+github.com\Chronokeeper\activego\engine.go:904.23,906.6 1 1
+github.com\Chronokeeper\activego\engine.go:908.17,910.6 1 1
+github.com\Chronokeeper\activego\engine.go:910.6,910.23 1 0
+github.com\Chronokeeper\activego\engine.go:910.23,912.6 1 0
+github.com\Chronokeeper\activego\engine.go:914.50,916.6 1 1
+github.com\Chronokeeper\activego\engine.go:918.4,920.28 2 1
+github.com\Chronokeeper\activego\engine.go:925.4,925.61 1 1
+github.com\Chronokeeper\activego\engine.go:930.4,932.34 1 1
+github.com\Chronokeeper\activego\engine.go:920.28,921.69 1 1
+github.com\Chronokeeper\activego\engine.go:921.69,923.6 1 0
+github.com\Chronokeeper\activego\engine.go:925.61,927.5 1 0
+github.com\Chronokeeper\activego\engine.go:927.5,929.5 1 1
+github.com\Chronokeeper\activego\engine.go:934.26,936.4 1 1
+github.com\Chronokeeper\activego\engine.go:940.144,942.4 1 0
+github.com\Chronokeeper\activego\engine.go:945.57,952.3 6 0
+github.com\Chronokeeper\activego\engine.go:954.17,955.27 1 0
+github.com\Chronokeeper\activego\engine.go:955.27,958.4 2 0
+github.com\Chronokeeper\activego\engine.go:958.4,961.4 2 0
+github.com\Chronokeeper\activego\engine.go:963.19,966.3 2 0
+github.com\Chronokeeper\activego\engine.go:972.63,975.29 3 0
+github.com\Chronokeeper\activego\engine.go:979.2,979.8 1 0
+github.com\Chronokeeper\activego\engine.go:975.29,978.3 2 0
+github.com\Chronokeeper\activego\engine.go:983.68,987.2 3 0
+github.com\Chronokeeper\activego\engine.go:990.79,994.2 3 0
+github.com\Chronokeeper\activego\engine.go:996.54,998.2 1 0
+github.com\Chronokeeper\activego\engine.go:1000.55,1004.40 4 0
+github.com\Chronokeeper\activego\engine.go:1015.2,1015.20 1 0
+github.com\Chronokeeper\activego\engine.go:1004.40,1006.25 2 0
+github.com\Chronokeeper\activego\engine.go:1007.3,1008.28 1 0
+github.com\Chronokeeper\activego\engine.go:1009.3,1010.25 1 0
+github.com\Chronokeeper\activego\engine.go:1011.3,1012.26 1 0
+github.com\Chronokeeper\activego\engine.go:1019.61,1023.2 3 0
+github.com\Chronokeeper\activego\engine.go:1026.61,1030.2 3 0
+github.com\Chronokeeper\activego\engine.go:1032.65,1034.2 1 1
+github.com\Chronokeeper\activego\engine.go:1036.62,1037.50 1 0
+github.com\Chronokeeper\activego\engine.go:1040.2,1040.22 1 0
+github.com\Chronokeeper\activego\engine.go:1037.50,1039.3 1 0
+github.com\Chronokeeper\activego\engine.go:1044.73,1046.32 2 0
+github.com\Chronokeeper\activego\engine.go:1049.2,1051.19 3 0
+github.com\Chronokeeper\activego\engine.go:1054.2,1054.19 1 0
+github.com\Chronokeeper\activego\engine.go:1058.2,1058.12 1 0
+github.com\Chronokeeper\activego\engine.go:1046.32,1048.3 1 0
+github.com\Chronokeeper\activego\engine.go:1051.19,1053.3 1 0
+github.com\Chronokeeper\activego\engine.go:1054.19,1057.3 2 0
+github.com\Chronokeeper\activego\engine.go:1062.62,1063.29 1 0
+github.com\Chronokeeper\activego\engine.go:1078.2,1078.12 1 0
+github.com\Chronokeeper\activego\engine.go:1063.29,1065.33 2 0
+github.com\Chronokeeper\activego\engine.go:1068.3,1070.20 3 0
+github.com\Chronokeeper\activego\engine.go:1073.3,1073.20 1 0
+github.com\Chronokeeper\activego\engine.go:1065.33,1067.4 1 0
+github.com\Chronokeeper\activego\engine.go:1070.20,1072.4 1 0
+github.com\Chronokeeper\activego\engine.go:1073.20,1076.4 2 0
+github.com\Chronokeeper\activego\engine.go:1084.56,1085.29 1 0
+github.com\Chronokeeper\activego\engine.go:1173.2,1173.12 1 0
+github.com\Chronokeeper\activego\engine.go:1085.29,1091.17 5 0
+github.com\Chronokeeper\activego\engine.go:1094.3,1094.15 1 0
+github.com\Chronokeeper\activego\engine.go:1104.3,1105.14 2 0
+github.com\Chronokeeper\activego\engine.go:1091.17,1093.4 1 0
+github.com\Chronokeeper\activego\engine.go:1094.15,1096.18 2 0
+github.com\Chronokeeper\activego\engine.go:1096.18,1098.5 1 0
+github.com\Chronokeeper\activego\engine.go:1105.14,1107.18 2 0
+github.com\Chronokeeper\activego\engine.go:1110.4,1111.18 2 0
+github.com\Chronokeeper\activego\engine.go:1107.18,1109.5 1 0
+github.com\Chronokeeper\activego\engine.go:1111.18,1113.5 1 0
+github.com\Chronokeeper\activego\engine.go:1114.4,1115.40 1 0
+github.com\Chronokeeper\activego\engine.go:1134.4,1134.43 1 0
+github.com\Chronokeeper\activego\engine.go:1115.40,1120.19 5 0
+github.com\Chronokeeper\activego\engine.go:1123.5,1123.17 1 0
+github.com\Chronokeeper\activego\engine.go:1120.19,1122.6 1 0
+github.com\Chronokeeper\activego\engine.go:1123.17,1128.20 5 0
+github.com\Chronokeeper\activego\engine.go:1128.20,1130.7 1 0
+github.com\Chronokeeper\activego\engine.go:1134.43,1138.38 4 0
+github.com\Chronokeeper\activego\engine.go:1138.38,1141.20 2 0
+github.com\Chronokeeper\activego\engine.go:1144.6,1144.18 1 0
+github.com\Chronokeeper\activego\engine.go:1141.20,1143.7 1 0
+github.com\Chronokeeper\activego\engine.go:1144.18,1149.21 5 0
+github.com\Chronokeeper\activego\engine.go:1149.21,1151.8 1 0
+github.com\Chronokeeper\activego\engine.go:1153.6,1153.44 1 0
+github.com\Chronokeeper\activego\engine.go:1153.44,1155.20 2 0
+github.com\Chronokeeper\activego\engine.go:1158.6,1158.18 1 0
+github.com\Chronokeeper\activego\engine.go:1155.20,1157.7 1 0
+github.com\Chronokeeper\activego\engine.go:1158.18,1163.21 5 0
+github.com\Chronokeeper\activego\engine.go:1163.21,1165.8 1 0
+github.com\Chronokeeper\activego\engine.go:1167.6,1169.6 1 0
+github.com\Chronokeeper\activego\engine.go:1176.57,1180.2 3 0
+github.com\Chronokeeper\activego\engine.go:1182.61,1185.29 3 0
+github.com\Chronokeeper\activego\engine.go:1191.2,1191.8 1 0
+github.com\Chronokeeper\activego\engine.go:1185.29,1187.36 2 0
+github.com\Chronokeeper\activego\engine.go:1187.36,1189.4 1 0
+github.com\Chronokeeper\activego\engine.go:1195.39,1200.16 4 0
+github.com\Chronokeeper\activego\engine.go:1203.2,1204.16 2 0
+github.com\Chronokeeper\activego\engine.go:1208.2,1208.25 1 0
+github.com\Chronokeeper\activego\engine.go:1200.16,1202.3 1 0
+github.com\Chronokeeper\activego\engine.go:1204.16,1207.3 2 0
+github.com\Chronokeeper\activego\engine.go:1212.64,1216.16 4 0
+github.com\Chronokeeper\activego\engine.go:1220.2,1220.29 1 0
+github.com\Chronokeeper\activego\engine.go:1227.2,1227.25 1 0
+github.com\Chronokeeper\activego\engine.go:1216.16,1218.3 1 0
+github.com\Chronokeeper\activego\engine.go:1220.29,1222.17 2 0
+github.com\Chronokeeper\activego\engine.go:1222.17,1225.4 2 0
+github.com\Chronokeeper\activego\engine.go:1230.62,1235.16 4 0
+github.com\Chronokeeper\activego\engine.go:1239.2,1239.29 1 0
+github.com\Chronokeeper\activego\engine.go:1246.2,1246.25 1 0
+github.com\Chronokeeper\activego\engine.go:1235.16,1237.3 1 0
+github.com\Chronokeeper\activego\engine.go:1239.29,1241.17 2 0
+github.com\Chronokeeper\activego\engine.go:1241.17,1244.4 2 0
+github.com\Chronokeeper\activego\engine.go:1249.41,1253.2 3 0
+github.com\Chronokeeper\activego\engine.go:1256.81,1260.2 3 0
+github.com\Chronokeeper\activego\engine.go:1263.112,1267.2 3 0
+github.com\Chronokeeper\activego\engine.go:1270.113,1274.2 3 0
+github.com\Chronokeeper\activego\engine.go:1292.67,1296.2 3 0
+github.com\Chronokeeper\activego\engine.go:1299.66,1303.2 3 0
+github.com\Chronokeeper\activego\engine.go:1311.90,1315.2 3 0
+github.com\Chronokeeper\activego\engine.go:1318.63,1322.2 3 0
+github.com\Chronokeeper\activego\engine.go:1326.59,1330.2 3 0
+github.com\Chronokeeper\activego\engine.go:1335.80,1339.2 3 0
+github.com\Chronokeeper\activego\engine.go:1343.69,1347.2 3 0
+github.com\Chronokeeper\activego\engine.go:1351.61,1354.2 2 0
+github.com\Chronokeeper\activego\engine.go:1358.62,1362.2 3 0
+github.com\Chronokeeper\activego\engine.go:1365.72,1367.16 2 0
+github.com\Chronokeeper\activego\engine.go:1370.2,1371.28 2 0
+github.com\Chronokeeper\activego\engine.go:1367.16,1369.3 1 0
+github.com\Chronokeeper\activego\engine.go:1375.65,1380.89 4 0
+github.com\Chronokeeper\activego\engine.go:1395.2,1397.21 2 0
+github.com\Chronokeeper\activego\engine.go:1408.2,1408.27 1 0
+github.com\Chronokeeper\activego\engine.go:1380.89,1381.30 1 0
+github.com\Chronokeeper\activego\engine.go:1384.3,1384.46 1 0
+github.com\Chronokeeper\activego\engine.go:1388.3,1388.12 1 0
+github.com\Chronokeeper\activego\engine.go:1392.3,1392.21 1 0
+github.com\Chronokeeper\activego\engine.go:1381.30,1383.4 1 0
+github.com\Chronokeeper\activego\engine.go:1384.46,1386.4 1 0
+github.com\Chronokeeper\activego\engine.go:1388.12,1390.4 1 0
+github.com\Chronokeeper\activego\engine.go:1397.21,1400.21 3 0
+github.com\Chronokeeper\activego\engine.go:1400.21,1403.18 3 0
+github.com\Chronokeeper\activego\engine.go:1403.18,1405.5 1 0
+github.com\Chronokeeper\activego\engine.go:1415.53,1417.20 1 0
+github.com\Chronokeeper\activego\engine.go:1420.2,1420.10 1 0
+github.com\Chronokeeper\activego\engine.go:1417.20,1419.3 1 0
+github.com\Chronokeeper\activego\engine.go:1423.63,1426.2 2 0
+github.com\Chronokeeper\activego\engine.go:1428.77,1431.2 2 0
+github.com\Chronokeeper\activego\engine.go:1433.83,1434.44 1 0
+github.com\Chronokeeper\activego\engine.go:1437.2,1437.21 1 0
+github.com\Chronokeeper\activego\engine.go:1464.2,1464.8 1 0
+github.com\Chronokeeper\activego\engine.go:1434.44,1436.3 1 0
+github.com\Chronokeeper\activego\engine.go:1438.2,1440.15 2 0
+github.com\Chronokeeper\activego\engine.go:1441.2,1442.44 1 0
+github.com\Chronokeeper\activego\engine.go:1443.2,1444.38 1 0
+github.com\Chronokeeper\activego\engine.go:1451.2,1452.44 1 0
+github.com\Chronokeeper\activego\engine.go:1459.2,1460.30 1 0
+github.com\Chronokeeper\activego\engine.go:1461.2,1462.23 1 0
+github.com\Chronokeeper\activego\engine.go:1444.38,1446.4 1 0
+github.com\Chronokeeper\activego\engine.go:1446.4,1446.50 1 0
+github.com\Chronokeeper\activego\engine.go:1446.50,1448.4 1 0
+github.com\Chronokeeper\activego\engine.go:1448.4,1450.4 1 0
+github.com\Chronokeeper\activego\engine.go:1452.44,1454.4 1 0
+github.com\Chronokeeper\activego\engine.go:1454.4,1454.44 1 0
+github.com\Chronokeeper\activego\engine.go:1454.44,1456.4 1 0
+github.com\Chronokeeper\activego\engine.go:1456.4,1458.4 1 0
+github.com\Chronokeeper\activego\engine.go:1468.43,1472.2 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:180.91,182.2 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:184.49,186.32 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:234.2,237.48 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:242.2,242.13 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:247.2,247.12 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:187.2,189.15 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:190.2,194.17 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:195.2,199.20 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:200.2,201.18 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:202.2,204.16 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:205.2,209.35 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:212.3,213.13 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:214.2,218.34 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:221.3,222.13 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:223.2,224.21 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:225.2,227.16 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:228.2,229.18 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:230.2,231.10 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:209.35,211.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:218.34,220.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:237.48,240.3 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:242.13,244.3 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:244.3,244.20 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:244.20,246.3 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:250.43,252.2 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:254.47,257.2 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:259.44,261.2 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:263.36,265.2 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:267.39,269.2 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:271.39,273.2 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:275.40,277.2 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:279.38,281.2 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:283.83,288.2 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:296.74,300.2 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:302.90,308.22 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:312.2,312.16 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:315.2,319.18 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:411.2,411.26 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:308.22,310.3 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:312.16,314.3 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:319.18,326.17 6 0
+github.com\Chronokeeper\activego\mysql_dialect.go:329.3,330.26 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:334.3,334.24 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:341.3,345.20 5 0
+github.com\Chronokeeper\activego\mysql_dialect.go:377.3,377.34 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:380.3,382.42 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:388.3,388.22 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:391.3,391.22 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:395.3,395.32 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:399.3,399.51 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:408.3,409.36 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:326.17,328.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:330.26,332.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:334.24,336.25 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:336.25,338.5 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:345.20,347.49 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:347.49,350.31 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:350.31,354.6 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:355.5,355.55 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:355.55,358.31 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:358.31,362.6 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:363.5,366.19 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:369.5,369.23 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:366.19,368.6 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:369.23,371.20 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:371.20,373.7 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:377.34,379.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:382.42,384.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:384.4,386.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:388.22,390.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:391.22,393.4 0 0
+github.com\Chronokeeper\activego\mysql_dialect.go:395.32,397.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:399.51,400.25 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:400.25,402.5 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:402.5,403.27 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:403.27,405.6 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:414.53,420.22 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:423.2,423.16 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:426.2,429.18 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:442.2,442.20 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:420.22,422.3 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:423.16,425.3 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:429.18,434.17 5 0
+github.com\Chronokeeper\activego\mysql_dialect.go:438.3,440.33 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:434.17,436.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:445.79,450.22 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:453.2,453.16 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:456.2,459.18 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:495.2,495.21 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:450.22,452.3 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:453.16,455.3 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:459.18,463.17 4 0
+github.com\Chronokeeper\activego\mysql_dialect.go:467.3,467.29 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:471.3,471.45 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:477.3,479.103 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:484.3,486.42 3 0
+github.com\Chronokeeper\activego\mysql_dialect.go:493.3,493.27 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:463.17,465.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:467.29,468.12 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:471.45,473.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:473.4,475.4 1 0
+github.com\Chronokeeper\activego\mysql_dialect.go:479.103,482.4 2 0
+github.com\Chronokeeper\activego\mysql_dialect.go:486.42,492.4 5 0
+github.com\Chronokeeper\activego\mysql_dialect.go:498.42,500.2 1 0
+github.com\Chronokeeper\activego\pq_driver.go:26.35,28.2 1 1
+github.com\Chronokeeper\activego\pq_driver.go:30.43,32.2 1 1
+github.com\Chronokeeper\activego\pq_driver.go:34.44,36.2 1 0
+github.com\Chronokeeper\activego\pq_driver.go:38.47,40.16 2 1
+github.com\Chronokeeper\activego\pq_driver.go:44.2,44.28 1 1
+github.com\Chronokeeper\activego\pq_driver.go:48.2,50.30 3 1
+github.com\Chronokeeper\activego\pq_driver.go:56.2,56.19 1 1
+github.com\Chronokeeper\activego\pq_driver.go:64.2,65.11 2 1
+github.com\Chronokeeper\activego\pq_driver.go:72.2,72.18 1 1
+github.com\Chronokeeper\activego\pq_driver.go:76.2,77.19 2 1
+github.com\Chronokeeper\activego\pq_driver.go:81.2,82.36 2 1
+github.com\Chronokeeper\activego\pq_driver.go:40.16,42.3 1 0
+github.com\Chronokeeper\activego\pq_driver.go:44.28,46.3 1 0
+github.com\Chronokeeper\activego\pq_driver.go:50.30,51.14 1 1
+github.com\Chronokeeper\activego\pq_driver.go:51.14,53.4 1 1
+github.com\Chronokeeper\activego\pq_driver.go:56.19,62.3 4 1
+github.com\Chronokeeper\activego\pq_driver.go:65.11,67.3 1 0
+github.com\Chronokeeper\activego\pq_driver.go:67.3,70.3 2 1
+github.com\Chronokeeper\activego\pq_driver.go:72.18,74.3 1 1
+github.com\Chronokeeper\activego\pq_driver.go:77.19,79.3 1 1
+github.com\Chronokeeper\activego\pq_driver.go:85.39,86.20 1 1
+github.com\Chronokeeper\activego\pq_driver.go:90.2,93.23 3 1
+github.com\Chronokeeper\activego\pq_driver.go:86.20,88.3 1 0
+github.com\Chronokeeper\activego\pq_driver.go:93.23,95.18 2 1
+github.com\Chronokeeper\activego\pq_driver.go:98.3,98.22 1 1
+github.com\Chronokeeper\activego\pq_driver.go:95.18,97.4 1 0
+github.com\Chronokeeper\activego\pq_driver.go:102.80,106.54 4 1
+github.com\Chronokeeper\activego\pq_driver.go:112.2,115.21 3 1
+github.com\Chronokeeper\activego\pq_driver.go:118.2,118.16 1 1
+github.com\Chronokeeper\activego\pq_driver.go:106.54,108.17 2 1
+github.com\Chronokeeper\activego\pq_driver.go:108.17,110.4 1 0
+github.com\Chronokeeper\activego\pq_driver.go:115.21,117.3 1 0
+github.com\Chronokeeper\activego\rows.go:27.65,37.41 8 0
+github.com\Chronokeeper\activego\rows.go:44.2,44.63 1 0
+github.com\Chronokeeper\activego\rows.go:48.2,51.16 4 0
+github.com\Chronokeeper\activego\rows.go:57.2,58.16 2 0
+github.com\Chronokeeper\activego\rows.go:64.2,65.16 2 0
+github.com\Chronokeeper\activego\rows.go:70.2,72.18 2 0
+github.com\Chronokeeper\activego\rows.go:37.41,39.3 1 0
+github.com\Chronokeeper\activego\rows.go:39.3,42.3 2 0
+github.com\Chronokeeper\activego\rows.go:44.63,46.3 1 0
+github.com\Chronokeeper\activego\rows.go:51.16,55.3 3 0
+github.com\Chronokeeper\activego\rows.go:58.16,62.3 3 0
+github.com\Chronokeeper\activego\rows.go:65.16,69.3 3 0
+github.com\Chronokeeper\activego\rows.go:76.31,77.47 1 0
+github.com\Chronokeeper\activego\rows.go:84.2,84.14 1 0
+github.com\Chronokeeper\activego\rows.go:77.47,79.15 2 0
+github.com\Chronokeeper\activego\rows.go:82.3,82.17 1 0
+github.com\Chronokeeper\activego\rows.go:79.15,81.4 1 0
+github.com\Chronokeeper\activego\rows.go:88.31,90.2 1 0
+github.com\Chronokeeper\activego\rows.go:93.48,94.27 1 0
+github.com\Chronokeeper\activego\rows.go:98.2,98.90 1 0
+github.com\Chronokeeper\activego\rows.go:102.2,102.78 1 0
+github.com\Chronokeeper\activego\rows.go:94.27,96.3 1 0
+github.com\Chronokeeper\activego\rows.go:98.90,100.3 1 0
+github.com\Chronokeeper\activego\rows.go:120.33,121.30 1 0
+github.com\Chronokeeper\activego\rows.go:125.2,125.27 1 0
+github.com\Chronokeeper\activego\rows.go:144.2,144.23 1 0
+github.com\Chronokeeper\activego\rows.go:121.30,123.3 1 0
+github.com\Chronokeeper\activego\rows.go:125.27,126.23 1 0
+github.com\Chronokeeper\activego\rows.go:133.3,133.23 1 0
+github.com\Chronokeeper\activego\rows.go:126.23,128.29 2 0
+github.com\Chronokeeper\activego\rows.go:128.29,131.5 2 0
+github.com\Chronokeeper\activego\rows.go:133.23,135.4 1 0
+github.com\Chronokeeper\activego\rows.go:136.3,137.23 1 0
+github.com\Chronokeeper\activego\rows.go:140.3,140.23 1 0
+github.com\Chronokeeper\activego\rows.go:137.23,139.4 1 0
+github.com\Chronokeeper\activego\rows.go:140.23,142.4 1 0
+github.com\Chronokeeper\activego\sqlite3_driver.go:18.85,20.2 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:22.85,26.18 3 0
+github.com\Chronokeeper\activego\mymysql_driver.go:60.2,61.19 2 0
+github.com\Chronokeeper\activego\mymysql_driver.go:64.2,68.16 4 0
+github.com\Chronokeeper\activego\mymysql_driver.go:26.18,29.18 2 0
+github.com\Chronokeeper\activego\mymysql_driver.go:32.3,35.33 4 0
+github.com\Chronokeeper\activego\mymysql_driver.go:57.3,57.14 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:29.18,31.4 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:35.33,38.20 3 0
+github.com\Chronokeeper\activego\mymysql_driver.go:43.4,43.13 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:38.20,40.5 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:40.5,42.5 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:44.4,45.17 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:46.4,48.19 2 0
+github.com\Chronokeeper\activego\mymysql_driver.go:51.5,51.20 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:52.4,53.51 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:48.19,50.6 1 0
+github.com\Chronokeeper\activego\mymysql_driver.go:61.19,63.3 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:214.91,216.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:218.49,220.32 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:253.2,253.21 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:257.2,259.13 3 0
+github.com\Chronokeeper\activego\mssql_dialect.go:264.2,264.12 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:221.2,222.21 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:223.2,227.17 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:228.2,232.20 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:233.2,235.20 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:238.2,239.22 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:240.2,242.15 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:243.2,244.17 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:245.2,246.18 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:247.2,248.18 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:249.2,250.10 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:235.20,237.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:253.21,255.3 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:259.13,261.3 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:261.3,261.20 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:261.20,263.3 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:267.43,269.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:271.47,274.2 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:276.44,278.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:280.36,282.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:284.39,286.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:288.39,290.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:292.56,296.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:298.40,300.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:302.38,304.2 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:306.83,310.2 3 0
+github.com\Chronokeeper\activego\mssql_dialect.go:318.82,322.2 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:324.74,328.2 3 0
+github.com\Chronokeeper\activego\mssql_dialect.go:330.90,337.16 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:340.2,344.18 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:386.2,386.26 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:337.16,339.3 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:344.18,348.17 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:352.3,358.13 6 0
+github.com\Chronokeeper\activego\mssql_dialect.go:374.3,374.51 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:383.3,384.36 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:348.17,350.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:359.3,360.53 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:361.3,362.51 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:363.3,364.52 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:365.3,366.38 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:366.38,368.5 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:368.5,371.5 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:374.51,375.25 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:375.25,377.5 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:377.5,378.27 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:378.27,380.6 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:389.53,394.16 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:397.2,400.18 3 0
+github.com\Chronokeeper\activego\mssql_dialect.go:410.2,410.20 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:394.16,396.3 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:400.18,404.17 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:407.3,408.33 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:404.17,406.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:413.79,428.16 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:431.2,434.18 3 0
+github.com\Chronokeeper\activego\mssql_dialect.go:470.2,470.21 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:428.16,430.3 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:434.18,439.17 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:443.3,444.17 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:448.3,448.8 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:454.3,456.103 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:460.3,462.42 3 0
+github.com\Chronokeeper\activego\mssql_dialect.go:468.3,468.27 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:439.17,441.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:444.17,446.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:448.8,450.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:450.4,452.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:456.103,458.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:462.42,467.4 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:473.99,475.21 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:479.2,485.45 4 0
+github.com\Chronokeeper\activego\mssql_dialect.go:496.2,496.21 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:502.2,504.12 3 0
+github.com\Chronokeeper\activego\mssql_dialect.go:475.21,477.3 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:485.45,487.43 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:492.3,493.14 2 0
+github.com\Chronokeeper\activego\mssql_dialect.go:487.43,489.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:489.4,491.4 1 0
+github.com\Chronokeeper\activego\mssql_dialect.go:496.21,500.3 3 0
+github.com\Chronokeeper\activego\mssql_dialect.go:507.42,509.2 1 0

+ 1470 - 0
engine.go

@@ -0,0 +1,1470 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"bufio"
+	"bytes"
+	"database/sql"
+	"encoding/gob"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+// Engine is the major struct of xorm, it means a database manager.
+// Commonly, an application only need one engine
+type Engine struct {
+	db      *core.DB
+	dialect core.Dialect
+
+	ColumnMapper  core.IMapper
+	TableMapper   core.IMapper
+	TagIdentifier string
+	Tables        map[reflect.Type]*core.Table
+	SqlMap  SqlMap
+	mutex  *sync.RWMutex
+	Cacher core.Cacher
+
+	ShowSQL bool
+
+	// !nashtsai! TODO ought to deprecate these but having logger to control its log level
+	ShowInfo  bool
+	ShowErr   bool
+	ShowDebug bool
+	ShowWarn  bool
+	// --227
+
+	Logger     core.ILogger
+	TZLocation *time.Location
+
+	disableGlobalCache bool
+}
+
+func (engine *Engine) SetLogger(logger core.ILogger) {
+	engine.Logger = logger
+	engine.dialect.SetLogger(logger)
+}
+
+func (engine *Engine) SetDisableGlobalCache(disable bool) {
+	if engine.disableGlobalCache != disable {
+		engine.disableGlobalCache = disable
+	}
+}
+
+func (engine *Engine) DriverName() string {
+	return engine.dialect.DriverName()
+}
+
+func (engine *Engine) DataSourceName() string {
+	return engine.dialect.DataSourceName()
+}
+
+func (engine *Engine) SetMapper(mapper core.IMapper) {
+	engine.SetTableMapper(mapper)
+	engine.SetColumnMapper(mapper)
+}
+
+func (engine *Engine) SetTableMapper(mapper core.IMapper) {
+	engine.TableMapper = mapper
+}
+
+func (engine *Engine) SetColumnMapper(mapper core.IMapper) {
+	engine.ColumnMapper = mapper
+}
+
+// If engine's database support batch insert records like
+// "insert into user values (name, age), (name, age)".
+// When the return is ture, then engine.Insert(&users) will
+// generate batch sql and exeute.
+func (engine *Engine) SupportInsertMany() bool {
+	return engine.dialect.SupportInsertMany()
+}
+
+// Engine's database use which charactor as quote.
+// mysql, sqlite use ` and postgres use "
+func (engine *Engine) QuoteStr() string {
+	return engine.dialect.QuoteStr()
+}
+
+// Use QuoteStr quote the string sql
+func (engine *Engine) Quote(sql string) string {
+	if len(sql) == 0 {
+		return sql
+	}
+	if string(sql[0]) == engine.dialect.QuoteStr() || sql[0] == '`' {
+		return sql
+	}
+	return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr()
+}
+
+// A simple wrapper to dialect's core.SqlType method
+func (engine *Engine) SqlType(c *core.Column) string {
+	return engine.dialect.SqlType(c)
+}
+
+// Database's autoincrement statement
+func (engine *Engine) AutoIncrStr() string {
+	return engine.dialect.AutoIncrStr()
+}
+
+// SetMaxOpenConns is only available for go 1.2+
+func (engine *Engine) SetMaxOpenConns(conns int) {
+	engine.db.SetMaxOpenConns(conns)
+}
+
+// @Deprecated
+func (engine *Engine) SetMaxConns(conns int) {
+	engine.SetMaxOpenConns(conns)
+}
+
+// SetMaxIdleConns
+func (engine *Engine) SetMaxIdleConns(conns int) {
+	engine.db.SetMaxIdleConns(conns)
+}
+
+// SetDefaltCacher set the default cacher. Xorm's default not enable cacher.
+func (engine *Engine) SetDefaultCacher(cacher core.Cacher) {
+	engine.Cacher = cacher
+}
+
+// If you has set default cacher, and you want temporilly stop use cache,
+// you can use NoCache()
+func (engine *Engine) NoCache() *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.NoCache()
+}
+
+func (engine *Engine) NoCascade() *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.NoCascade()
+}
+
+// Set a table use a special cacher
+func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) {
+	v := rValue(bean)
+	tb := engine.autoMapType(v)
+	tb.Cacher = cacher
+}
+
+// NewDB provides an interface to operate database directly
+func (engine *Engine) NewDB() (*core.DB, error) {
+	return core.OpenDialect(engine.dialect)
+}
+
+func (engine *Engine) DB() *core.DB {
+	return engine.db
+}
+
+func (engine *Engine) Dialect() core.Dialect {
+	return engine.dialect
+}
+
+// New a session
+func (engine *Engine) NewSession() *Session {
+	session := &Session{Engine: engine}
+	session.Init()
+	return session
+}
+
+// Close the engine
+func (engine *Engine) Close() error {
+	return engine.db.Close()
+}
+
+// Ping tests if database is alive
+func (engine *Engine) Ping() error {
+	session := engine.NewSession()
+	defer session.Close()
+	engine.LogInfo("PING DATABASE", engine.DriverName)
+	return session.Ping()
+}
+
+// logging sql
+func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
+	if engine.ShowSQL {
+		engine.overrideLogLevel(core.LOG_INFO)
+		if len(sqlArgs) > 0 {
+			engine.Logger.Infof("[sql] %v [args] %v", sqlStr, sqlArgs)
+		} else {
+			engine.Logger.Infof("[sql] %v", sqlStr)
+		}
+	}
+}
+
+func (engine *Engine) LogSQLQueryTime(sqlStr string, args interface{}, executionBlock func() (*core.Stmt, *core.Rows, error)) (*core.Stmt, *core.Rows, error) {
+	if engine.ShowDebug {
+		b4ExecTime := time.Now()
+		stmt, res, err := executionBlock()
+		execDuration := time.Since(b4ExecTime)
+		engine.LogDebugf("[time] %s - args %v - query took: %vns", sqlStr, args, execDuration.Nanoseconds())
+		return stmt, res, err
+	} else {
+		return executionBlock()
+	}
+}
+
+func (engine *Engine) LogSQLExecutionTime(sqlStr string, args interface{}, executionBlock func() (sql.Result, error)) (sql.Result, error) {
+	if engine.ShowDebug {
+		b4ExecTime := time.Now()
+		res, err := executionBlock()
+		execDuration := time.Since(b4ExecTime)
+		engine.LogDebugf("[time] %s - args %v - execution took: %vns", sqlStr, args, execDuration.Nanoseconds())
+		return res, err
+	} else {
+		return executionBlock()
+	}
+}
+
+// logging error
+func (engine *Engine) overrideLogLevel(overrideLevel core.LogLevel) {
+	logLevel := engine.Logger.Level()
+	if logLevel == core.LOG_UNKNOWN {
+		// intend to left empty
+	} else if logLevel < overrideLevel { // TODO can remove if deprecated engine.ShowErr
+		engine.Logger.SetLevel(core.LOG_ERR) // try override logger's log level
+	}
+
+}
+
+func (engine *Engine) LogError(contents ...interface{}) {
+	if engine.ShowErr {
+		engine.overrideLogLevel(core.LOG_ERR)
+		engine.Logger.Err(contents...)
+	}
+}
+
+func (engine *Engine) LogErrorf(format string, contents ...interface{}) {
+	if engine.ShowErr {
+		engine.overrideLogLevel(core.LOG_ERR)
+		engine.Logger.Errf(format, contents...)
+	}
+}
+
+// logging info
+func (engine *Engine) LogInfo(contents ...interface{}) {
+	if engine.ShowInfo {
+		engine.overrideLogLevel(core.LOG_INFO)
+		engine.Logger.Info(contents...)
+	}
+}
+
+func (engine *Engine) LogInfof(format string, contents ...interface{}) {
+	if engine.ShowErr {
+		engine.overrideLogLevel(core.LOG_INFO)
+		engine.Logger.Infof(format, contents...)
+	}
+}
+
+// logging debug
+func (engine *Engine) LogDebug(contents ...interface{}) {
+	if engine.ShowDebug {
+		engine.overrideLogLevel(core.LOG_DEBUG)
+		engine.Logger.Debug(contents...)
+	}
+}
+
+func (engine *Engine) LogDebugf(format string, contents ...interface{}) {
+	if engine.ShowDebug {
+		engine.overrideLogLevel(core.LOG_DEBUG)
+		engine.Logger.Debugf(format, contents...)
+	}
+}
+
+// logging warn
+func (engine *Engine) LogWarn(contents ...interface{}) {
+	if engine.ShowWarn {
+		engine.overrideLogLevel(core.LOG_WARNING)
+		engine.Logger.Warning(contents...)
+	}
+}
+
+func (engine *Engine) LogWarnf(format string, contents ...interface{}) {
+	if engine.ShowWarn {
+		engine.overrideLogLevel(core.LOG_WARNING)
+		engine.Logger.Warningf(format, contents...)
+	}
+}
+
+// Sql method let's you manualy write raw sql and operate
+// For example:
+//
+//         engine.Sql("select * from user").Find(&users)
+//
+// This    code will execute "select * from user" and set the records to users
+//
+func (engine *Engine) Sql(querystring string, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Sql(querystring, args...)
+}
+
+// Default if your struct has "created" or "updated" filed tag, the fields
+// will automatically be filled with current time when Insert or Update
+// invoked. Call NoAutoTime if you dont' want to fill automatically.
+func (engine *Engine) NoAutoTime() *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.NoAutoTime()
+}
+
+// Retrieve all tables, columns, indexes' informations from database.
+func (engine *Engine) DBMetas() ([]*core.Table, error) {
+	tables, err := engine.dialect.GetTables()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, table := range tables {
+		colSeq, cols, err := engine.dialect.GetColumns(table.Name)
+		if err != nil {
+			return nil, err
+		}
+		for _, name := range colSeq {
+			table.AddColumn(cols[name])
+		}
+		//table.Columns = cols
+		//table.ColumnsSeq = colSeq
+		indexes, err := engine.dialect.GetIndexes(table.Name)
+		if err != nil {
+			return nil, err
+		}
+		table.Indexes = indexes
+
+		for _, index := range indexes {
+			for _, name := range index.Cols {
+				if col := table.GetColumn(name); col != nil {
+					col.Indexes[index.Name] = true
+				} else {
+					return nil, fmt.Errorf("Unknown col "+name+" in indexes %v of table", index, table.ColumnsSeq())
+				}
+			}
+		}
+	}
+	return tables, nil
+}
+
+/*
+dump database all table structs and data to a file
+*/
+func (engine *Engine) DumpAllToFile(fp string) error {
+	f, err := os.Create(fp)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return engine.DumpAll(f)
+}
+
+/*
+dump database all table structs and data to w
+*/
+func (engine *Engine) DumpAll(w io.Writer) error {
+	tables, err := engine.DBMetas()
+	if err != nil {
+		return err
+	}
+
+	for _, table := range tables {
+		_, err = io.WriteString(w, engine.dialect.CreateTableSql(table, "", table.StoreEngine, "")+"\n\n")
+		if err != nil {
+			return err
+		}
+		for _, index := range table.Indexes {
+			_, err = io.WriteString(w, engine.dialect.CreateIndexSql(table.Name, index)+"\n\n")
+			if err != nil {
+				return err
+			}
+		}
+
+		rows, err := engine.DB().Query("SELECT * FROM " + engine.Quote(table.Name))
+		if err != nil {
+			return err
+		}
+
+		cols, err := rows.Columns()
+		if err != nil {
+			return err
+		}
+		if len(cols) == 0 {
+			continue
+		}
+		for rows.Next() {
+			dest := make([]interface{}, len(cols))
+			err = rows.ScanSlice(&dest)
+			if err != nil {
+				return err
+			}
+
+			_, err = io.WriteString(w, "INSERT INTO "+engine.Quote(table.Name)+" ("+engine.Quote(strings.Join(cols, engine.Quote(", ")))+") VALUES (")
+			if err != nil {
+				return err
+			}
+
+			var temp string
+			for i, d := range dest {
+				col := table.GetColumn(cols[i])
+				if d == nil {
+					temp += ", NULL"
+				} else if col.SQLType.IsText() || col.SQLType.IsTime() {
+					var v = fmt.Sprintf("%s", d)
+					temp += ", '" + strings.Replace(v, "'", "''", -1) + "'"
+				} else if col.SQLType.IsBlob() {
+					if reflect.TypeOf(d).Kind() == reflect.Slice {
+						temp += fmt.Sprintf(", %s", engine.dialect.FormatBytes(d.([]byte)))
+					} else if reflect.TypeOf(d).Kind() == reflect.String {
+						temp += fmt.Sprintf(", '%s'", d.(string))
+					}
+				} else if col.SQLType.IsNumeric() {
+					switch reflect.TypeOf(d).Kind() {
+					case reflect.Slice:
+						temp += fmt.Sprintf(", %s", string(d.([]byte)))
+					default:
+						temp += fmt.Sprintf(", %v", d)
+					}
+				} else {
+					s := fmt.Sprintf("%v", d)
+					if strings.Contains(s, ":") || strings.Contains(s, "-") {
+						temp += fmt.Sprintf(", '%s'", s)
+					} else {
+						temp += fmt.Sprintf(", %s", s)
+					}
+				}
+			}
+			_, err = io.WriteString(w, temp[2:]+");\n\n")
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// use cascade or not
+func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Cascade(trueOrFalse...)
+}
+
+// Where method provide a condition query
+func (engine *Engine) Where(querystring string, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Where(querystring, args...)
+}
+
+// Id mehtod provoide a condition as (id) = ?
+func (engine *Engine) Id(id interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Id(id)
+}
+
+// Apply before Processor, affected bean is passed to closure arg
+func (engine *Engine) Before(closures func(interface{})) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Before(closures)
+}
+
+// Apply after insert Processor, affected bean is passed to closure arg
+func (engine *Engine) After(closures func(interface{})) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.After(closures)
+}
+
+// set charset when create table, only support mysql now
+func (engine *Engine) Charset(charset string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Charset(charset)
+}
+
+// set store engine when create table, only support mysql now
+func (engine *Engine) StoreEngine(storeEngine string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.StoreEngine(storeEngine)
+}
+
+// use for distinct columns. Caution: when you are using cache,
+// distinct will not be cached because cache system need id,
+// but distinct will not provide id
+func (engine *Engine) Distinct(columns ...string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Distinct(columns...)
+}
+
+// only use the paramters as select or update columns
+func (engine *Engine) Cols(columns ...string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Cols(columns...)
+}
+
+func (engine *Engine) AllCols() *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.AllCols()
+}
+
+func (engine *Engine) MustCols(columns ...string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.MustCols(columns...)
+}
+
+// Xorm automatically retrieve condition according struct, but
+// if struct has bool field, it will ignore them. So use UseBool
+// to tell system to do not ignore them.
+// If no paramters, it will use all the bool field of struct, or
+// it will use paramters's columns
+func (engine *Engine) UseBool(columns ...string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.UseBool(columns...)
+}
+
+// Only not use the paramters as select or update columns
+func (engine *Engine) Omit(columns ...string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Omit(columns...)
+}
+
+// This method will generate "column IN (?, ?)"
+func (engine *Engine) In(column string, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.In(column, args...)
+}
+
+// Method Inc provides a update string like "column = column + ?"
+func (engine *Engine) Incr(column string, arg ...interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Incr(column, arg...)
+}
+
+// Method Decr provides a update string like "column = column - ?"
+func (engine *Engine) Decr(column string, arg ...interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Decr(column, arg...)
+}
+
+// Method SetExpr provides a update string like "column = {expression}"
+func (engine *Engine) SetExpr(column string, expression string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.SetExpr(column, expression)
+}
+
+// Temporarily change the Get, Find, Update's table
+func (engine *Engine) Table(tableNameOrBean interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Table(tableNameOrBean)
+}
+
+// set the table alias
+func (engine *Engine) Alias(alias string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Alias(alias)
+}
+
+// This method will generate "LIMIT start, limit"
+func (engine *Engine) Limit(limit int, start ...int) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Limit(limit, start...)
+}
+
+// Method Desc will generate "ORDER BY column1 DESC, column2 DESC"
+// This will
+func (engine *Engine) Desc(colNames ...string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Desc(colNames...)
+}
+
+// Method Asc will generate "ORDER BY column1,column2 Asc"
+// This method can chainable use.
+//
+//        engine.Desc("name").Asc("age").Find(&users)
+//        // SELECT * FROM user ORDER BY name DESC, age ASC
+//
+func (engine *Engine) Asc(colNames ...string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Asc(colNames...)
+}
+
+// Method OrderBy will generate "ORDER BY order"
+func (engine *Engine) OrderBy(order string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.OrderBy(order)
+}
+
+// The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
+func (engine *Engine) Join(join_operator string, tablename interface{}, condition string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Join(join_operator, tablename, condition)
+}
+
+// Generate Group By statement
+func (engine *Engine) GroupBy(keys string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.GroupBy(keys)
+}
+
+// Generate Having statement
+func (engine *Engine) Having(conditions string) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Having(conditions)
+}
+
+func (engine *Engine) autoMapType(v reflect.Value) *core.Table {
+	t := v.Type()
+	engine.mutex.Lock()
+	table, ok := engine.Tables[t]
+	if !ok {
+		table = engine.mapType(v)
+		engine.Tables[t] = table
+		if v.CanAddr() {
+			engine.GobRegister(v.Addr().Interface())
+		} else {
+			engine.GobRegister(v.Interface())
+		}
+	}
+	engine.mutex.Unlock()
+	return table
+}
+
+func (engine *Engine) GobRegister(v interface{}) *Engine {
+	//fmt.Printf("Type: %[1]T => Data: %[1]#v\n", v)
+	gob.Register(v)
+	return engine
+}
+
+func (engine *Engine) TableInfo(bean interface{}) *core.Table {
+	v := rValue(bean)
+	return engine.autoMapType(v)
+}
+
+func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
+	if index, ok := table.Indexes[indexName]; ok {
+		index.AddColumn(col.Name)
+		col.Indexes[index.Name] = true
+	} else {
+		index := core.NewIndex(indexName, indexType)
+		index.AddColumn(col.Name)
+		table.AddIndex(index)
+		col.Indexes[index.Name] = true
+	}
+}
+
+func (engine *Engine) newTable() *core.Table {
+	table := core.NewEmptyTable()
+
+	if !engine.disableGlobalCache {
+		table.Cacher = engine.Cacher
+	}
+	return table
+}
+
+func (engine *Engine) mapType(v reflect.Value) *core.Table {
+	t := v.Type()
+	table := engine.newTable()
+	method := v.MethodByName("TableName")
+	if !method.IsValid() {
+		if v.CanAddr() {
+			method = v.Addr().MethodByName("TableName")
+		}
+	}
+	if method.IsValid() {
+		params := []reflect.Value{}
+		results := method.Call(params)
+		if len(results) == 1 {
+			table.Name = results[0].Interface().(string)
+		}
+	}
+
+	if table.Name == "" {
+		table.Name = engine.TableMapper.Obj2Table(t.Name())
+	}
+	table.Type = t
+
+	var idFieldColName string
+	var err error
+
+	hasCacheTag := false
+	hasNoCacheTag := false
+
+	for i := 0; i < t.NumField(); i++ {
+		tag := t.Field(i).Tag
+
+		ormTagStr := tag.Get(engine.TagIdentifier)
+		var col *core.Column
+		fieldValue := v.Field(i)
+		fieldType := fieldValue.Type()
+
+		if ormTagStr != "" {
+			col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
+				IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]bool)}
+			tags := strings.Split(ormTagStr, " ")
+
+			if len(tags) > 0 {
+				if tags[0] == "-" {
+					continue
+				}
+				if strings.ToUpper(tags[0]) == "EXTENDS" {
+					if fieldValue.Kind() == reflect.Struct {
+						parentTable := engine.mapType(fieldValue)
+						for _, col := range parentTable.Columns() {
+							col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName)
+							table.AddColumn(col)
+						}
+
+						continue
+					} else if fieldValue.Kind() == reflect.Ptr {
+						f := fieldValue.Type().Elem()
+						if f.Kind() == reflect.Struct {
+							fieldValue = fieldValue.Elem()
+							if !fieldValue.IsValid() || fieldValue.IsNil() {
+								fieldValue = reflect.New(f).Elem()
+							}
+						}
+
+						parentTable := engine.mapType(fieldValue)
+						for _, col := range parentTable.Columns() {
+							col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName)
+							table.AddColumn(col)
+						}
+
+						continue
+					}
+					//TODO: warning
+				}
+
+				indexNames := make(map[string]int)
+				var isIndex, isUnique bool
+				var preKey string
+				for j, key := range tags {
+					k := strings.ToUpper(key)
+					switch {
+					case k == "<-":
+						col.MapType = core.ONLYFROMDB
+					case k == "->":
+						col.MapType = core.ONLYTODB
+					case k == "PK":
+						col.IsPrimaryKey = true
+						col.Nullable = false
+					case k == "NULL":
+						if j == 0 {
+							col.Nullable = true
+						} else {
+							col.Nullable = (strings.ToUpper(tags[j-1]) != "NOT")
+						}
+					// TODO: for postgres how add autoincr?
+					/*case strings.HasPrefix(k, "AUTOINCR(") && strings.HasSuffix(k, ")"):
+					col.IsAutoIncrement = true
+
+					autoStart := k[len("AUTOINCR")+1 : len(k)-1]
+					autoStartInt, err := strconv.Atoi(autoStart)
+					if err != nil {
+						engine.LogError(err)
+					}
+					col.AutoIncrStart = autoStartInt*/
+					case k == "AUTOINCR":
+						col.IsAutoIncrement = true
+						//col.AutoIncrStart = 1
+					case k == "DEFAULT":
+						col.Default = tags[j+1]
+					case k == "CREATED":
+						col.IsCreated = true
+					case k == "VERSION":
+						col.IsVersion = true
+						col.Default = "1"
+					case k == "UPDATED":
+						col.IsUpdated = true
+					case k == "DELETED":
+						col.IsDeleted = true
+					case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"):
+						indexName := k[len("INDEX")+1 : len(k)-1]
+						indexNames[indexName] = core.IndexType
+					case k == "INDEX":
+						isIndex = true
+					case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"):
+						indexName := k[len("UNIQUE")+1 : len(k)-1]
+						indexNames[indexName] = core.UniqueType
+					case k == "UNIQUE":
+						isUnique = true
+					case k == "NOTNULL":
+						col.Nullable = false
+					case k == "CACHE":
+						if !hasCacheTag {
+							hasCacheTag = true
+						}
+					case k == "NOCACHE":
+						if !hasNoCacheTag {
+							hasNoCacheTag = true
+						}
+					case k == "NOT":
+					default:
+						if strings.HasPrefix(k, "'") && strings.HasSuffix(k, "'") {
+							if preKey != "DEFAULT" {
+								col.Name = key[1 : len(key)-1]
+							}
+						} else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") {
+							fs := strings.Split(k, "(")
+
+							if _, ok := core.SqlTypes[fs[0]]; !ok {
+								preKey = k
+								continue
+							}
+							col.SQLType = core.SQLType{fs[0], 0, 0}
+							if fs[0] == core.Enum && fs[1][0] == '\'' { //enum
+								options := strings.Split(fs[1][0:len(fs[1])-1], ",")
+								col.EnumOptions = make(map[string]int)
+								for k, v := range options {
+									v = strings.TrimSpace(v)
+									v = strings.Trim(v, "'")
+									col.EnumOptions[v] = k
+								}
+							} else if fs[0] == core.Set && fs[1][0] == '\'' { //set
+								options := strings.Split(fs[1][0:len(fs[1])-1], ",")
+								col.SetOptions = make(map[string]int)
+								for k, v := range options {
+									v = strings.TrimSpace(v)
+									v = strings.Trim(v, "'")
+									col.SetOptions[v] = k
+								}
+							} else {
+								fs2 := strings.Split(fs[1][0:len(fs[1])-1], ",")
+								if len(fs2) == 2 {
+									col.Length, err = strconv.Atoi(fs2[0])
+									if err != nil {
+										engine.LogError(err)
+									}
+									col.Length2, err = strconv.Atoi(fs2[1])
+									if err != nil {
+										engine.LogError(err)
+									}
+								} else if len(fs2) == 1 {
+									col.Length, err = strconv.Atoi(fs2[0])
+									if err != nil {
+										engine.LogError(err)
+									}
+								}
+							}
+						} else {
+							if _, ok := core.SqlTypes[k]; ok {
+								col.SQLType = core.SQLType{k, 0, 0}
+							} else if key != col.Default {
+								col.Name = key
+							}
+						}
+						engine.dialect.SqlType(col)
+					}
+					preKey = k
+				}
+				if col.SQLType.Name == "" {
+					col.SQLType = core.Type2SQLType(fieldType)
+				}
+				if col.Length == 0 {
+					col.Length = col.SQLType.DefaultLength
+				}
+				if col.Length2 == 0 {
+					col.Length2 = col.SQLType.DefaultLength2
+				}
+
+				if col.Name == "" {
+					col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name)
+				}
+
+				if isUnique {
+					indexNames[col.Name] = core.UniqueType
+				} else if isIndex {
+					indexNames[col.Name] = core.IndexType
+				}
+
+				for indexName, indexType := range indexNames {
+					addIndex(indexName, table, col, indexType)
+				}
+			}
+		} else {
+			var sqlType core.SQLType
+			if fieldValue.CanAddr() {
+				if _, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+					sqlType = core.SQLType{core.Text, 0, 0}
+				}
+			}
+			if _, ok := fieldValue.Interface().(core.Conversion); ok {
+				sqlType = core.SQLType{core.Text, 0, 0}
+			} else {
+				sqlType = core.Type2SQLType(fieldType)
+			}
+			col = core.NewColumn(engine.ColumnMapper.Obj2Table(t.Field(i).Name),
+				t.Field(i).Name, sqlType, sqlType.DefaultLength,
+				sqlType.DefaultLength2, true)
+		}
+		if col.IsAutoIncrement {
+			col.Nullable = false
+		}
+
+		table.AddColumn(col)
+
+		if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) {
+			idFieldColName = col.Name
+		}
+	} // end for
+
+	if idFieldColName != "" && len(table.PrimaryKeys) == 0 {
+		col := table.GetColumn(idFieldColName)
+		col.IsPrimaryKey = true
+		col.IsAutoIncrement = true
+		col.Nullable = false
+		table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
+		table.AutoIncrement = col.Name
+	}
+
+	if hasCacheTag {
+		if engine.Cacher != nil { // !nash! use engine's cacher if provided
+			engine.Logger.Info("enable cache on table:", table.Name)
+			table.Cacher = engine.Cacher
+		} else {
+			engine.Logger.Info("enable LRU cache on table:", table.Name)
+			table.Cacher = NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) // !nashtsai! HACK use LRU cacher for now
+		}
+	}
+	if hasNoCacheTag {
+		engine.Logger.Info("no cache on table:", table.Name)
+		table.Cacher = nil
+	}
+
+	return table
+}
+
+// Map a struct to a table
+func (engine *Engine) mapping(beans ...interface{}) (e error) {
+	engine.mutex.Lock()
+	defer engine.mutex.Unlock()
+	for _, bean := range beans {
+		v := rValue(bean)
+		engine.Tables[v.Type()] = engine.mapType(v)
+	}
+	return
+}
+
+// If a table has any reocrd
+func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.IsTableEmpty(bean)
+}
+
+// If a table is exist
+func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.IsTableExist(beanOrTableName)
+}
+
+func (engine *Engine) IdOf(bean interface{}) core.PK {
+	return engine.IdOfV(reflect.ValueOf(bean))
+}
+
+func (engine *Engine) IdOfV(rv reflect.Value) core.PK {
+	v := reflect.Indirect(rv)
+	table := engine.autoMapType(v)
+	pk := make([]interface{}, len(table.PrimaryKeys))
+	for i, col := range table.PKColumns() {
+		pkField := v.FieldByName(col.FieldName)
+		switch pkField.Kind() {
+		case reflect.String:
+			pk[i] = pkField.String()
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			pk[i] = pkField.Int()
+		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+			pk[i] = pkField.Uint()
+		}
+	}
+	return core.PK(pk)
+}
+
+// create indexes
+func (engine *Engine) CreateIndexes(bean interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.CreateIndexes(bean)
+}
+
+// create uniques
+func (engine *Engine) CreateUniques(bean interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.CreateUniques(bean)
+}
+
+func (engine *Engine) getCacher2(table *core.Table) core.Cacher {
+	return table.Cacher
+}
+
+func (engine *Engine) getCacher(v reflect.Value) core.Cacher {
+	if table := engine.autoMapType(v); table != nil {
+		return table.Cacher
+	}
+	return engine.Cacher
+}
+
+// If enabled cache, clear the cache bean
+func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
+	t := rType(bean)
+	if t.Kind() != reflect.Struct {
+		return errors.New("error params")
+	}
+	table := engine.TableInfo(bean)
+	cacher := table.Cacher
+	if cacher == nil {
+		cacher = engine.Cacher
+	}
+	if cacher != nil {
+		cacher.ClearIds(table.Name)
+		cacher.DelBean(table.Name, id)
+	}
+	return nil
+}
+
+// If enabled cache, clear some tables' cache
+func (engine *Engine) ClearCache(beans ...interface{}) error {
+	for _, bean := range beans {
+		t := rType(bean)
+		if t.Kind() != reflect.Struct {
+			return errors.New("error params")
+		}
+		table := engine.TableInfo(bean)
+		cacher := table.Cacher
+		if cacher == nil {
+			cacher = engine.Cacher
+		}
+		if cacher != nil {
+			cacher.ClearIds(table.Name)
+			cacher.ClearBeans(table.Name)
+		}
+	}
+	return nil
+}
+
+// Sync the new struct changes to database, this method will automatically add
+// table, column, index, unique. but will not delete or change anything.
+// If you change some field, you should change the database manually.
+func (engine *Engine) Sync(beans ...interface{}) error {
+	for _, bean := range beans {
+		table := engine.TableInfo(bean)
+
+		s := engine.NewSession()
+		defer s.Close()
+		isExist, err := s.Table(bean).isTableExist(table.Name)
+		if err != nil {
+			return err
+		}
+		if !isExist {
+			err = engine.CreateTables(bean)
+			if err != nil {
+				return err
+			}
+		}
+		/*isEmpty, err := engine.IsEmptyTable(bean)
+		  if err != nil {
+		      return err
+		  }*/
+		var isEmpty bool = false
+		if isEmpty {
+			err = engine.DropTables(bean)
+			if err != nil {
+				return err
+			}
+			err = engine.CreateTables(bean)
+			if err != nil {
+				return err
+			}
+		} else {
+			for _, col := range table.Columns() {
+				session := engine.NewSession()
+				session.Statement.RefTable = table
+				defer session.Close()
+				isExist, err := session.Engine.dialect.IsColumnExist(table.Name, col.Name)
+				if err != nil {
+					return err
+				}
+				if !isExist {
+					session := engine.NewSession()
+					session.Statement.RefTable = table
+					defer session.Close()
+					err = session.addColumn(col.Name)
+					if err != nil {
+						return err
+					}
+				}
+			}
+
+			for name, index := range table.Indexes {
+				session := engine.NewSession()
+				session.Statement.RefTable = table
+				defer session.Close()
+				if index.Type == core.UniqueType {
+					//isExist, err := session.isIndexExist(table.Name, name, true)
+					isExist, err := session.isIndexExist2(table.Name, index.Cols, true)
+					if err != nil {
+						return err
+					}
+					if !isExist {
+						session := engine.NewSession()
+						session.Statement.RefTable = table
+						defer session.Close()
+						err = session.addUnique(table.Name, name)
+						if err != nil {
+							return err
+						}
+					}
+				} else if index.Type == core.IndexType {
+					isExist, err := session.isIndexExist2(table.Name, index.Cols, false)
+					if err != nil {
+						return err
+					}
+					if !isExist {
+						session := engine.NewSession()
+						session.Statement.RefTable = table
+						defer session.Close()
+						err = session.addIndex(table.Name, name)
+						if err != nil {
+							return err
+						}
+					}
+				} else {
+					return errors.New("unknow index type")
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func (engine *Engine) Sync2(beans ...interface{}) error {
+	s := engine.NewSession()
+	defer s.Close()
+	return s.Sync2(beans...)
+}
+
+func (engine *Engine) unMap(beans ...interface{}) (e error) {
+	engine.mutex.Lock()
+	defer engine.mutex.Unlock()
+	for _, bean := range beans {
+		t := rType(bean)
+		if _, ok := engine.Tables[t]; ok {
+			delete(engine.Tables, t)
+		}
+	}
+	return
+}
+
+// Drop all mapped table
+func (engine *Engine) dropAll() error {
+	session := engine.NewSession()
+	defer session.Close()
+
+	err := session.Begin()
+	if err != nil {
+		return err
+	}
+	err = session.dropAll()
+	if err != nil {
+		session.Rollback()
+		return err
+	}
+	return session.Commit()
+}
+
+// CreateTables create tabls according bean
+func (engine *Engine) CreateTables(beans ...interface{}) error {
+	session := engine.NewSession()
+	err := session.Begin()
+	defer session.Close()
+	if err != nil {
+		return err
+	}
+
+	for _, bean := range beans {
+		err = session.CreateTable(bean)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	}
+	return session.Commit()
+}
+
+func (engine *Engine) DropTables(beans ...interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+
+	err := session.Begin()
+	if err != nil {
+		return err
+	}
+
+	for _, bean := range beans {
+		err = session.DropTable(bean)
+		if err != nil {
+			session.Rollback()
+			return err
+		}
+	}
+	return session.Commit()
+}
+
+func (engine *Engine) createAll() error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.createAll()
+}
+
+// Exec raw sql
+func (engine *Engine) Exec(sql string, args ...interface{}) (sql.Result, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Exec(sql, args...)
+}
+
+// Exec a raw sql and return records as []map[string][]byte
+func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Query(sql, paramStr...)
+}
+
+// Exec a raw sql and return records as []map[string][]byte
+func (engine *Engine) Query2(sql string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Query2(sql, paramStr...)
+}
+
+//func XMLString(v interface{}, IndentXML bool) (string, error) {
+//	var result []byte
+//	var err error
+//	if IndentXML {
+//		result, err = xml.MarshalIndent(v, "", "  ")
+//	} else {
+//		result, err = xml.Marshal(v)
+//	}
+//	if err != nil {
+//		return "", err
+//	}
+
+//	return string(result), nil
+//}
+
+// Insert one or more records
+func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Insert(beans...)
+}
+
+// Insert only one record
+func (engine *Engine) InsertOne(bean interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.InsertOne(bean)
+}
+
+// Update records, bean's non-empty fields are updated contents,
+// condiBean' non-empty filds are conditions
+// CAUTION:
+//        1.bool will defaultly be updated content nor conditions
+//         You should call UseBool if you have bool to use.
+//        2.float32 & float64 may be not inexact as conditions
+func (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Update(bean, condiBeans...)
+}
+
+// Delete records, bean's non-empty fields are conditions
+func (engine *Engine) Delete(bean interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Delete(bean)
+}
+
+// Get retrieve one record from table, bean's non-empty fields
+// are conditions
+func (engine *Engine) Get(bean interface{}) (bool, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Get(bean)
+}
+
+// Find retrieve records from table, condiBeans's non-empty fields
+// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
+// map[int64]*Struct
+func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Find(beans, condiBeans...)
+}
+
+// Iterate record by record handle records from table, bean's non-empty fields
+// are conditions.
+func (engine *Engine) Iterate(bean interface{}, fun IterFunc) error {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Iterate(bean, fun)
+}
+
+// Return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields
+// are conditions.
+func (engine *Engine) Rows(bean interface{}) (*Rows, error) {
+	session := engine.NewSession()
+	return session.Rows(bean)
+}
+
+// Count counts the records. bean's non-empty fields
+// are conditions.
+func (engine *Engine) Count(bean interface{}) (int64, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.Count(bean)
+}
+
+// Import SQL DDL file
+func (engine *Engine) ImportFile(ddlPath string) ([]sql.Result, error) {
+	file, err := os.Open(ddlPath)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+	return engine.Import(file)
+}
+
+// Import SQL DDL file
+func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
+	var results []sql.Result
+	var lastError error
+	scanner := bufio.NewScanner(r)
+
+	semiColSpliter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+		if atEOF && len(data) == 0 {
+			return 0, nil, nil
+		}
+		if i := bytes.IndexByte(data, ';'); i >= 0 {
+			return i + 1, data[0:i], nil
+		}
+		// If we're at EOF, we have a final, non-terminated line. Return it.
+		if atEOF {
+			return len(data), data, nil
+		}
+		// Request more data.
+		return 0, nil, nil
+	}
+
+	scanner.Split(semiColSpliter)
+
+	for scanner.Scan() {
+		query := scanner.Text()
+		query = strings.Trim(query, " \t")
+		if len(query) > 0 {
+			result, err := engine.DB().Exec(query)
+			results = append(results, result)
+			if err != nil {
+				lastError = err
+			}
+		}
+	}
+	return results, lastError
+}
+
+var (
+	NULL_TIME time.Time
+)
+
+func (engine *Engine) TZTime(t time.Time) time.Time {
+
+	if NULL_TIME != t { // if time is not initialized it's not suitable for Time.In()
+		return t.In(engine.TZLocation)
+	}
+	return t
+}
+
+func (engine *Engine) NowTime(sqlTypeName string) interface{} {
+	t := time.Now()
+	return engine.FormatTime(sqlTypeName, t)
+}
+
+func (engine *Engine) NowTime2(sqlTypeName string) (interface{}, time.Time) {
+	t := time.Now()
+	return engine.FormatTime(sqlTypeName, t), t
+}
+
+func (engine *Engine) FormatTime(sqlTypeName string, t time.Time) (v interface{}) {
+	if engine.dialect.DBType() == core.ORACLE {
+		return t
+	}
+	switch sqlTypeName {
+	case core.Time:
+		s := engine.TZTime(t).Format("2006-01-02 15:04:05") //time.RFC3339
+		v = s[11:19]
+	case core.Date:
+		v = engine.TZTime(t).Format("2006-01-02")
+	case core.DateTime, core.TimeStamp:
+		if engine.dialect.DBType() == "ql" {
+			v = engine.TZTime(t)
+		} else if engine.dialect.DBType() == "sqlite3" {
+			v = engine.TZTime(t).UTC().Format("2006-01-02 15:04:05")
+		} else {
+			v = engine.TZTime(t).Format("2006-01-02 15:04:05")
+		}
+	case core.TimeStampz:
+		if engine.dialect.DBType() == core.MSSQL {
+			v = engine.TZTime(t).Format("2006-01-02T15:04:05.9999999Z07:00")
+		} else if engine.DriverName() == "mssql" {
+			v = engine.TZTime(t)
+		} else {
+			v = engine.TZTime(t).Format(time.RFC3339Nano)
+		}
+	case core.BigInt, core.Int:
+		v = engine.TZTime(t).Unix()
+	default:
+		v = engine.TZTime(t)
+	}
+	return
+}
+
+// Always disable struct tag "deleted"
+func (engine *Engine) Unscoped() *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Unscoped()
+}

+ 166 - 0
engineplus.go

@@ -0,0 +1,166 @@
+package xorm
+
+import (
+	"encoding/json"
+
+	"github.com/Chronokeeper/anyxml"
+)
+
+func (engine *Engine) SqlMapClient(sqlTagName string, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	return session.Sql(engine.SqlMap.Sql[sqlTagName], args...)
+}
+
+func (engine *Engine) SqlTemplateClient(sqlTagName string, args ...interface{}) *Session {
+	session := engine.NewSession()
+	session.IsAutoClose = true
+	map1:=args[0].(map[string]interface{})
+	if engine.SqlMap.SqlTemplate[sqlTagName]==nil{
+		return session.Sql("", &map1)
+	}
+	sql, err := engine.SqlMap.SqlTemplate[sqlTagName].Execute(map1)
+	if err != nil {
+		engine.Logger.Err(err)
+	}
+
+	return session.Sql(sql, &map1)
+}
+
+// Get retrieve one record from table, bean's non-empty fields
+// are conditions
+func (engine *Engine) GetFirst(bean interface{}) ResultBean {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.GetFirst(bean)
+}
+
+// Exec a raw sql and return records as []map[string]interface{}
+func (engine *Engine) QueryAll(sql string, paramStr ...interface{}) (resultsSlice []map[string]interface{}, err error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.QueryAll(sql, paramStr...)
+}
+
+// Exec a raw sql and return records as []map[string]interface{}
+func (engine *Engine) QueryAllByMap(sql string, paramMap interface{}) (resultsSlice []map[string]interface{}, err error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.QueryAllByMap(sql, paramMap)
+}
+
+func (engine *Engine) QueryAllByMapToJsonString(sql string, paramMap interface{}) (string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	results, err := session.QueryAllByMap(sql, paramMap)
+	if err != nil {
+		return "", err
+	}
+	return JSONString(results, true)
+}
+
+func (engine *Engine) QueryAllByMapToJsonStringWithDateFormat(dateFormat string, sql string, paramMap interface{}) (string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	results, err := session.QueryAllByMapWithDateFormat(dateFormat, sql, paramMap)
+	if err != nil {
+		return "", err
+	}
+	return JSONString(results, true)
+}
+
+func (engine *Engine) QueryAllToJsonString(sql string, paramStr ...interface{}) (string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	results, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	return JSONString(results, true)
+}
+
+func (engine *Engine) QueryAllToJsonStringWithDateFormat(dateFormat string, sql string, paramStr ...interface{}) (string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	results, err := session.QueryAllWithDateFormat(dateFormat, sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	return JSONString(results, true)
+}
+
+func (engine *Engine) QueryAllToXmlString(sql string, paramStr ...interface{}) (string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	resultSlice, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+
+	results, err := anyxml.Xml(resultSlice, "result")
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func (engine *Engine) QueryAllToXmlIndentString(sql string, prefix string, indent string, paramStr ...interface{}) (string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	resultSlice, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	results, err := anyxml.XmlIndent(resultSlice, prefix, indent, "result")
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func (engine *Engine) QueryAllToXmlStringWithDateFormat(dateFormat string, sql string, paramStr ...interface{}) (string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	resultSlice, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	results, err := anyxml.XmlWithDateFormat(dateFormat, resultSlice)
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func (engine *Engine) QueryAllToXmlIndentStringWithDateFormat(dateFormat string, sql string, prefix string, indent string, paramStr ...interface{}) (string, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	resultSlice, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	results, err := anyxml.XmlIndentWithDateFormat(dateFormat, resultSlice, "", "  ", "results")
+
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func JSONString(v interface{}, IndentJSON bool) (string, error) {
+	var result []byte
+	var err error
+	if IndentJSON {
+		result, err = json.MarshalIndent(v, "", "  ")
+	} else {
+		result, err = json.Marshal(v)
+	}
+	if err != nil {
+		return "", err
+	}
+
+	if string(result)=="null"{
+		return "", nil
+	}
+	return string(result), nil
+}

+ 19 - 0
error.go

@@ -0,0 +1,19 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+)
+
+var (
+	ErrParamsType      error = errors.New("Params type error")
+	ErrTableNotFound   error = errors.New("Not found table")
+	ErrUnSupportedType error = errors.New("Unsupported type error")
+	ErrNotExist        error = errors.New("Not exist error")
+	ErrCacheFailed     error = errors.New("Cache failed")
+	ErrNeedDeletedCond error = errors.New("Delete need at least one condition")
+	ErrNotImplemented  error = errors.New("Not implemented.")
+)

+ 42 - 0
goracle_driver.go

@@ -0,0 +1,42 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"regexp"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	core.RegisterDriver("goracle", &goracleDriver{})
+// }
+
+type goracleDriver struct {
+}
+
+func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.ORACLE}
+	dsnPattern := regexp.MustCompile(
+		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
+			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
+			`\/(?P<dbname>.*?)` + // /dbname
+			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
+	matches := dsnPattern.FindStringSubmatch(dataSourceName)
+	//tlsConfigRegister := make(map[string]*tls.Config)
+	names := dsnPattern.SubexpNames()
+
+	for i, match := range matches {
+		switch names[i] {
+		case "dbname":
+			db.DbName = match
+		}
+	}
+	if db.DbName == "" {
+		return nil, errors.New("dbname is empty")
+	}
+	return db, nil
+}

+ 385 - 0
helpers.go

@@ -0,0 +1,385 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"fmt"
+	"reflect"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+func isZero(k interface{}) bool {
+	switch k.(type) {
+	case int:
+		return k.(int) == 0
+	case int8:
+		return k.(int8) == 0
+	case int16:
+		return k.(int16) == 0
+	case int32:
+		return k.(int32) == 0
+	case int64:
+		return k.(int64) == 0
+	case uint:
+		return k.(uint) == 0
+	case uint8:
+		return k.(uint8) == 0
+	case uint16:
+		return k.(uint16) == 0
+	case uint32:
+		return k.(uint32) == 0
+	case uint64:
+		return k.(uint64) == 0
+	case string:
+		return k.(string) == ""
+	}
+	return false
+}
+
+func isPKZero(pk core.PK) bool {
+	for _, k := range pk {
+		if isZero(k) {
+			return true
+		}
+	}
+	return false
+}
+
+func indexNoCase(s, sep string) int {
+	return strings.Index(strings.ToLower(s), strings.ToLower(sep))
+}
+
+func splitNoCase(s, sep string) []string {
+	idx := indexNoCase(s, sep)
+	if idx < 0 {
+		return []string{s}
+	}
+	return strings.Split(s, s[idx:idx+len(sep)])
+}
+
+func splitNNoCase(s, sep string, n int) []string {
+	idx := indexNoCase(s, sep)
+	if idx < 0 {
+		return []string{s}
+	}
+	return strings.SplitN(s, s[idx:idx+len(sep)], n)
+}
+
+func makeArray(elem string, count int) []string {
+	res := make([]string, count)
+	for i := 0; i < count; i++ {
+		res[i] = elem
+	}
+	return res
+}
+
+func rValue(bean interface{}) reflect.Value {
+	return reflect.Indirect(reflect.ValueOf(bean))
+}
+
+func rType(bean interface{}) reflect.Type {
+	sliceValue := reflect.Indirect(reflect.ValueOf(bean))
+	//return reflect.TypeOf(sliceValue.Interface())
+	return sliceValue.Type()
+}
+
+func structName(v reflect.Type) string {
+	for v.Kind() == reflect.Ptr {
+		v = v.Elem()
+	}
+	return v.Name()
+}
+
+func sliceEq(left, right []string) bool {
+	if len(left) != len(right) {
+		return false
+	}
+	sort.Sort(sort.StringSlice(left))
+	sort.Sort(sort.StringSlice(right))
+	for i := 0; i < len(left); i++ {
+		if left[i] != right[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func reflect2value(rawValue *reflect.Value) (str string, err error) {
+	aa := reflect.TypeOf((*rawValue).Interface())
+	vv := reflect.ValueOf((*rawValue).Interface())
+	switch aa.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		str = strconv.FormatInt(vv.Int(), 10)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		str = strconv.FormatUint(vv.Uint(), 10)
+	case reflect.Float32, reflect.Float64:
+		str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
+	case reflect.String:
+		str = vv.String()
+	case reflect.Array, reflect.Slice:
+		switch aa.Elem().Kind() {
+		case reflect.Uint8:
+			data := rawValue.Interface().([]byte)
+			str = string(data)
+		default:
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	//时间类型
+	case reflect.Struct:
+		if aa == core.TimeType {
+			str = rawValue.Interface().(time.Time).Format(time.RFC3339Nano)
+		} else {
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	case reflect.Bool:
+		str = strconv.FormatBool(vv.Bool())
+	case reflect.Complex128, reflect.Complex64:
+		str = fmt.Sprintf("%v", vv.Complex())
+	/* TODO: unsupported types below
+	   case reflect.Map:
+	   case reflect.Ptr:
+	   case reflect.Uintptr:
+	   case reflect.UnsafePointer:
+	   case reflect.Chan, reflect.Func, reflect.Interface:
+	*/
+	default:
+		err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+	}
+	return
+}
+
+func value2Bytes(rawValue *reflect.Value) (data []byte, err error) {
+	var str string
+	str, err = reflect2value(rawValue)
+	if err != nil {
+		return
+	}
+	data = []byte(str)
+	return
+}
+
+func value2String(rawValue *reflect.Value) (data string, err error) {
+	data, err = reflect2value(rawValue)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := row2mapStr(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := row2map(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
+	result := make(map[string][]byte)
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+		//if row is null then ignore
+		if rawValue.Interface() == nil {
+			//fmt.Println("ignore ...", key, rawValue)
+			continue
+		}
+
+		if data, err := value2Bytes(&rawValue); err == nil {
+			result[key] = data
+		} else {
+			return nil, err // !nashtsai! REVIEW, should return err or just error log?
+		}
+	}
+	return result, nil
+}
+
+func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
+	result := make(map[string]string)
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+		//if row is null then ignore
+		if rawValue.Interface() == nil {
+			//fmt.Println("ignore ...", key, rawValue)
+			continue
+		}
+
+		if data, err := value2String(&rawValue); err == nil {
+			result[key] = data
+		} else {
+			return nil, err // !nashtsai! REVIEW, should return err or just error log?
+		}
+	}
+	return result, nil
+}
+
+func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) {
+	rows, err := tx.Query(sqlStr, params...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2Strings(rows)
+}
+
+func query2(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []map[string]string, err error) {
+	s, err := db.Prepare(sqlStr)
+	if err != nil {
+		return nil, err
+	}
+	defer s.Close()
+	rows, err := s.Query(params...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	return rows2Strings(rows)
+}
+
+func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
+	v, err := col.ValueOf(bean)
+	if err != nil {
+		return
+	}
+	if v.CanSet() {
+		switch v.Type().Kind() {
+		case reflect.Struct:
+			v.Set(reflect.ValueOf(t).Convert(v.Type()))
+		case reflect.Int, reflect.Int64, reflect.Int32:
+			v.SetInt(t.Unix())
+		case reflect.Uint, reflect.Uint64, reflect.Uint32:
+			v.SetUint(uint64(t.Unix()))
+		}
+	}
+}
+
+func genCols(table *core.Table, session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
+	colNames := make([]string, 0)
+	args := make([]interface{}, 0)
+
+	for _, col := range table.Columns() {
+		lColName := strings.ToLower(col.Name)
+		if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
+			if _, ok := session.Statement.columnMap[lColName]; !ok {
+				continue
+			}
+		}
+		if col.MapType == core.ONLYFROMDB {
+			continue
+		}
+
+		fieldValuePtr, err := col.ValueOf(bean)
+		if err != nil {
+			session.Engine.LogError(err)
+			continue
+		}
+		fieldValue := *fieldValuePtr
+
+		if col.IsAutoIncrement {
+			switch fieldValue.Type().Kind() {
+			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
+				if fieldValue.Int() == 0 {
+					continue
+				}
+			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
+				if fieldValue.Uint() == 0 {
+					continue
+				}
+			case reflect.String:
+				if len(fieldValue.String()) == 0 {
+					continue
+				}
+			}
+		}
+
+		if col.IsDeleted {
+			continue
+		}
+
+		if session.Statement.ColumnStr != "" {
+			if _, ok := session.Statement.columnMap[lColName]; !ok {
+				continue
+			}
+		}
+		if session.Statement.OmitStr != "" {
+			if _, ok := session.Statement.columnMap[lColName]; ok {
+				continue
+			}
+		}
+
+		if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
+			val, t := session.Engine.NowTime2(col.SQLType.Name)
+			args = append(args, val)
+
+			var colName = col.Name
+			session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+				col := table.GetColumn(colName)
+				setColumnTime(bean, col, t)
+			})
+		} else if col.IsVersion && session.Statement.checkVersion {
+			args = append(args, 1)
+		} else {
+			arg, err := session.value2Interface(col, fieldValue)
+			if err != nil {
+				return colNames, args, err
+			}
+			args = append(args, arg)
+		}
+
+		if includeQuote {
+			colNames = append(colNames, session.Engine.Quote(col.Name)+" = ?")
+		} else {
+			colNames = append(colNames, col.Name)
+		}
+	}
+	return colNames, args, nil
+}

+ 279 - 0
helpersplus.go

@@ -0,0 +1,279 @@
+package xorm
+
+import (
+	"fmt"
+	"reflect"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+func reflect2objectWithDateFormat(rawValue *reflect.Value, dateFormat string) (value interface{}, err error) {
+	aa := reflect.TypeOf((*rawValue).Interface())
+	vv := reflect.ValueOf((*rawValue).Interface())
+	switch aa.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		value = vv.Int()
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		value = vv.Uint()
+	case reflect.Float32, reflect.Float64:
+		value = vv.Float()
+	case reflect.String:
+		value = vv.String()
+	case reflect.Array, reflect.Slice:
+		switch aa.Elem().Kind() {
+		case reflect.Uint8:
+			data := rawValue.Interface().([]byte)
+			value = string(data)
+		default:
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	//时间类型
+	case reflect.Struct:
+		if aa == core.TimeType {
+			//			loc, _ := time.LoadLocation("Local")                            //重要:获取时区
+			//			value, _ = time.ParseInLocation(dateFormat, rawValue.Interface().(time.Time).Format(dateFormat), loc)
+			value = rawValue.Interface().(time.Time).Format(dateFormat)
+		} else {
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	case reflect.Bool:
+		value = vv.Bool()
+	case reflect.Complex128, reflect.Complex64:
+		value = vv.Complex()
+	/* TODO: unsupported types below
+	   case reflect.Map:
+	   case reflect.Ptr:
+	   case reflect.Uintptr:
+	   case reflect.UnsafePointer:
+	   case reflect.Chan, reflect.Func, reflect.Interface:
+	*/
+	default:
+		err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+	}
+	return
+}
+
+func value2ObjectWithDateFormat(rawValue *reflect.Value, dateFormat string) (data interface{}, err error) {
+	data, err = reflect2objectWithDateFormat(rawValue, dateFormat)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func rows2mapObjectsWithDateFormat(rows *core.Rows, dateFormat string) (resultsSlice []map[string]interface{}, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := rows2mapObjectWithDateFormat(rows, dateFormat, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+func rows2mapObjectWithDateFormat(rows *core.Rows, dateFormat string, fields []string) (resultsMap map[string]interface{}, err error) {
+	result := make(map[string]interface{})
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+		//if row is null then ignore
+		if rawValue.Interface() == nil {
+			continue
+		}
+
+		if data, err := value2ObjectWithDateFormat(&rawValue, dateFormat); err == nil {
+			result[key] = data
+		} else {
+			return nil, err // !nashtsai! REVIEW, should return err or just error log?
+		}
+
+	}
+	return result, nil
+}
+
+func txQueryByMap(tx *core.Tx, sqlStr string, params interface{}) (resultsSlice []map[string]interface{}, err error) {
+	rows, err := tx.QueryMap(sqlStr, params)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2mapObjects(rows)
+}
+
+func txQuery3WithDateFormat(tx *core.Tx, dateFormat string, sqlStr string, params ...interface{}) (resultsSlice []map[string]interface{}, err error) {
+	rows, err := tx.Query(sqlStr, params...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2mapObjectsWithDateFormat(rows, dateFormat)
+}
+
+func queryByMap(db *core.DB, sqlStr string, params interface{}) (resultsSlice []map[string]interface{}, err error) {
+	s, err := db.Prepare(sqlStr)
+	if err != nil {
+		return nil, err
+	}
+	defer s.Close()
+
+	rows, err := s.QueryMap(params)
+
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	return rows2mapObjects(rows)
+}
+
+func query3WithDateFormat(db *core.DB, dateFormat string, sqlStr string, params ...interface{}) (resultsSlice []map[string]interface{}, err error) {
+	s, err := db.Prepare(sqlStr)
+	if err != nil {
+		return nil, err
+	}
+	defer s.Close()
+	rows, err := s.Query(params...)
+
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	return rows2mapObjectsWithDateFormat(rows, dateFormat)
+}
+
+func reflect2object(rawValue *reflect.Value) (value interface{}, err error) {
+	aa := reflect.TypeOf((*rawValue).Interface())
+	vv := reflect.ValueOf((*rawValue).Interface())
+	switch aa.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		value = vv.Int()
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		value = vv.Uint()
+	case reflect.Float32, reflect.Float64:
+		value = vv.Float()
+	case reflect.String:
+		value = vv.String()
+	case reflect.Array, reflect.Slice:
+		switch aa.Elem().Kind() {
+		case reflect.Uint8:
+			data := rawValue.Interface().([]byte)
+			value = string(data)
+		default:
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	//时间类型
+	case reflect.Struct:
+		if aa == core.TimeType {
+			value = rawValue.Interface().(time.Time)
+		} else {
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	case reflect.Bool:
+		value = vv.Bool()
+	case reflect.Complex128, reflect.Complex64:
+		value = vv.Complex()
+	/* TODO: unsupported types below
+	   case reflect.Map:
+	   case reflect.Ptr:
+	   case reflect.Uintptr:
+	   case reflect.UnsafePointer:
+	   case reflect.Chan, reflect.Func, reflect.Interface:
+	*/
+	default:
+		err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+	}
+	return
+}
+
+func value2Object(rawValue *reflect.Value) (data interface{}, err error) {
+	data, err = reflect2object(rawValue)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func rows2mapObjects(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := rows2mapObject(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+func rows2mapObject(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
+	result := make(map[string]interface{})
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+		//if row is null then ignore
+		if rawValue.Interface() == nil {
+			continue
+		}
+
+		if data, err := value2Object(&rawValue); err == nil {
+			result[key] = data
+		} else {
+			return nil, err // !nashtsai! REVIEW, should return err or just error log?
+		}
+
+	}
+	return result, nil
+}
+
+//xiaolipeng
+func txQuery3(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string]interface{}, err error) {
+	rows, err := tx.Query(sqlStr, params...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	return rows2mapObjects(rows)
+}
+
+//xiaolipeng
+func query3(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []map[string]interface{}, err error) {
+	s, err := db.Prepare(sqlStr)
+	if err != nil {
+		return nil, err
+	}
+	defer s.Close()
+	rows, err := s.Query(params...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	return rows2mapObjects(rows)
+}

+ 110 - 0
logger.go

@@ -0,0 +1,110 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"fmt"
+	"io"
+	"log"
+
+	"github.com/xormplus/core"
+)
+
+const (
+	DEFAULT_LOG_PREFIX = "[xorm]"
+	DEFAULT_LOG_FLAG   = log.Ldate | log.Lmicroseconds
+	DEFAULT_LOG_LEVEL  = core.LOG_DEBUG
+)
+
+type SimpleLogger struct {
+	DEBUG *log.Logger
+	ERR   *log.Logger
+	INFO  *log.Logger
+	WARN  *log.Logger
+	level core.LogLevel
+}
+
+func NewSimpleLogger(out io.Writer) *SimpleLogger {
+	return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
+}
+
+func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger {
+	return NewSimpleLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL)
+}
+
+func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *SimpleLogger {
+	return &SimpleLogger{
+		DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), flag),
+		ERR:   log.New(out, fmt.Sprintf("%s [error] ", prefix), flag),
+		INFO:  log.New(out, fmt.Sprintf("%s [info]  ", prefix), flag),
+		WARN:  log.New(out, fmt.Sprintf("%s [warn]  ", prefix), flag),
+		level: l,
+	}
+}
+
+func (s *SimpleLogger) Err(v ...interface{}) (err error) {
+	if s.level > core.LOG_OFF && s.level <= core.LOG_ERR {
+		s.ERR.Println(v...)
+	}
+	return
+}
+
+func (s *SimpleLogger) Errf(format string, v ...interface{}) (err error) {
+	if s.level > core.LOG_OFF && s.level <= core.LOG_ERR {
+		s.ERR.Printf(format, v...)
+	}
+	return
+}
+
+func (s *SimpleLogger) Debug(v ...interface{}) (err error) {
+	if s.level > core.LOG_OFF && s.level <= core.LOG_DEBUG {
+		s.DEBUG.Println(v...)
+	}
+	return
+}
+
+func (s *SimpleLogger) Debugf(format string, v ...interface{}) (err error) {
+	if s.level > core.LOG_OFF && s.level >= core.LOG_DEBUG {
+		s.DEBUG.Printf(format, v...)
+	}
+	return
+}
+
+func (s *SimpleLogger) Info(v ...interface{}) (err error) {
+	if s.level > core.LOG_OFF && s.level >= core.LOG_INFO {
+		s.INFO.Println(v...)
+	}
+	return
+}
+
+func (s *SimpleLogger) Infof(format string, v ...interface{}) (err error) {
+	if s.level > core.LOG_OFF && s.level >= core.LOG_INFO {
+		s.INFO.Printf(format, v...)
+	}
+	return
+}
+
+func (s *SimpleLogger) Warning(v ...interface{}) (err error) {
+	if s.level > core.LOG_OFF && s.level >= core.LOG_WARNING {
+		s.WARN.Println(v...)
+	}
+	return
+}
+
+func (s *SimpleLogger) Warningf(format string, v ...interface{}) (err error) {
+	if s.level > core.LOG_OFF && s.level >= core.LOG_WARNING {
+		s.WARN.Printf(format, v...)
+	}
+	return
+}
+
+func (s *SimpleLogger) Level() core.LogLevel {
+	return s.level
+}
+
+func (s *SimpleLogger) SetLevel(l core.LogLevel) (err error) {
+	s.level = l
+	return
+}

+ 289 - 0
lru_cacher.go

@@ -0,0 +1,289 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"container/list"
+	"fmt"
+	"sync"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+type LRUCacher struct {
+	idList   *list.List
+	sqlList  *list.List
+	idIndex  map[string]map[string]*list.Element
+	sqlIndex map[string]map[string]*list.Element
+	store    core.CacheStore
+	mutex    sync.Mutex
+	// maxSize    int
+	MaxElementSize int
+	Expired        time.Duration
+	GcInterval     time.Duration
+}
+
+func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
+	return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
+}
+
+func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
+	cacher := &LRUCacher{store: store, idList: list.New(),
+		sqlList: list.New(), Expired: expired,
+		GcInterval: core.CacheGcInterval, MaxElementSize: maxElementSize,
+		sqlIndex: make(map[string]map[string]*list.Element),
+		idIndex:  make(map[string]map[string]*list.Element),
+	}
+	cacher.RunGC()
+	return cacher
+}
+
+//func NewLRUCacher3(store CacheStore, expired time.Duration, maxSize int) *LRUCacher {
+//    return newLRUCacher(store, expired, maxSize, 0)
+//}
+
+// RunGC run once every m.GcInterval
+func (m *LRUCacher) RunGC() {
+	time.AfterFunc(m.GcInterval, func() {
+		m.RunGC()
+		m.GC()
+	})
+}
+
+// GC check ids lit and sql list to remove all element expired
+func (m *LRUCacher) GC() {
+	//fmt.Println("begin gc ...")
+	//defer fmt.Println("end gc ...")
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	var removedNum int
+	for e := m.idList.Front(); e != nil; {
+		if removedNum <= core.CacheGcMaxRemoved &&
+			time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired {
+			removedNum++
+			next := e.Next()
+			//fmt.Println("removing ...", e.Value)
+			node := e.Value.(*idNode)
+			m.delBean(node.tbName, node.id)
+			e = next
+		} else {
+			//fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.idList.Len())
+			break
+		}
+	}
+
+	removedNum = 0
+	for e := m.sqlList.Front(); e != nil; {
+		if removedNum <= core.CacheGcMaxRemoved &&
+			time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired {
+			removedNum++
+			next := e.Next()
+			//fmt.Println("removing ...", e.Value)
+			node := e.Value.(*sqlNode)
+			m.delIds(node.tbName, node.sql)
+			e = next
+		} else {
+			//fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.sqlList.Len())
+			break
+		}
+	}
+}
+
+// Get all bean's ids according to sql and parameter from cache
+func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	if _, ok := m.sqlIndex[tableName]; !ok {
+		m.sqlIndex[tableName] = make(map[string]*list.Element)
+	}
+	if v, err := m.store.Get(sql); err == nil {
+		if el, ok := m.sqlIndex[tableName][sql]; !ok {
+			el = m.sqlList.PushBack(newSqlNode(tableName, sql))
+			m.sqlIndex[tableName][sql] = el
+		} else {
+			lastTime := el.Value.(*sqlNode).lastVisit
+			// if expired, remove the node and return nil
+			if time.Now().Sub(lastTime) > m.Expired {
+				m.delIds(tableName, sql)
+				return nil
+			}
+			m.sqlList.MoveToBack(el)
+			el.Value.(*sqlNode).lastVisit = time.Now()
+		}
+		return v
+	} else {
+		m.delIds(tableName, sql)
+	}
+
+	return nil
+}
+
+// Get bean according tableName and id from cache
+func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	if _, ok := m.idIndex[tableName]; !ok {
+		m.idIndex[tableName] = make(map[string]*list.Element)
+	}
+	tid := genId(tableName, id)
+	if v, err := m.store.Get(tid); err == nil {
+		if el, ok := m.idIndex[tableName][id]; ok {
+			lastTime := el.Value.(*idNode).lastVisit
+			// if expired, remove the node and return nil
+			if time.Now().Sub(lastTime) > m.Expired {
+				m.delBean(tableName, id)
+				//m.clearIds(tableName)
+				return nil
+			}
+			m.idList.MoveToBack(el)
+			el.Value.(*idNode).lastVisit = time.Now()
+		} else {
+			el = m.idList.PushBack(newIdNode(tableName, id))
+			m.idIndex[tableName][id] = el
+		}
+		return v
+	} else {
+		// store bean is not exist, then remove memory's index
+		m.delBean(tableName, id)
+		//m.clearIds(tableName)
+		return nil
+	}
+}
+
+// Clear all sql-ids mapping on table tableName from cache
+func (m *LRUCacher) clearIds(tableName string) {
+	if tis, ok := m.sqlIndex[tableName]; ok {
+		for sql, v := range tis {
+			m.sqlList.Remove(v)
+			m.store.Del(sql)
+		}
+	}
+	m.sqlIndex[tableName] = make(map[string]*list.Element)
+}
+
+func (m *LRUCacher) ClearIds(tableName string) {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	m.clearIds(tableName)
+}
+
+func (m *LRUCacher) clearBeans(tableName string) {
+	if tis, ok := m.idIndex[tableName]; ok {
+		for id, v := range tis {
+			m.idList.Remove(v)
+			tid := genId(tableName, id)
+			m.store.Del(tid)
+		}
+	}
+	m.idIndex[tableName] = make(map[string]*list.Element)
+}
+
+func (m *LRUCacher) ClearBeans(tableName string) {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	m.clearBeans(tableName)
+}
+
+func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	if _, ok := m.sqlIndex[tableName]; !ok {
+		m.sqlIndex[tableName] = make(map[string]*list.Element)
+	}
+	if el, ok := m.sqlIndex[tableName][sql]; !ok {
+		el = m.sqlList.PushBack(newSqlNode(tableName, sql))
+		m.sqlIndex[tableName][sql] = el
+	} else {
+		el.Value.(*sqlNode).lastVisit = time.Now()
+	}
+	m.store.Put(sql, ids)
+	if m.sqlList.Len() > m.MaxElementSize {
+		e := m.sqlList.Front()
+		node := e.Value.(*sqlNode)
+		m.delIds(node.tbName, node.sql)
+	}
+}
+
+func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	var el *list.Element
+	var ok bool
+
+	if el, ok = m.idIndex[tableName][id]; !ok {
+		el = m.idList.PushBack(newIdNode(tableName, id))
+		m.idIndex[tableName][id] = el
+	} else {
+		el.Value.(*idNode).lastVisit = time.Now()
+	}
+
+	m.store.Put(genId(tableName, id), obj)
+	if m.idList.Len() > m.MaxElementSize {
+		e := m.idList.Front()
+		node := e.Value.(*idNode)
+		m.delBean(node.tbName, node.id)
+	}
+}
+
+func (m *LRUCacher) delIds(tableName, sql string) {
+	if _, ok := m.sqlIndex[tableName]; ok {
+		if el, ok := m.sqlIndex[tableName][sql]; ok {
+			delete(m.sqlIndex[tableName], sql)
+			m.sqlList.Remove(el)
+		}
+	}
+	m.store.Del(sql)
+}
+
+func (m *LRUCacher) DelIds(tableName, sql string) {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	m.delIds(tableName, sql)
+}
+
+func (m *LRUCacher) delBean(tableName string, id string) {
+	tid := genId(tableName, id)
+	if el, ok := m.idIndex[tableName][id]; ok {
+		delete(m.idIndex[tableName], id)
+		m.idList.Remove(el)
+		m.clearIds(tableName)
+	}
+	m.store.Del(tid)
+}
+
+func (m *LRUCacher) DelBean(tableName string, id string) {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	m.delBean(tableName, id)
+}
+
+type idNode struct {
+	tbName    string
+	id        string
+	lastVisit time.Time
+}
+
+type sqlNode struct {
+	tbName    string
+	sql       string
+	lastVisit time.Time
+}
+
+func genSqlKey(sql string, args interface{}) string {
+	return fmt.Sprintf("%v-%v", sql, args)
+}
+
+func genId(prefix string, id string) string {
+	return fmt.Sprintf("%v-%v", prefix, id)
+}
+
+func newIdNode(tbName string, id string) *idNode {
+	return &idNode{tbName, id, time.Now()}
+}
+
+func newSqlNode(tbName, sql string) *sqlNode {
+	return &sqlNode{tbName, sql, time.Now()}
+}

+ 47 - 0
memroy_store.go

@@ -0,0 +1,47 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"sync"
+
+	"github.com/xormplus/core"
+)
+
+var _ core.CacheStore = NewMemoryStore()
+
+// memory store
+type MemoryStore struct {
+	store map[interface{}]interface{}
+	mutex sync.RWMutex
+}
+
+func NewMemoryStore() *MemoryStore {
+	return &MemoryStore{store: make(map[interface{}]interface{})}
+}
+
+func (s *MemoryStore) Put(key string, value interface{}) error {
+	s.mutex.Lock()
+	defer s.mutex.Unlock()
+	s.store[key] = value
+	return nil
+}
+
+func (s *MemoryStore) Get(key string) (interface{}, error) {
+	s.mutex.RLock()
+	defer s.mutex.RUnlock()
+	if v, ok := s.store[key]; ok {
+		return v, nil
+	}
+
+	return nil, ErrNotExist
+}
+
+func (s *MemoryStore) Del(key string) error {
+	s.mutex.Lock()
+	defer s.mutex.Unlock()
+	delete(s.store, key)
+	return nil
+}

+ 509 - 0
mssql_dialect.go

@@ -0,0 +1,509 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	RegisterDialect("mssql", &mssql{})
+// }
+
+var (
+	mssqlReservedWords = map[string]bool{
+		"ADD":                    true,
+		"EXTERNAL":               true,
+		"PROCEDURE":              true,
+		"ALL":                    true,
+		"FETCH":                  true,
+		"PUBLIC":                 true,
+		"ALTER":                  true,
+		"FILE":                   true,
+		"RAISERROR":              true,
+		"AND":                    true,
+		"FILLFACTOR":             true,
+		"READ":                   true,
+		"ANY":                    true,
+		"FOR":                    true,
+		"READTEXT":               true,
+		"AS":                     true,
+		"FOREIGN":                true,
+		"RECONFIGURE":            true,
+		"ASC":                    true,
+		"FREETEXT":               true,
+		"REFERENCES":             true,
+		"AUTHORIZATION":          true,
+		"FREETEXTTABLE":          true,
+		"REPLICATION":            true,
+		"BACKUP":                 true,
+		"FROM":                   true,
+		"RESTORE":                true,
+		"BEGIN":                  true,
+		"FULL":                   true,
+		"RESTRICT":               true,
+		"BETWEEN":                true,
+		"FUNCTION":               true,
+		"RETURN":                 true,
+		"BREAK":                  true,
+		"GOTO":                   true,
+		"REVERT":                 true,
+		"BROWSE":                 true,
+		"GRANT":                  true,
+		"REVOKE":                 true,
+		"BULK":                   true,
+		"GROUP":                  true,
+		"RIGHT":                  true,
+		"BY":                     true,
+		"HAVING":                 true,
+		"ROLLBACK":               true,
+		"CASCADE":                true,
+		"HOLDLOCK":               true,
+		"ROWCOUNT":               true,
+		"CASE":                   true,
+		"IDENTITY":               true,
+		"ROWGUIDCOL":             true,
+		"CHECK":                  true,
+		"IDENTITY_INSERT":        true,
+		"RULE":                   true,
+		"CHECKPOINT":             true,
+		"IDENTITYCOL":            true,
+		"SAVE":                   true,
+		"CLOSE":                  true,
+		"IF":                     true,
+		"SCHEMA":                 true,
+		"CLUSTERED":              true,
+		"IN":                     true,
+		"SECURITYAUDIT":          true,
+		"COALESCE":               true,
+		"INDEX":                  true,
+		"SELECT":                 true,
+		"COLLATE":                true,
+		"INNER":                  true,
+		"SEMANTICKEYPHRASETABLE": true,
+		"COLUMN":                 true,
+		"INSERT":                 true,
+		"SEMANTICSIMILARITYDETAILSTABLE": true,
+		"COMMIT":                  true,
+		"INTERSECT":               true,
+		"SEMANTICSIMILARITYTABLE": true,
+		"COMPUTE":                 true,
+		"INTO":                    true,
+		"SESSION_USER":            true,
+		"CONSTRAINT":              true,
+		"IS":                      true,
+		"SET":                     true,
+		"CONTAINS":                true,
+		"JOIN":                    true,
+		"SETUSER":                 true,
+		"CONTAINSTABLE":           true,
+		"KEY":                     true,
+		"SHUTDOWN":                true,
+		"CONTINUE":                true,
+		"KILL":                    true,
+		"SOME":                    true,
+		"CONVERT":                 true,
+		"LEFT":                    true,
+		"STATISTICS":              true,
+		"CREATE":                  true,
+		"LIKE":                    true,
+		"SYSTEM_USER":             true,
+		"CROSS":                   true,
+		"LINENO":                  true,
+		"TABLE":                   true,
+		"CURRENT":                 true,
+		"LOAD":                    true,
+		"TABLESAMPLE":             true,
+		"CURRENT_DATE":            true,
+		"MERGE":                   true,
+		"TEXTSIZE":                true,
+		"CURRENT_TIME":            true,
+		"NATIONAL":                true,
+		"THEN":                    true,
+		"CURRENT_TIMESTAMP":       true,
+		"NOCHECK":                 true,
+		"TO":                      true,
+		"CURRENT_USER":            true,
+		"NONCLUSTERED":            true,
+		"TOP":                     true,
+		"CURSOR":                  true,
+		"NOT":                     true,
+		"TRAN":                    true,
+		"DATABASE":                true,
+		"NULL":                    true,
+		"TRANSACTION":             true,
+		"DBCC":                    true,
+		"NULLIF":                  true,
+		"TRIGGER":                 true,
+		"DEALLOCATE":              true,
+		"OF":                      true,
+		"TRUNCATE":                true,
+		"DECLARE":                 true,
+		"OFF":                     true,
+		"TRY_CONVERT":             true,
+		"DEFAULT":                 true,
+		"OFFSETS":                 true,
+		"TSEQUAL":                 true,
+		"DELETE":                  true,
+		"ON":                      true,
+		"UNION":                   true,
+		"DENY":                    true,
+		"OPEN":                    true,
+		"UNIQUE":                  true,
+		"DESC":                    true,
+		"OPENDATASOURCE":          true,
+		"UNPIVOT":                 true,
+		"DISK":                    true,
+		"OPENQUERY":               true,
+		"UPDATE":                  true,
+		"DISTINCT":                true,
+		"OPENROWSET":              true,
+		"UPDATETEXT":              true,
+		"DISTRIBUTED":             true,
+		"OPENXML":                 true,
+		"USE":                     true,
+		"DOUBLE":                  true,
+		"OPTION":                  true,
+		"USER":                    true,
+		"DROP":                    true,
+		"OR":                      true,
+		"VALUES":                  true,
+		"DUMP":                    true,
+		"ORDER":                   true,
+		"VARYING":                 true,
+		"ELSE":                    true,
+		"OUTER":                   true,
+		"VIEW":                    true,
+		"END":                     true,
+		"OVER":                    true,
+		"WAITFOR":                 true,
+		"ERRLVL":                  true,
+		"PERCENT":                 true,
+		"WHEN":                    true,
+		"ESCAPE":                  true,
+		"PIVOT":                   true,
+		"WHERE":                   true,
+		"EXCEPT":                  true,
+		"PLAN":                    true,
+		"WHILE":                   true,
+		"EXEC":                    true,
+		"PRECISION":               true,
+		"WITH":                    true,
+		"EXECUTE":                 true,
+		"PRIMARY":                 true,
+		"WITHIN":                  true,
+		"EXISTS":                  true,
+		"PRINT":                   true,
+		"WRITETEXT":               true,
+		"EXIT":                    true,
+		"PROC":                    true,
+	}
+)
+
+type mssql struct {
+	core.Base
+}
+
+func (db *mssql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *mssql) SqlType(c *core.Column) string {
+	var res string
+	switch t := c.SQLType.Name; t {
+	case core.Bool:
+		res = core.TinyInt
+	case core.Serial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = core.Int
+	case core.BigSerial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = core.BigInt
+	case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob:
+		res = core.VarBinary
+		if c.Length == 0 {
+			c.Length = 50
+		}
+	case core.TimeStamp:
+		res = core.DateTime
+	case core.TimeStampz:
+		res = "DATETIMEOFFSET"
+		c.Length = 7
+	case core.MediumInt:
+		res = core.Int
+	case core.MediumText, core.TinyText, core.LongText, core.Json:
+		res = core.Text
+	case core.Double:
+		res = core.Real
+	default:
+		res = t
+	}
+
+	if res == core.Int {
+		return core.Int
+	}
+
+	var hasLen1 bool = (c.Length > 0)
+	var hasLen2 bool = (c.Length2 > 0)
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *mssql) SupportInsertMany() bool {
+	return true
+}
+
+func (db *mssql) IsReserved(name string) bool {
+	_, ok := mssqlReservedWords[name]
+	return ok
+}
+
+func (db *mssql) Quote(name string) string {
+	return "\"" + name + "\""
+}
+
+func (db *mssql) QuoteStr() string {
+	return "\""
+}
+
+func (db *mssql) SupportEngine() bool {
+	return false
+}
+
+func (db *mssql) AutoIncrStr() string {
+	return "IDENTITY"
+}
+
+func (db *mssql) DropTableSql(tableName string) string {
+	return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+
+		"object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+
+		"DROP TABLE \"%s\"", tableName, tableName)
+}
+
+func (db *mssql) SupportCharset() bool {
+	return false
+}
+
+func (db *mssql) IndexOnTable() bool {
+	return true
+}
+
+func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{idxName}
+	sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?"
+	return sql, args
+}
+
+/*func (db *mssql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{tableName, colName}
+	sql := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
+	return sql, args
+}*/
+
+func (db *mssql) IsColumnExist(tableName, colName string) (bool, error) {
+	query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
+
+	return db.HasRecords(query, tableName, colName)
+}
+
+func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{}
+	sql := "select * from sysobjects where id = object_id(N'" + tableName + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1"
+	return sql, args
+}
+
+func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{}
+	s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale
+from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
+where a.object_id=object_id('` + tableName + `')`
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+	for rows.Next() {
+		var name, ctype, precision, scale string
+		var maxLen int
+		err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		col := new(core.Column)
+		col.Indexes = make(map[string]bool)
+		col.Length = maxLen
+		col.Name = strings.Trim(name, "` ")
+
+		ct := strings.ToUpper(ctype)
+		switch ct {
+		case "DATETIMEOFFSET":
+			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
+		case "NVARCHAR":
+			col.SQLType = core.SQLType{core.NVarchar, 0, 0}
+		case "IMAGE":
+			col.SQLType = core.SQLType{core.VarBinary, 0, 0}
+		default:
+			if _, ok := core.SqlTypes[ct]; ok {
+				col.SQLType = core.SQLType{ct, 0, 0}
+			} else {
+				return nil, nil, errors.New(fmt.Sprintf("unknow colType %v for %v - %v",
+					ct, tableName, col.Name))
+			}
+		}
+
+		if col.SQLType.IsText() || col.SQLType.IsTime() {
+			if col.Default != "" {
+				col.Default = "'" + col.Default + "'"
+			} else {
+				if col.DefaultIsEmpty {
+					col.Default = "''"
+				}
+			}
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+	return colSeq, cols, nil
+}
+
+func (db *mssql) GetTables() ([]*core.Table, error) {
+	args := []interface{}{}
+	s := `select name from sysobjects where xtype ='U'`
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		var name string
+		err = rows.Scan(&name)
+		if err != nil {
+			return nil, err
+		}
+		table.Name = strings.Trim(name, "` ")
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{tableName}
+	s := `SELECT
+IXS.NAME                    AS  [INDEX_NAME],
+C.NAME                      AS  [COLUMN_NAME],
+IXS.is_unique AS [IS_UNIQUE]
+FROM SYS.INDEXES IXS
+INNER JOIN SYS.INDEX_COLUMNS   IXCS
+ON IXS.OBJECT_ID=IXCS.OBJECT_ID  AND IXS.INDEX_ID = IXCS.INDEX_ID
+INNER   JOIN SYS.COLUMNS C  ON IXS.OBJECT_ID=C.OBJECT_ID
+AND IXCS.COLUMN_ID=C.COLUMN_ID
+WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
+`
+
+	rows, err := db.DB().Query(s, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var indexType int
+		var indexName, colName, isUnique string
+
+		err = rows.Scan(&indexName, &colName, &isUnique)
+		if err != nil {
+			return nil, err
+		}
+
+		i, err := strconv.ParseBool(isUnique)
+		if err != nil {
+			return nil, err
+		}
+
+		if i {
+			indexType = core.UniqueType
+		} else {
+			indexType = core.IndexType
+		}
+
+		colName = strings.Trim(colName, "` ")
+
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			indexName = indexName[5+len(tableName) : len(indexName)]
+		}
+
+		var index *core.Index
+		var ok bool
+		if index, ok = indexes[indexName]; !ok {
+			index = new(core.Index)
+			index.Type = indexType
+			index.Name = indexName
+			indexes[indexName] = index
+		}
+		index.AddColumn(colName)
+	}
+	return indexes, nil
+}
+
+func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
+	var sql string
+	if tableName == "" {
+		tableName = table.Name
+	}
+
+	sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE "
+
+	sql += db.QuoteStr() + tableName + db.QuoteStr() + " ("
+
+	pkList := table.PrimaryKeys
+
+	for _, colName := range table.ColumnsSeq() {
+		col := table.GetColumn(colName)
+		if col.IsPrimaryKey && len(pkList) == 1 {
+			sql += col.String(db)
+		} else {
+			sql += col.StringNoPk(db)
+		}
+		sql = strings.TrimSpace(sql)
+		sql += ", "
+	}
+
+	if len(pkList) > 1 {
+		sql += "PRIMARY KEY ( "
+		sql += strings.Join(pkList, ",")
+		sql += " ), "
+	}
+
+	sql = sql[:len(sql)-2] + ")"
+	sql += ";"
+	return sql
+}
+
+func (db *mssql) Filters() []core.Filter {
+	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
+}

+ 69 - 0
mymysql_driver.go

@@ -0,0 +1,69 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"strings"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	core.RegisterDriver("mymysql", &mymysqlDriver{})
+// }
+
+type mymysqlDriver struct {
+}
+
+func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.MYSQL}
+
+	pd := strings.SplitN(dataSourceName, "*", 2)
+	if len(pd) == 2 {
+		// Parse protocol part of URI
+		p := strings.SplitN(pd[0], ":", 2)
+		if len(p) != 2 {
+			return nil, errors.New("Wrong protocol part of URI")
+		}
+		db.Proto = p[0]
+		options := strings.Split(p[1], ",")
+		db.Raddr = options[0]
+		for _, o := range options[1:] {
+			kv := strings.SplitN(o, "=", 2)
+			var k, v string
+			if len(kv) == 2 {
+				k, v = kv[0], kv[1]
+			} else {
+				k, v = o, "true"
+			}
+			switch k {
+			case "laddr":
+				db.Laddr = v
+			case "timeout":
+				to, err := time.ParseDuration(v)
+				if err != nil {
+					return nil, err
+				}
+				db.Timeout = to
+			default:
+				return nil, errors.New("Unknown option: " + k)
+			}
+		}
+		// Remove protocol part
+		pd = pd[1:]
+	}
+	// Parse database part of URI
+	dup := strings.SplitN(pd[0], "/", 3)
+	if len(dup) != 3 {
+		return nil, errors.New("Wrong database part of URI")
+	}
+	db.DbName = dup[0]
+	db.User = dup[1]
+	db.Passwd = dup[2]
+
+	return db, nil
+}

+ 500 - 0
mysql_dialect.go

@@ -0,0 +1,500 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	RegisterDialect("mysql", &mysql{})
+// }
+
+var (
+	mysqlReservedWords = map[string]bool{
+		"ADD":               true,
+		"ALL":               true,
+		"ALTER":             true,
+		"ANALYZE":           true,
+		"AND":               true,
+		"AS":                true,
+		"ASC":               true,
+		"ASENSITIVE":        true,
+		"BEFORE":            true,
+		"BETWEEN":           true,
+		"BIGINT":            true,
+		"BINARY":            true,
+		"BLOB":              true,
+		"BOTH":              true,
+		"BY":                true,
+		"CALL":              true,
+		"CASCADE":           true,
+		"CASE":              true,
+		"CHANGE":            true,
+		"CHAR":              true,
+		"CHARACTER":         true,
+		"CHECK":             true,
+		"COLLATE":           true,
+		"COLUMN":            true,
+		"CONDITION":         true,
+		"CONNECTION":        true,
+		"CONSTRAINT":        true,
+		"CONTINUE":          true,
+		"CONVERT":           true,
+		"CREATE":            true,
+		"CROSS":             true,
+		"CURRENT_DATE":      true,
+		"CURRENT_TIME":      true,
+		"CURRENT_TIMESTAMP": true,
+		"CURRENT_USER":      true,
+		"CURSOR":            true,
+		"DATABASE":          true,
+		"DATABASES":         true,
+		"DAY_HOUR":          true,
+		"DAY_MICROSECOND":   true,
+		"DAY_MINUTE":        true,
+		"DAY_SECOND":        true,
+		"DEC":               true,
+		"DECIMAL":           true,
+		"DECLARE":           true,
+		"DEFAULT":           true,
+		"DELAYED":           true,
+		"DELETE":            true,
+		"DESC":              true,
+		"DESCRIBE":          true,
+		"DETERMINISTIC":     true,
+		"DISTINCT":          true,
+		"DISTINCTROW":       true,
+		"DIV":               true,
+		"DOUBLE":            true,
+		"DROP":              true,
+		"DUAL":              true,
+		"EACH":              true,
+		"ELSE":              true,
+		"ELSEIF":            true,
+		"ENCLOSED":          true,
+		"ESCAPED":           true,
+		"EXISTS":            true,
+		"EXIT":              true,
+		"EXPLAIN":           true,
+		"FALSE":             true,
+		"FETCH":             true,
+		"FLOAT":             true,
+		"FLOAT4":            true,
+		"FLOAT8":            true,
+		"FOR":               true,
+		"FORCE":             true,
+		"FOREIGN":           true,
+		"FROM":              true,
+		"FULLTEXT":          true,
+		"GOTO":              true,
+		"GRANT":             true,
+		"GROUP":             true,
+		"HAVING":            true,
+		"HIGH_PRIORITY":     true,
+		"HOUR_MICROSECOND":  true,
+		"HOUR_MINUTE":       true,
+		"HOUR_SECOND":       true,
+		"IF":                true,
+		"IGNORE":            true,
+		"IN":                true, "INDEX": true,
+		"INFILE": true, "INNER": true, "INOUT": true,
+		"INSENSITIVE": true, "INSERT": true, "INT": true,
+		"INT1": true, "INT2": true, "INT3": true,
+		"INT4": true, "INT8": true, "INTEGER": true,
+		"INTERVAL": true, "INTO": true, "IS": true,
+		"ITERATE": true, "JOIN": true, "KEY": true,
+		"KEYS": true, "KILL": true, "LABEL": true,
+		"LEADING": true, "LEAVE": true, "LEFT": true,
+		"LIKE": true, "LIMIT": true, "LINEAR": true,
+		"LINES": true, "LOAD": true, "LOCALTIME": true,
+		"LOCALTIMESTAMP": true, "LOCK": true, "LONG": true,
+		"LONGBLOB": true, "LONGTEXT": true, "LOOP": true,
+		"LOW_PRIORITY": true, "MATCH": true, "MEDIUMBLOB": true,
+		"MEDIUMINT": true, "MEDIUMTEXT": true, "MIDDLEINT": true,
+		"MINUTE_MICROSECOND": true, "MINUTE_SECOND": true, "MOD": true,
+		"MODIFIES": true, "NATURAL": true, "NOT": true,
+		"NO_WRITE_TO_BINLOG": true, "NULL": true, "NUMERIC": true,
+		"ON	OPTIMIZE": true, "OPTION": true,
+		"OPTIONALLY": true, "OR": true, "ORDER": true,
+		"OUT": true, "OUTER": true, "OUTFILE": true,
+		"PRECISION": true, "PRIMARY": true, "PROCEDURE": true,
+		"PURGE": true, "RAID0": true, "RANGE": true,
+		"READ": true, "READS": true, "REAL": true,
+		"REFERENCES": true, "REGEXP": true, "RELEASE": true,
+		"RENAME": true, "REPEAT": true, "REPLACE": true,
+		"REQUIRE": true, "RESTRICT": true, "RETURN": true,
+		"REVOKE": true, "RIGHT": true, "RLIKE": true,
+		"SCHEMA": true, "SCHEMAS": true, "SECOND_MICROSECOND": true,
+		"SELECT": true, "SENSITIVE": true, "SEPARATOR": true,
+		"SET": true, "SHOW": true, "SMALLINT": true,
+		"SPATIAL": true, "SPECIFIC": true, "SQL": true,
+		"SQLEXCEPTION": true, "SQLSTATE": true, "SQLWARNING": true,
+		"SQL_BIG_RESULT": true, "SQL_CALC_FOUND_ROWS": true, "SQL_SMALL_RESULT": true,
+		"SSL": true, "STARTING": true, "STRAIGHT_JOIN": true,
+		"TABLE": true, "TERMINATED": true, "THEN": true,
+		"TINYBLOB": true, "TINYINT": true, "TINYTEXT": true,
+		"TO": true, "TRAILING": true, "TRIGGER": true,
+		"TRUE": true, "UNDO": true, "UNION": true,
+		"UNIQUE": true, "UNLOCK": true, "UNSIGNED": true,
+		"UPDATE": true, "USAGE": true, "USE": true,
+		"USING": true, "UTC_DATE": true, "UTC_TIME": true,
+		"UTC_TIMESTAMP": true, "VALUES": true, "VARBINARY": true,
+		"VARCHAR":      true,
+		"VARCHARACTER": true,
+		"VARYING":      true,
+		"WHEN":         true,
+		"WHERE":        true,
+		"WHILE":        true,
+		"WITH":         true,
+		"WRITE":        true,
+		"X509":         true,
+		"XOR":          true,
+		"YEAR_MONTH":   true,
+		"ZEROFILL":     true,
+	}
+)
+
+type mysql struct {
+	core.Base
+	net               string
+	addr              string
+	params            map[string]string
+	loc               *time.Location
+	timeout           time.Duration
+	tls               *tls.Config
+	allowAllFiles     bool
+	allowOldPasswords bool
+	clientFoundRows   bool
+}
+
+func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *mysql) SqlType(c *core.Column) string {
+	var res string
+	switch t := c.SQLType.Name; t {
+	case core.Bool:
+		res = core.TinyInt
+		c.Length = 1
+	case core.Serial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = core.Int
+	case core.BigSerial:
+		c.IsAutoIncrement = true
+		c.IsPrimaryKey = true
+		c.Nullable = false
+		res = core.BigInt
+	case core.Bytea:
+		res = core.Blob
+	case core.TimeStampz:
+		res = core.Char
+		c.Length = 64
+	case core.Enum: //mysql enum
+		res = core.Enum
+		res += "("
+		opts := ""
+		for v, _ := range c.EnumOptions {
+			opts += fmt.Sprintf(",'%v'", v)
+		}
+		res += strings.TrimLeft(opts, ",")
+		res += ")"
+	case core.Set: //mysql set
+		res = core.Set
+		res += "("
+		opts := ""
+		for v, _ := range c.SetOptions {
+			opts += fmt.Sprintf(",'%v'", v)
+		}
+		res += strings.TrimLeft(opts, ",")
+		res += ")"
+	case core.NVarchar:
+		res = core.Varchar
+	case core.Uuid:
+		res = core.Varchar
+		c.Length = 40
+	case core.Json:
+		res = core.Text
+	default:
+		res = t
+	}
+
+	var hasLen1 bool = (c.Length > 0)
+	var hasLen2 bool = (c.Length2 > 0)
+
+	if res == core.BigInt && !hasLen1 && !hasLen2 {
+		c.Length = 20
+		hasLen1 = true
+	}
+
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *mysql) SupportInsertMany() bool {
+	return true
+}
+
+func (db *mysql) IsReserved(name string) bool {
+	_, ok := mysqlReservedWords[name]
+	return ok
+}
+
+func (db *mysql) Quote(name string) string {
+	return "`" + name + "`"
+}
+
+func (db *mysql) QuoteStr() string {
+	return "`"
+}
+
+func (db *mysql) SupportEngine() bool {
+	return true
+}
+
+func (db *mysql) AutoIncrStr() string {
+	return "AUTO_INCREMENT"
+}
+
+func (db *mysql) SupportCharset() bool {
+	return true
+}
+
+func (db *mysql) IndexOnTable() bool {
+	return true
+}
+
+func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{db.DbName, tableName, idxName}
+	sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
+	sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
+	return sql, args
+}
+
+/*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{db.DbName, tableName, colName}
+	sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
+	return sql, args
+}*/
+
+func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{db.DbName, tableName}
+	sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
+	return sql, args
+}
+
+func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{db.DbName, tableName}
+	s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
+		" `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+	for rows.Next() {
+		col := new(core.Column)
+		col.Indexes = make(map[string]bool)
+
+		var columnName, isNullable, colType, colKey, extra string
+		var colDefault *string
+		err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra)
+		if err != nil {
+			return nil, nil, err
+		}
+		col.Name = strings.Trim(columnName, "` ")
+		if "YES" == isNullable {
+			col.Nullable = true
+		}
+
+		if colDefault != nil {
+			col.Default = *colDefault
+			if col.Default == "" {
+				col.DefaultIsEmpty = true
+			}
+		}
+
+		cts := strings.Split(colType, "(")
+		colName := cts[0]
+		colType = strings.ToUpper(colName)
+		var len1, len2 int
+		if len(cts) == 2 {
+			idx := strings.Index(cts[1], ")")
+			if colType == core.Enum && cts[1][0] == '\'' { //enum
+				options := strings.Split(cts[1][0:idx], ",")
+				col.EnumOptions = make(map[string]int)
+				for k, v := range options {
+					v = strings.TrimSpace(v)
+					v = strings.Trim(v, "'")
+					col.EnumOptions[v] = k
+				}
+			} else if colType == core.Set && cts[1][0] == '\'' {
+				options := strings.Split(cts[1][0:idx], ",")
+				col.SetOptions = make(map[string]int)
+				for k, v := range options {
+					v = strings.TrimSpace(v)
+					v = strings.Trim(v, "'")
+					col.SetOptions[v] = k
+				}
+			} else {
+				lens := strings.Split(cts[1][0:idx], ",")
+				len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
+				if err != nil {
+					return nil, nil, err
+				}
+				if len(lens) == 2 {
+					len2, err = strconv.Atoi(lens[1])
+					if err != nil {
+						return nil, nil, err
+					}
+				}
+			}
+		}
+		if colType == "FLOAT UNSIGNED" {
+			colType = "FLOAT"
+		}
+		col.Length = len1
+		col.Length2 = len2
+		if _, ok := core.SqlTypes[colType]; ok {
+			col.SQLType = core.SQLType{colType, len1, len2}
+		} else {
+			return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType))
+		}
+
+		if colKey == "PRI" {
+			col.IsPrimaryKey = true
+		}
+		if colKey == "UNI" {
+			//col.is
+		}
+
+		if extra == "auto_increment" {
+			col.IsAutoIncrement = true
+		}
+
+		if col.SQLType.IsText() || col.SQLType.IsTime() {
+			if col.Default != "" {
+				col.Default = "'" + col.Default + "'"
+			} else {
+				if col.DefaultIsEmpty {
+					col.Default = "''"
+				}
+			}
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+	return colSeq, cols, nil
+}
+
+func (db *mysql) GetTables() ([]*core.Table, error) {
+	args := []interface{}{db.DbName}
+	s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " +
+		"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB')"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		var name, engine, tableRows string
+		var autoIncr *string
+		err = rows.Scan(&name, &engine, &tableRows, &autoIncr)
+		if err != nil {
+			return nil, err
+		}
+
+		table.Name = name
+		table.StoreEngine = engine
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{db.DbName, tableName}
+	s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var indexType int
+		var indexName, colName, nonUnique string
+		err = rows.Scan(&indexName, &nonUnique, &colName)
+		if err != nil {
+			return nil, err
+		}
+
+		if indexName == "PRIMARY" {
+			continue
+		}
+
+		if "YES" == nonUnique || nonUnique == "1" {
+			indexType = core.IndexType
+		} else {
+			indexType = core.UniqueType
+		}
+
+		colName = strings.Trim(colName, "` ")
+		var isRegular bool
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			indexName = indexName[5+len(tableName) : len(indexName)]
+			isRegular = true
+		}
+
+		var index *core.Index
+		var ok bool
+		if index, ok = indexes[indexName]; !ok {
+			index = new(core.Index)
+			index.IsRegular = isRegular
+			index.Type = indexType
+			index.Name = indexName
+			indexes[indexName] = index
+		}
+		index.AddColumn(colName)
+	}
+	return indexes, nil
+}
+
+func (db *mysql) Filters() []core.Filter {
+	return []core.Filter{&core.IdFilter{}}
+}

+ 54 - 0
mysql_driver.go

@@ -0,0 +1,54 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"regexp"
+	"strings"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	core.RegisterDriver("mysql", &mysqlDriver{})
+// }
+
+type mysqlDriver struct {
+}
+
+func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	dsnPattern := regexp.MustCompile(
+		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
+			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
+			`\/(?P<dbname>.*?)` + // /dbname
+			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
+	matches := dsnPattern.FindStringSubmatch(dataSourceName)
+	//tlsConfigRegister := make(map[string]*tls.Config)
+	names := dsnPattern.SubexpNames()
+
+	uri := &core.Uri{DbType: core.MYSQL}
+
+	for i, match := range matches {
+		switch names[i] {
+		case "dbname":
+			uri.DbName = match
+		case "params":
+			if len(match) > 0 {
+				kvs := strings.Split(match, "&")
+				for _, kv := range kvs {
+					splits := strings.Split(kv, "=")
+					if len(splits) == 2 {
+						switch splits[0] {
+						case "charset":
+							uri.Charset = splits[1]
+						}
+					}
+				}
+			}
+
+		}
+	}
+	return uri, nil
+}

+ 41 - 0
oci8_driver.go

@@ -0,0 +1,41 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"regexp"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	core.RegisterDriver("oci8", &oci8Driver{})
+// }
+
+type oci8Driver struct {
+}
+
+//dataSourceName=user/password@ipv4:port/dbname
+//dataSourceName=user/password@[ipv6]:port/dbname
+func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.ORACLE}
+	dsnPattern := regexp.MustCompile(
+		`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
+			`(?P<net>.*)` + // ip:port
+			`\/(?P<dbname>.*)`) // dbname
+	matches := dsnPattern.FindStringSubmatch(dataSourceName)
+	names := dsnPattern.SubexpNames()
+	for i, match := range matches {
+		switch names[i] {
+		case "dbname":
+			db.DbName = match
+		}
+	}
+	if db.DbName == "" {
+		return nil, errors.New("dbname is empty")
+	}
+	return db, nil
+}

+ 38 - 0
odbc_driver.go

@@ -0,0 +1,38 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"strings"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	core.RegisterDriver("odbc", &odbcDriver{})
+// }
+
+type odbcDriver struct {
+}
+
+func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	kv := strings.Split(dataSourceName, ";")
+	var dbName string
+
+	for _, c := range kv {
+		vv := strings.Split(strings.TrimSpace(c), "=")
+		if len(vv) == 2 {
+			switch strings.ToLower(vv[0]) {
+			case "database":
+				dbName = vv[1]
+			}
+		}
+	}
+	if dbName == "" {
+		return nil, errors.New("no db name provided")
+	}
+	return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
+}

+ 860 - 0
oracle_dialect.go

@@ -0,0 +1,860 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	RegisterDialect("oracle", &oracle{})
+// }
+
+var (
+	oracleReservedWords = map[string]bool{
+		"ACCESS":                    true,
+		"ACCOUNT":                   true,
+		"ACTIVATE":                  true,
+		"ADD":                       true,
+		"ADMIN":                     true,
+		"ADVISE":                    true,
+		"AFTER":                     true,
+		"ALL":                       true,
+		"ALL_ROWS":                  true,
+		"ALLOCATE":                  true,
+		"ALTER":                     true,
+		"ANALYZE":                   true,
+		"AND":                       true,
+		"ANY":                       true,
+		"ARCHIVE":                   true,
+		"ARCHIVELOG":                true,
+		"ARRAY":                     true,
+		"AS":                        true,
+		"ASC":                       true,
+		"AT":                        true,
+		"AUDIT":                     true,
+		"AUTHENTICATED":             true,
+		"AUTHORIZATION":             true,
+		"AUTOEXTEND":                true,
+		"AUTOMATIC":                 true,
+		"BACKUP":                    true,
+		"BECOME":                    true,
+		"BEFORE":                    true,
+		"BEGIN":                     true,
+		"BETWEEN":                   true,
+		"BFILE":                     true,
+		"BITMAP":                    true,
+		"BLOB":                      true,
+		"BLOCK":                     true,
+		"BODY":                      true,
+		"BY":                        true,
+		"CACHE":                     true,
+		"CACHE_INSTANCES":           true,
+		"CANCEL":                    true,
+		"CASCADE":                   true,
+		"CAST":                      true,
+		"CFILE":                     true,
+		"CHAINED":                   true,
+		"CHANGE":                    true,
+		"CHAR":                      true,
+		"CHAR_CS":                   true,
+		"CHARACTER":                 true,
+		"CHECK":                     true,
+		"CHECKPOINT":                true,
+		"CHOOSE":                    true,
+		"CHUNK":                     true,
+		"CLEAR":                     true,
+		"CLOB":                      true,
+		"CLONE":                     true,
+		"CLOSE":                     true,
+		"CLOSE_CACHED_OPEN_CURSORS": true,
+		"CLUSTER":                   true,
+		"COALESCE":                  true,
+		"COLUMN":                    true,
+		"COLUMNS":                   true,
+		"COMMENT":                   true,
+		"COMMIT":                    true,
+		"COMMITTED":                 true,
+		"COMPATIBILITY":             true,
+		"COMPILE":                   true,
+		"COMPLETE":                  true,
+		"COMPOSITE_LIMIT":           true,
+		"COMPRESS":                  true,
+		"COMPUTE":                   true,
+		"CONNECT":                   true,
+		"CONNECT_TIME":              true,
+		"CONSTRAINT":                true,
+		"CONSTRAINTS":               true,
+		"CONTENTS":                  true,
+		"CONTINUE":                  true,
+		"CONTROLFILE":               true,
+		"CONVERT":                   true,
+		"COST":                      true,
+		"CPU_PER_CALL":              true,
+		"CPU_PER_SESSION":           true,
+		"CREATE":                    true,
+		"CURRENT":                   true,
+		"CURRENT_SCHEMA":            true,
+		"CURREN_USER":               true,
+		"CURSOR":                    true,
+		"CYCLE":                     true,
+		"DANGLING":                  true,
+		"DATABASE":                  true,
+		"DATAFILE":                  true,
+		"DATAFILES":                 true,
+		"DATAOBJNO":                 true,
+		"DATE":                      true,
+		"DBA":                       true,
+		"DBHIGH":                    true,
+		"DBLOW":                     true,
+		"DBMAC":                     true,
+		"DEALLOCATE":                true,
+		"DEBUG":                     true,
+		"DEC":                       true,
+		"DECIMAL":                   true,
+		"DECLARE":                   true,
+		"DEFAULT":                   true,
+		"DEFERRABLE":                true,
+		"DEFERRED":                  true,
+		"DEGREE":                    true,
+		"DELETE":                    true,
+		"DEREF":                     true,
+		"DESC":                      true,
+		"DIRECTORY":                 true,
+		"DISABLE":                   true,
+		"DISCONNECT":                true,
+		"DISMOUNT":                  true,
+		"DISTINCT":                  true,
+		"DISTRIBUTED":               true,
+		"DML":                       true,
+		"DOUBLE":                    true,
+		"DROP":                      true,
+		"DUMP":                      true,
+		"EACH":                      true,
+		"ELSE":                      true,
+		"ENABLE":                    true,
+		"END":                       true,
+		"ENFORCE":                   true,
+		"ENTRY":                     true,
+		"ESCAPE":                    true,
+		"EXCEPT":                    true,
+		"EXCEPTIONS":                true,
+		"EXCHANGE":                  true,
+		"EXCLUDING":                 true,
+		"EXCLUSIVE":                 true,
+		"EXECUTE":                   true,
+		"EXISTS":                    true,
+		"EXPIRE":                    true,
+		"EXPLAIN":                   true,
+		"EXTENT":                    true,
+		"EXTENTS":                   true,
+		"EXTERNALLY":                true,
+		"FAILED_LOGIN_ATTEMPTS":     true,
+		"FALSE":                     true,
+		"FAST":                      true,
+		"FILE":                      true,
+		"FIRST_ROWS":                true,
+		"FLAGGER":                   true,
+		"FLOAT":                     true,
+		"FLOB":                      true,
+		"FLUSH":                     true,
+		"FOR":                       true,
+		"FORCE":                     true,
+		"FOREIGN":                   true,
+		"FREELIST":                  true,
+		"FREELISTS":                 true,
+		"FROM":                      true,
+		"FULL":                      true,
+		"FUNCTION":                  true,
+		"GLOBAL":                    true,
+		"GLOBALLY":                  true,
+		"GLOBAL_NAME":               true,
+		"GRANT":                     true,
+		"GROUP":                     true,
+		"GROUPS":                    true,
+		"HASH":                      true,
+		"HASHKEYS":                  true,
+		"HAVING":                    true,
+		"HEADER":                    true,
+		"HEAP":                      true,
+		"IDENTIFIED":                true,
+		"IDGENERATORS":              true,
+		"IDLE_TIME":                 true,
+		"IF":                        true,
+		"IMMEDIATE":                 true,
+		"IN":                        true,
+		"INCLUDING":                 true,
+		"INCREMENT":                 true,
+		"INDEX":                     true,
+		"INDEXED":                   true,
+		"INDEXES":                   true,
+		"INDICATOR":                 true,
+		"IND_PARTITION":             true,
+		"INITIAL":                   true,
+		"INITIALLY":                 true,
+		"INITRANS":                  true,
+		"INSERT":                    true,
+		"INSTANCE":                  true,
+		"INSTANCES":                 true,
+		"INSTEAD":                   true,
+		"INT":                       true,
+		"INTEGER":                   true,
+		"INTERMEDIATE":              true,
+		"INTERSECT":                 true,
+		"INTO":                      true,
+		"IS":                        true,
+		"ISOLATION":                 true,
+		"ISOLATION_LEVEL":           true,
+		"KEEP":                      true,
+		"KEY":                       true,
+		"KILL":                      true,
+		"LABEL":                     true,
+		"LAYER":                     true,
+		"LESS":                      true,
+		"LEVEL":                     true,
+		"LIBRARY":                   true,
+		"LIKE":                      true,
+		"LIMIT":                     true,
+		"LINK":                      true,
+		"LIST":                      true,
+		"LOB":                       true,
+		"LOCAL":                     true,
+		"LOCK":                      true,
+		"LOCKED":                    true,
+		"LOG":                       true,
+		"LOGFILE":                   true,
+		"LOGGING":                   true,
+		"LOGICAL_READS_PER_CALL":    true,
+		"LOGICAL_READS_PER_SESSION": true,
+		"LONG":                     true,
+		"MANAGE":                   true,
+		"MASTER":                   true,
+		"MAX":                      true,
+		"MAXARCHLOGS":              true,
+		"MAXDATAFILES":             true,
+		"MAXEXTENTS":               true,
+		"MAXINSTANCES":             true,
+		"MAXLOGFILES":              true,
+		"MAXLOGHISTORY":            true,
+		"MAXLOGMEMBERS":            true,
+		"MAXSIZE":                  true,
+		"MAXTRANS":                 true,
+		"MAXVALUE":                 true,
+		"MIN":                      true,
+		"MEMBER":                   true,
+		"MINIMUM":                  true,
+		"MINEXTENTS":               true,
+		"MINUS":                    true,
+		"MINVALUE":                 true,
+		"MLSLABEL":                 true,
+		"MLS_LABEL_FORMAT":         true,
+		"MODE":                     true,
+		"MODIFY":                   true,
+		"MOUNT":                    true,
+		"MOVE":                     true,
+		"MTS_DISPATCHERS":          true,
+		"MULTISET":                 true,
+		"NATIONAL":                 true,
+		"NCHAR":                    true,
+		"NCHAR_CS":                 true,
+		"NCLOB":                    true,
+		"NEEDED":                   true,
+		"NESTED":                   true,
+		"NETWORK":                  true,
+		"NEW":                      true,
+		"NEXT":                     true,
+		"NOARCHIVELOG":             true,
+		"NOAUDIT":                  true,
+		"NOCACHE":                  true,
+		"NOCOMPRESS":               true,
+		"NOCYCLE":                  true,
+		"NOFORCE":                  true,
+		"NOLOGGING":                true,
+		"NOMAXVALUE":               true,
+		"NOMINVALUE":               true,
+		"NONE":                     true,
+		"NOORDER":                  true,
+		"NOOVERRIDE":               true,
+		"NOPARALLEL":               true,
+		"NOREVERSE":                true,
+		"NORMAL":                   true,
+		"NOSORT":                   true,
+		"NOT":                      true,
+		"NOTHING":                  true,
+		"NOWAIT":                   true,
+		"NULL":                     true,
+		"NUMBER":                   true,
+		"NUMERIC":                  true,
+		"NVARCHAR2":                true,
+		"OBJECT":                   true,
+		"OBJNO":                    true,
+		"OBJNO_REUSE":              true,
+		"OF":                       true,
+		"OFF":                      true,
+		"OFFLINE":                  true,
+		"OID":                      true,
+		"OIDINDEX":                 true,
+		"OLD":                      true,
+		"ON":                       true,
+		"ONLINE":                   true,
+		"ONLY":                     true,
+		"OPCODE":                   true,
+		"OPEN":                     true,
+		"OPTIMAL":                  true,
+		"OPTIMIZER_GOAL":           true,
+		"OPTION":                   true,
+		"OR":                       true,
+		"ORDER":                    true,
+		"ORGANIZATION":             true,
+		"OSLABEL":                  true,
+		"OVERFLOW":                 true,
+		"OWN":                      true,
+		"PACKAGE":                  true,
+		"PARALLEL":                 true,
+		"PARTITION":                true,
+		"PASSWORD":                 true,
+		"PASSWORD_GRACE_TIME":      true,
+		"PASSWORD_LIFE_TIME":       true,
+		"PASSWORD_LOCK_TIME":       true,
+		"PASSWORD_REUSE_MAX":       true,
+		"PASSWORD_REUSE_TIME":      true,
+		"PASSWORD_VERIFY_FUNCTION": true,
+		"PCTFREE":                  true,
+		"PCTINCREASE":              true,
+		"PCTTHRESHOLD":             true,
+		"PCTUSED":                  true,
+		"PCTVERSION":               true,
+		"PERCENT":                  true,
+		"PERMANENT":                true,
+		"PLAN":                     true,
+		"PLSQL_DEBUG":              true,
+		"POST_TRANSACTION":         true,
+		"PRECISION":                true,
+		"PRESERVE":                 true,
+		"PRIMARY":                  true,
+		"PRIOR":                    true,
+		"PRIVATE":                  true,
+		"PRIVATE_SGA":              true,
+		"PRIVILEGE":                true,
+		"PRIVILEGES":               true,
+		"PROCEDURE":                true,
+		"PROFILE":                  true,
+		"PUBLIC":                   true,
+		"PURGE":                    true,
+		"QUEUE":                    true,
+		"QUOTA":                    true,
+		"RANGE":                    true,
+		"RAW":                      true,
+		"RBA":                      true,
+		"READ":                     true,
+		"READUP":                   true,
+		"REAL":                     true,
+		"REBUILD":                  true,
+		"RECOVER":                  true,
+		"RECOVERABLE":              true,
+		"RECOVERY":                 true,
+		"REF":                      true,
+		"REFERENCES":               true,
+		"REFERENCING":              true,
+		"REFRESH":                  true,
+		"RENAME":                   true,
+		"REPLACE":                  true,
+		"RESET":                    true,
+		"RESETLOGS":                true,
+		"RESIZE":                   true,
+		"RESOURCE":                 true,
+		"RESTRICTED":               true,
+		"RETURN":                   true,
+		"RETURNING":                true,
+		"REUSE":                    true,
+		"REVERSE":                  true,
+		"REVOKE":                   true,
+		"ROLE":                     true,
+		"ROLES":                    true,
+		"ROLLBACK":                 true,
+		"ROW":                      true,
+		"ROWID":                    true,
+		"ROWNUM":                   true,
+		"ROWS":                     true,
+		"RULE":                     true,
+		"SAMPLE":                   true,
+		"SAVEPOINT":                true,
+		"SB4":                      true,
+		"SCAN_INSTANCES":           true,
+		"SCHEMA":                   true,
+		"SCN":                      true,
+		"SCOPE":                    true,
+		"SD_ALL":                   true,
+		"SD_INHIBIT":               true,
+		"SD_SHOW":                  true,
+		"SEGMENT":                  true,
+		"SEG_BLOCK":                true,
+		"SEG_FILE":                 true,
+		"SELECT":                   true,
+		"SEQUENCE":                 true,
+		"SERIALIZABLE":             true,
+		"SESSION":                  true,
+		"SESSION_CACHED_CURSORS":   true,
+		"SESSIONS_PER_USER":        true,
+		"SET":                      true,
+		"SHARE":                    true,
+		"SHARED":                   true,
+		"SHARED_POOL":              true,
+		"SHRINK":                   true,
+		"SIZE":                     true,
+		"SKIP":                     true,
+		"SKIP_UNUSABLE_INDEXES":    true,
+		"SMALLINT":                 true,
+		"SNAPSHOT":                 true,
+		"SOME":                     true,
+		"SORT":                     true,
+		"SPECIFICATION":            true,
+		"SPLIT":                    true,
+		"SQL_TRACE":                true,
+		"STANDBY":                  true,
+		"START":                    true,
+		"STATEMENT_ID":             true,
+		"STATISTICS":               true,
+		"STOP":                     true,
+		"STORAGE":                  true,
+		"STORE":                    true,
+		"STRUCTURE":                true,
+		"SUCCESSFUL":               true,
+		"SWITCH":                   true,
+		"SYS_OP_ENFORCE_NOT_NULL$": true,
+		"SYS_OP_NTCIMG$":           true,
+		"SYNONYM":                  true,
+		"SYSDATE":                  true,
+		"SYSDBA":                   true,
+		"SYSOPER":                  true,
+		"SYSTEM":                   true,
+		"TABLE":                    true,
+		"TABLES":                   true,
+		"TABLESPACE":               true,
+		"TABLESPACE_NO":            true,
+		"TABNO":                    true,
+		"TEMPORARY":                true,
+		"THAN":                     true,
+		"THE":                      true,
+		"THEN":                     true,
+		"THREAD":                   true,
+		"TIMESTAMP":                true,
+		"TIME":                     true,
+		"TO":                       true,
+		"TOPLEVEL":                 true,
+		"TRACE":                    true,
+		"TRACING":                  true,
+		"TRANSACTION":              true,
+		"TRANSITIONAL":             true,
+		"TRIGGER":                  true,
+		"TRIGGERS":                 true,
+		"TRUE":                     true,
+		"TRUNCATE":                 true,
+		"TX":                       true,
+		"TYPE":                     true,
+		"UB2":                      true,
+		"UBA":                      true,
+		"UID":                      true,
+		"UNARCHIVED":               true,
+		"UNDO":                     true,
+		"UNION":                    true,
+		"UNIQUE":                   true,
+		"UNLIMITED":                true,
+		"UNLOCK":                   true,
+		"UNRECOVERABLE":            true,
+		"UNTIL":                    true,
+		"UNUSABLE":                 true,
+		"UNUSED":                   true,
+		"UPDATABLE":                true,
+		"UPDATE":                   true,
+		"USAGE":                    true,
+		"USE":                      true,
+		"USER":                     true,
+		"USING":                    true,
+		"VALIDATE":                 true,
+		"VALIDATION":               true,
+		"VALUE":                    true,
+		"VALUES":                   true,
+		"VARCHAR":                  true,
+		"VARCHAR2":                 true,
+		"VARYING":                  true,
+		"VIEW":                     true,
+		"WHEN":                     true,
+		"WHENEVER":                 true,
+		"WHERE":                    true,
+		"WITH":                     true,
+		"WITHOUT":                  true,
+		"WORK":                     true,
+		"WRITE":                    true,
+		"WRITEDOWN":                true,
+		"WRITEUP":                  true,
+		"XID":                      true,
+		"YEAR":                     true,
+		"ZONE":                     true,
+	}
+)
+
+type oracle struct {
+	core.Base
+}
+
+func (db *oracle) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *oracle) SqlType(c *core.Column) string {
+	var res string
+	switch t := c.SQLType.Name; t {
+	case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool, core.Serial, core.BigSerial:
+		res = "NUMBER"
+	case core.Binary, core.VarBinary, core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob, core.Bytea:
+		return core.Blob
+	case core.Time, core.DateTime, core.TimeStamp:
+		res = core.TimeStamp
+	case core.TimeStampz:
+		res = "TIMESTAMP WITH TIME ZONE"
+	case core.Float, core.Double, core.Numeric, core.Decimal:
+		res = "NUMBER"
+	case core.Text, core.MediumText, core.LongText, core.Json:
+		res = "CLOB"
+	case core.Char, core.Varchar, core.TinyText:
+		res = "VARCHAR2"
+	default:
+		res = t
+	}
+
+	var hasLen1 bool = (c.Length > 0)
+	var hasLen2 bool = (c.Length2 > 0)
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *oracle) AutoIncrStr() string {
+	return "AUTO_INCREMENT"
+}
+
+func (db *oracle) SupportInsertMany() bool {
+	return true
+}
+
+func (db *oracle) IsReserved(name string) bool {
+	_, ok := oracleReservedWords[name]
+	return ok
+}
+
+func (db *oracle) Quote(name string) string {
+	return "\"" + name + "\""
+}
+
+func (db *oracle) QuoteStr() string {
+	return "\""
+}
+
+func (db *oracle) SupportEngine() bool {
+	return false
+}
+
+func (db *oracle) SupportCharset() bool {
+	return false
+}
+
+func (db *oracle) SupportDropIfExists() bool {
+	return false
+}
+
+func (db *oracle) IndexOnTable() bool {
+	return false
+}
+
+func (db *oracle) DropTableSql(tableName string) string {
+	return fmt.Sprintf("DROP TABLE `%s`", tableName)
+}
+
+func (b *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
+	var sql string
+	sql = "CREATE TABLE "
+	if tableName == "" {
+		tableName = table.Name
+	}
+
+	sql += b.Quote(tableName) + " ("
+
+	pkList := table.PrimaryKeys
+
+	for _, colName := range table.ColumnsSeq() {
+		col := table.GetColumn(colName)
+		/*if col.IsPrimaryKey && len(pkList) == 1 {
+			sql += col.String(b.dialect)
+		} else {*/
+		sql += col.StringNoPk(b)
+		//}
+		sql = strings.TrimSpace(sql)
+		sql += ", "
+	}
+
+	if len(pkList) > 0 {
+		sql += "PRIMARY KEY ( "
+		sql += b.Quote(strings.Join(pkList, b.Quote(",")))
+		sql += " ), "
+	}
+
+	sql = sql[:len(sql)-2] + ")"
+	if b.SupportEngine() && storeEngine != "" {
+		sql += " ENGINE=" + storeEngine
+	}
+	if b.SupportCharset() {
+		if len(charset) == 0 {
+			charset = b.URI().Charset
+		}
+		if len(charset) > 0 {
+			sql += " DEFAULT CHARSET " + charset
+		}
+	}
+	return sql
+}
+
+func (db *oracle) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{tableName, idxName}
+	return `SELECT INDEX_NAME FROM USER_INDEXES ` +
+		`WHERE TABLE_NAME = :1 AND INDEX_NAME = :2`, args
+}
+
+func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	return `SELECT table_name FROM user_tables WHERE table_name = :1`, args
+}
+
+func (db *oracle) MustDropTable(tableName string) error {
+	sql, args := db.TableCheckSql(tableName)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", sql, args)
+	}
+
+	rows, err := db.DB().Query(sql, args...)
+	if err != nil {
+		return err
+	}
+	defer rows.Close()
+
+	if !rows.Next() {
+		return nil
+	}
+
+	sql = "Drop Table \"" + tableName + "\""
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", sql)
+	}
+	_, err = db.DB().Exec(sql)
+	return err
+}
+
+/*func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(colName)}
+	return "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = ?" +
+		" AND column_name = ?", args
+}*/
+
+func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
+	args := []interface{}{tableName, colName}
+	query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
+		" AND column_name = :2"
+	rows, err := db.DB().Query(query, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", query, args)
+	}
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	if rows.Next() {
+		return true, nil
+	}
+	return false, nil
+}
+
+func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{tableName}
+	s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
+		"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+	for rows.Next() {
+		col := new(core.Column)
+		col.Indexes = make(map[string]bool)
+
+		var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string
+		var dataLen int
+
+		err = rows.Scan(&colName, &colDefault, &dataType, &dataLen, &dataPrecision,
+			&dataScale, &nullable)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		col.Name = strings.Trim(*colName, `" `)
+		if colDefault != nil {
+			col.Default = *colDefault
+			col.DefaultIsEmpty = false
+		}
+
+		if *nullable == "Y" {
+			col.Nullable = true
+		} else {
+			col.Nullable = false
+		}
+
+		var ignore bool
+
+		var dt string
+		var len1, len2 int
+		dts := strings.Split(*dataType, "(")
+		dt = dts[0]
+		if len(dts) > 1 {
+			lens := strings.Split(dts[1][:len(dts[1])-1], ",")
+			if len(lens) > 1 {
+				len1, _ = strconv.Atoi(lens[0])
+				len2, _ = strconv.Atoi(lens[1])
+			} else {
+				len1, _ = strconv.Atoi(lens[0])
+			}
+		}
+
+		switch dt {
+		case "VARCHAR2":
+			col.SQLType = core.SQLType{core.Varchar, len1, len2}
+		case "NVARCHAR2":
+			col.SQLType = core.SQLType{core.NVarchar, len1, len2}
+		case "TIMESTAMP WITH TIME ZONE":
+			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
+		case "NUMBER":
+			col.SQLType = core.SQLType{core.Double, len1, len2}
+		case "LONG", "LONG RAW":
+			col.SQLType = core.SQLType{core.Text, 0, 0}
+		case "RAW":
+			col.SQLType = core.SQLType{core.Binary, 0, 0}
+		case "ROWID":
+			col.SQLType = core.SQLType{core.Varchar, 18, 0}
+		case "AQ$_SUBSCRIBERS":
+			ignore = true
+		default:
+			col.SQLType = core.SQLType{strings.ToUpper(dt), len1, len2}
+		}
+
+		if ignore {
+			continue
+		}
+
+		if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
+			return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v %v", *dataType, col.SQLType))
+		}
+
+		col.Length = dataLen
+
+		if col.SQLType.IsText() || col.SQLType.IsTime() {
+			if !col.DefaultIsEmpty {
+				col.Default = "'" + col.Default + "'"
+			}
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+
+	return colSeq, cols, nil
+}
+
+func (db *oracle) GetTables() ([]*core.Table, error) {
+	args := []interface{}{}
+	s := "SELECT table_name FROM user_tables"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		err = rows.Scan(&table.Name)
+		if err != nil {
+			return nil, err
+		}
+
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{tableName}
+	s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
+		"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var indexType int
+		var indexName, colName, uniqueness string
+
+		err = rows.Scan(&colName, &uniqueness, &indexName)
+		if err != nil {
+			return nil, err
+		}
+
+		indexName = strings.Trim(indexName, `" `)
+
+		if uniqueness == "UNIQUE" {
+			indexType = core.UniqueType
+		} else {
+			indexType = core.IndexType
+		}
+
+		var index *core.Index
+		var ok bool
+		if index, ok = indexes[indexName]; !ok {
+			index = new(core.Index)
+			index.Type = indexType
+			index.Name = indexName
+			indexes[indexName] = index
+		}
+		index.AddColumn(colName)
+	}
+	return indexes, nil
+}
+
+func (db *oracle) Filters() []core.Filter {
+	return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{":", 1}, &core.IdFilter{}}
+}

+ 746 - 0
pg_reserved.txt

@@ -0,0 +1,746 @@
+A	 	non-reserved	non-reserved	 
+ABORT	non-reserved	 	 	 
+ABS	 	reserved	reserved	 
+ABSENT	 	non-reserved	non-reserved	 
+ABSOLUTE	non-reserved	non-reserved	non-reserved	reserved
+ACCESS	non-reserved	 	 	 
+ACCORDING	 	non-reserved	non-reserved	 
+ACTION	non-reserved	non-reserved	non-reserved	reserved
+ADA	 	non-reserved	non-reserved	non-reserved
+ADD	non-reserved	non-reserved	non-reserved	reserved
+ADMIN	non-reserved	non-reserved	non-reserved	 
+AFTER	non-reserved	non-reserved	non-reserved	 
+AGGREGATE	non-reserved	 	 	 
+ALL	reserved	reserved	reserved	reserved
+ALLOCATE	 	reserved	reserved	reserved
+ALSO	non-reserved	 	 	 
+ALTER	non-reserved	reserved	reserved	reserved
+ALWAYS	non-reserved	non-reserved	non-reserved	 
+ANALYSE	reserved	 	 	 
+ANALYZE	reserved	 	 	 
+AND	reserved	reserved	reserved	reserved
+ANY	reserved	reserved	reserved	reserved
+ARE	 	reserved	reserved	reserved
+ARRAY	reserved	reserved	reserved	 
+ARRAY_AGG	 	reserved	reserved	 
+ARRAY_MAX_CARDINALITY	 	reserved	 	 
+AS	reserved	reserved	reserved	reserved
+ASC	reserved	non-reserved	non-reserved	reserved
+ASENSITIVE	 	reserved	reserved	 
+ASSERTION	non-reserved	non-reserved	non-reserved	reserved
+ASSIGNMENT	non-reserved	non-reserved	non-reserved	 
+ASYMMETRIC	reserved	reserved	reserved	 
+AT	non-reserved	reserved	reserved	reserved
+ATOMIC	 	reserved	reserved	 
+ATTRIBUTE	non-reserved	non-reserved	non-reserved	 
+ATTRIBUTES	 	non-reserved	non-reserved	 
+AUTHORIZATION	reserved (can be function or type)	reserved	reserved	reserved
+AVG	 	reserved	reserved	reserved
+BACKWARD	non-reserved	 	 	 
+BASE64	 	non-reserved	non-reserved	 
+BEFORE	non-reserved	non-reserved	non-reserved	 
+BEGIN	non-reserved	reserved	reserved	reserved
+BEGIN_FRAME	 	reserved	 	 
+BEGIN_PARTITION	 	reserved	 	 
+BERNOULLI	 	non-reserved	non-reserved	 
+BETWEEN	non-reserved (cannot be function or type)	reserved	reserved	reserved
+BIGINT	non-reserved (cannot be function or type)	reserved	reserved	 
+BINARY	reserved (can be function or type)	reserved	reserved	 
+BIT	non-reserved (cannot be function or type)	 	 	reserved
+BIT_LENGTH	 	 	 	reserved
+BLOB	 	reserved	reserved	 
+BLOCKED	 	non-reserved	non-reserved	 
+BOM	 	non-reserved	non-reserved	 
+BOOLEAN	non-reserved (cannot be function or type)	reserved	reserved	 
+BOTH	reserved	reserved	reserved	reserved
+BREADTH	 	non-reserved	non-reserved	 
+BY	non-reserved	reserved	reserved	reserved
+C	 	non-reserved	non-reserved	non-reserved
+CACHE	non-reserved	 	 	 
+CALL	 	reserved	reserved	 
+CALLED	non-reserved	reserved	reserved	 
+CARDINALITY	 	reserved	reserved	 
+CASCADE	non-reserved	non-reserved	non-reserved	reserved
+CASCADED	non-reserved	reserved	reserved	reserved
+CASE	reserved	reserved	reserved	reserved
+CAST	reserved	reserved	reserved	reserved
+CATALOG	non-reserved	non-reserved	non-reserved	reserved
+CATALOG_NAME	 	non-reserved	non-reserved	non-reserved
+CEIL	 	reserved	reserved	 
+CEILING	 	reserved	reserved	 
+CHAIN	non-reserved	non-reserved	non-reserved	 
+CHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
+CHARACTER	non-reserved (cannot be function or type)	reserved	reserved	reserved
+CHARACTERISTICS	non-reserved	non-reserved	non-reserved	 
+CHARACTERS	 	non-reserved	non-reserved	 
+CHARACTER_LENGTH	 	reserved	reserved	reserved
+CHARACTER_SET_CATALOG	 	non-reserved	non-reserved	non-reserved
+CHARACTER_SET_NAME	 	non-reserved	non-reserved	non-reserved
+CHARACTER_SET_SCHEMA	 	non-reserved	non-reserved	non-reserved
+CHAR_LENGTH	 	reserved	reserved	reserved
+CHECK	reserved	reserved	reserved	reserved
+CHECKPOINT	non-reserved	 	 	 
+CLASS	non-reserved	 	 	 
+CLASS_ORIGIN	 	non-reserved	non-reserved	non-reserved
+CLOB	 	reserved	reserved	 
+CLOSE	non-reserved	reserved	reserved	reserved
+CLUSTER	non-reserved	 	 	 
+COALESCE	non-reserved (cannot be function or type)	reserved	reserved	reserved
+COBOL	 	non-reserved	non-reserved	non-reserved
+COLLATE	reserved	reserved	reserved	reserved
+COLLATION	reserved (can be function or type)	non-reserved	non-reserved	reserved
+COLLATION_CATALOG	 	non-reserved	non-reserved	non-reserved
+COLLATION_NAME	 	non-reserved	non-reserved	non-reserved
+COLLATION_SCHEMA	 	non-reserved	non-reserved	non-reserved
+COLLECT	 	reserved	reserved	 
+COLUMN	reserved	reserved	reserved	reserved
+COLUMNS	 	non-reserved	non-reserved	 
+COLUMN_NAME	 	non-reserved	non-reserved	non-reserved
+COMMAND_FUNCTION	 	non-reserved	non-reserved	non-reserved
+COMMAND_FUNCTION_CODE	 	non-reserved	non-reserved	 
+COMMENT	non-reserved	 	 	 
+COMMENTS	non-reserved	 	 	 
+COMMIT	non-reserved	reserved	reserved	reserved
+COMMITTED	non-reserved	non-reserved	non-reserved	non-reserved
+CONCURRENTLY	reserved (can be function or type)	 	 	 
+CONDITION	 	reserved	reserved	 
+CONDITION_NUMBER	 	non-reserved	non-reserved	non-reserved
+CONFIGURATION	non-reserved	 	 	 
+CONNECT	 	reserved	reserved	reserved
+CONNECTION	non-reserved	non-reserved	non-reserved	reserved
+CONNECTION_NAME	 	non-reserved	non-reserved	non-reserved
+CONSTRAINT	reserved	reserved	reserved	reserved
+CONSTRAINTS	non-reserved	non-reserved	non-reserved	reserved
+CONSTRAINT_CATALOG	 	non-reserved	non-reserved	non-reserved
+CONSTRAINT_NAME	 	non-reserved	non-reserved	non-reserved
+CONSTRAINT_SCHEMA	 	non-reserved	non-reserved	non-reserved
+CONSTRUCTOR	 	non-reserved	non-reserved	 
+CONTAINS	 	reserved	non-reserved	 
+CONTENT	non-reserved	non-reserved	non-reserved	 
+CONTINUE	non-reserved	non-reserved	non-reserved	reserved
+CONTROL	 	non-reserved	non-reserved	 
+CONVERSION	non-reserved	 	 	 
+CONVERT	 	reserved	reserved	reserved
+COPY	non-reserved	 	 	 
+CORR	 	reserved	reserved	 
+CORRESPONDING	 	reserved	reserved	reserved
+COST	non-reserved	 	 	 
+COUNT	 	reserved	reserved	reserved
+COVAR_POP	 	reserved	reserved	 
+COVAR_SAMP	 	reserved	reserved	 
+CREATE	reserved	reserved	reserved	reserved
+CROSS	reserved (can be function or type)	reserved	reserved	reserved
+CSV	non-reserved	 	 	 
+CUBE	 	reserved	reserved	 
+CUME_DIST	 	reserved	reserved	 
+CURRENT	non-reserved	reserved	reserved	reserved
+CURRENT_CATALOG	reserved	reserved	reserved	 
+CURRENT_DATE	reserved	reserved	reserved	reserved
+CURRENT_DEFAULT_TRANSFORM_GROUP	 	reserved	reserved	 
+CURRENT_PATH	 	reserved	reserved	 
+CURRENT_ROLE	reserved	reserved	reserved	 
+CURRENT_ROW	 	reserved	 	 
+CURRENT_SCHEMA	reserved (can be function or type)	reserved	reserved	 
+CURRENT_TIME	reserved	reserved	reserved	reserved
+CURRENT_TIMESTAMP	reserved	reserved	reserved	reserved
+CURRENT_TRANSFORM_GROUP_FOR_TYPE	 	reserved	reserved	 
+CURRENT_USER	reserved	reserved	reserved	reserved
+CURSOR	non-reserved	reserved	reserved	reserved
+CURSOR_NAME	 	non-reserved	non-reserved	non-reserved
+CYCLE	non-reserved	reserved	reserved	 
+DATA	non-reserved	non-reserved	non-reserved	non-reserved
+DATABASE	non-reserved	 	 	 
+DATALINK	 	reserved	reserved	 
+DATE	 	reserved	reserved	reserved
+DATETIME_INTERVAL_CODE	 	non-reserved	non-reserved	non-reserved
+DATETIME_INTERVAL_PRECISION	 	non-reserved	non-reserved	non-reserved
+DAY	non-reserved	reserved	reserved	reserved
+DB	 	non-reserved	non-reserved	 
+DEALLOCATE	non-reserved	reserved	reserved	reserved
+DEC	non-reserved (cannot be function or type)	reserved	reserved	reserved
+DECIMAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
+DECLARE	non-reserved	reserved	reserved	reserved
+DEFAULT	reserved	reserved	reserved	reserved
+DEFAULTS	non-reserved	non-reserved	non-reserved	 
+DEFERRABLE	reserved	non-reserved	non-reserved	reserved
+DEFERRED	non-reserved	non-reserved	non-reserved	reserved
+DEFINED	 	non-reserved	non-reserved	 
+DEFINER	non-reserved	non-reserved	non-reserved	 
+DEGREE	 	non-reserved	non-reserved	 
+DELETE	non-reserved	reserved	reserved	reserved
+DELIMITER	non-reserved	 	 	 
+DELIMITERS	non-reserved	 	 	 
+DENSE_RANK	 	reserved	reserved	 
+DEPTH	 	non-reserved	non-reserved	 
+DEREF	 	reserved	reserved	 
+DERIVED	 	non-reserved	non-reserved	 
+DESC	reserved	non-reserved	non-reserved	reserved
+DESCRIBE	 	reserved	reserved	reserved
+DESCRIPTOR	 	non-reserved	non-reserved	reserved
+DETERMINISTIC	 	reserved	reserved	 
+DIAGNOSTICS	 	non-reserved	non-reserved	reserved
+DICTIONARY	non-reserved	 	 	 
+DISABLE	non-reserved	 	 	 
+DISCARD	non-reserved	 	 	 
+DISCONNECT	 	reserved	reserved	reserved
+DISPATCH	 	non-reserved	non-reserved	 
+DISTINCT	reserved	reserved	reserved	reserved
+DLNEWCOPY	 	reserved	reserved	 
+DLPREVIOUSCOPY	 	reserved	reserved	 
+DLURLCOMPLETE	 	reserved	reserved	 
+DLURLCOMPLETEONLY	 	reserved	reserved	 
+DLURLCOMPLETEWRITE	 	reserved	reserved	 
+DLURLPATH	 	reserved	reserved	 
+DLURLPATHONLY	 	reserved	reserved	 
+DLURLPATHWRITE	 	reserved	reserved	 
+DLURLSCHEME	 	reserved	reserved	 
+DLURLSERVER	 	reserved	reserved	 
+DLVALUE	 	reserved	reserved	 
+DO	reserved	 	 	 
+DOCUMENT	non-reserved	non-reserved	non-reserved	 
+DOMAIN	non-reserved	non-reserved	non-reserved	reserved
+DOUBLE	non-reserved	reserved	reserved	reserved
+DROP	non-reserved	reserved	reserved	reserved
+DYNAMIC	 	reserved	reserved	 
+DYNAMIC_FUNCTION	 	non-reserved	non-reserved	non-reserved
+DYNAMIC_FUNCTION_CODE	 	non-reserved	non-reserved	 
+EACH	non-reserved	reserved	reserved	 
+ELEMENT	 	reserved	reserved	 
+ELSE	reserved	reserved	reserved	reserved
+EMPTY	 	non-reserved	non-reserved	 
+ENABLE	non-reserved	 	 	 
+ENCODING	non-reserved	non-reserved	non-reserved	 
+ENCRYPTED	non-reserved	 	 	 
+END	reserved	reserved	reserved	reserved
+END-EXEC	 	reserved	reserved	reserved
+END_FRAME	 	reserved	 	 
+END_PARTITION	 	reserved	 	 
+ENFORCED	 	non-reserved	 	 
+ENUM	non-reserved	 	 	 
+EQUALS	 	reserved	non-reserved	 
+ESCAPE	non-reserved	reserved	reserved	reserved
+EVENT	non-reserved	 	 	 
+EVERY	 	reserved	reserved	 
+EXCEPT	reserved	reserved	reserved	reserved
+EXCEPTION	 	 	 	reserved
+EXCLUDE	non-reserved	non-reserved	non-reserved	 
+EXCLUDING	non-reserved	non-reserved	non-reserved	 
+EXCLUSIVE	non-reserved	 	 	 
+EXEC	 	reserved	reserved	reserved
+EXECUTE	non-reserved	reserved	reserved	reserved
+EXISTS	non-reserved (cannot be function or type)	reserved	reserved	reserved
+EXP	 	reserved	reserved	 
+EXPLAIN	non-reserved	 	 	 
+EXPRESSION	 	non-reserved	 	 
+EXTENSION	non-reserved	 	 	 
+EXTERNAL	non-reserved	reserved	reserved	reserved
+EXTRACT	non-reserved (cannot be function or type)	reserved	reserved	reserved
+FALSE	reserved	reserved	reserved	reserved
+FAMILY	non-reserved	 	 	 
+FETCH	reserved	reserved	reserved	reserved
+FILE	 	non-reserved	non-reserved	 
+FILTER	 	reserved	reserved	 
+FINAL	 	non-reserved	non-reserved	 
+FIRST	non-reserved	non-reserved	non-reserved	reserved
+FIRST_VALUE	 	reserved	reserved	 
+FLAG	 	non-reserved	non-reserved	 
+FLOAT	non-reserved (cannot be function or type)	reserved	reserved	reserved
+FLOOR	 	reserved	reserved	 
+FOLLOWING	non-reserved	non-reserved	non-reserved	 
+FOR	reserved	reserved	reserved	reserved
+FORCE	non-reserved	 	 	 
+FOREIGN	reserved	reserved	reserved	reserved
+FORTRAN	 	non-reserved	non-reserved	non-reserved
+FORWARD	non-reserved	 	 	 
+FOUND	 	non-reserved	non-reserved	reserved
+FRAME_ROW	 	reserved	 	 
+FREE	 	reserved	reserved	 
+FREEZE	reserved (can be function or type)	 	 	 
+FROM	reserved	reserved	reserved	reserved
+FS	 	non-reserved	non-reserved	 
+FULL	reserved (can be function or type)	reserved	reserved	reserved
+FUNCTION	non-reserved	reserved	reserved	 
+FUNCTIONS	non-reserved	 	 	 
+FUSION	 	reserved	reserved	 
+G	 	non-reserved	non-reserved	 
+GENERAL	 	non-reserved	non-reserved	 
+GENERATED	 	non-reserved	non-reserved	 
+GET	 	reserved	reserved	reserved
+GLOBAL	non-reserved	reserved	reserved	reserved
+GO	 	non-reserved	non-reserved	reserved
+GOTO	 	non-reserved	non-reserved	reserved
+GRANT	reserved	reserved	reserved	reserved
+GRANTED	non-reserved	non-reserved	non-reserved	 
+GREATEST	non-reserved (cannot be function or type)	 	 	 
+GROUP	reserved	reserved	reserved	reserved
+GROUPING	 	reserved	reserved	 
+GROUPS	 	reserved	 	 
+HANDLER	non-reserved	 	 	 
+HAVING	reserved	reserved	reserved	reserved
+HEADER	non-reserved	 	 	 
+HEX	 	non-reserved	non-reserved	 
+HIERARCHY	 	non-reserved	non-reserved	 
+HOLD	non-reserved	reserved	reserved	 
+HOUR	non-reserved	reserved	reserved	reserved
+ID	 	non-reserved	non-reserved	 
+IDENTITY	non-reserved	reserved	reserved	reserved
+IF	non-reserved	 	 	 
+IGNORE	 	non-reserved	non-reserved	 
+ILIKE	reserved (can be function or type)	 	 	 
+IMMEDIATE	non-reserved	non-reserved	non-reserved	reserved
+IMMEDIATELY	 	non-reserved	 	 
+IMMUTABLE	non-reserved	 	 	 
+IMPLEMENTATION	 	non-reserved	non-reserved	 
+IMPLICIT	non-reserved	 	 	 
+IMPORT	 	reserved	reserved	 
+IN	reserved	reserved	reserved	reserved
+INCLUDING	non-reserved	non-reserved	non-reserved	 
+INCREMENT	non-reserved	non-reserved	non-reserved	 
+INDENT	 	non-reserved	non-reserved	 
+INDEX	non-reserved	 	 	 
+INDEXES	non-reserved	 	 	 
+INDICATOR	 	reserved	reserved	reserved
+INHERIT	non-reserved	 	 	 
+INHERITS	non-reserved	 	 	 
+INITIALLY	reserved	non-reserved	non-reserved	reserved
+INLINE	non-reserved	 	 	 
+INNER	reserved (can be function or type)	reserved	reserved	reserved
+INOUT	non-reserved (cannot be function or type)	reserved	reserved	 
+INPUT	non-reserved	non-reserved	non-reserved	reserved
+INSENSITIVE	non-reserved	reserved	reserved	reserved
+INSERT	non-reserved	reserved	reserved	reserved
+INSTANCE	 	non-reserved	non-reserved	 
+INSTANTIABLE	 	non-reserved	non-reserved	 
+INSTEAD	non-reserved	non-reserved	non-reserved	 
+INT	non-reserved (cannot be function or type)	reserved	reserved	reserved
+INTEGER	non-reserved (cannot be function or type)	reserved	reserved	reserved
+INTEGRITY	 	non-reserved	non-reserved	 
+INTERSECT	reserved	reserved	reserved	reserved
+INTERSECTION	 	reserved	reserved	 
+INTERVAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
+INTO	reserved	reserved	reserved	reserved
+INVOKER	non-reserved	non-reserved	non-reserved	 
+IS	reserved (can be function or type)	reserved	reserved	reserved
+ISNULL	reserved (can be function or type)	 	 	 
+ISOLATION	non-reserved	non-reserved	non-reserved	reserved
+JOIN	reserved (can be function or type)	reserved	reserved	reserved
+K	 	non-reserved	non-reserved	 
+KEY	non-reserved	non-reserved	non-reserved	reserved
+KEY_MEMBER	 	non-reserved	non-reserved	 
+KEY_TYPE	 	non-reserved	non-reserved	 
+LABEL	non-reserved	 	 	 
+LAG	 	reserved	reserved	 
+LANGUAGE	non-reserved	reserved	reserved	reserved
+LARGE	non-reserved	reserved	reserved	 
+LAST	non-reserved	non-reserved	non-reserved	reserved
+LAST_VALUE	 	reserved	reserved	 
+LATERAL	reserved	reserved	reserved	 
+LC_COLLATE	non-reserved	 	 	 
+LC_CTYPE	non-reserved	 	 	 
+LEAD	 	reserved	reserved	 
+LEADING	reserved	reserved	reserved	reserved
+LEAKPROOF	non-reserved	 	 	 
+LEAST	non-reserved (cannot be function or type)	 	 	 
+LEFT	reserved (can be function or type)	reserved	reserved	reserved
+LENGTH	 	non-reserved	non-reserved	non-reserved
+LEVEL	non-reserved	non-reserved	non-reserved	reserved
+LIBRARY	 	non-reserved	non-reserved	 
+LIKE	reserved (can be function or type)	reserved	reserved	reserved
+LIKE_REGEX	 	reserved	reserved	 
+LIMIT	reserved	non-reserved	non-reserved	 
+LINK	 	non-reserved	non-reserved	 
+LISTEN	non-reserved	 	 	 
+LN	 	reserved	reserved	 
+LOAD	non-reserved	 	 	 
+LOCAL	non-reserved	reserved	reserved	reserved
+LOCALTIME	reserved	reserved	reserved	 
+LOCALTIMESTAMP	reserved	reserved	reserved	 
+LOCATION	non-reserved	non-reserved	non-reserved	 
+LOCATOR	 	non-reserved	non-reserved	 
+LOCK	non-reserved	 	 	 
+LOWER	 	reserved	reserved	reserved
+M	 	non-reserved	non-reserved	 
+MAP	 	non-reserved	non-reserved	 
+MAPPING	non-reserved	non-reserved	non-reserved	 
+MATCH	non-reserved	reserved	reserved	reserved
+MATCHED	 	non-reserved	non-reserved	 
+MATERIALIZED	non-reserved	 	 	 
+MAX	 	reserved	reserved	reserved
+MAXVALUE	non-reserved	non-reserved	non-reserved	 
+MAX_CARDINALITY	 	 	reserved	 
+MEMBER	 	reserved	reserved	 
+MERGE	 	reserved	reserved	 
+MESSAGE_LENGTH	 	non-reserved	non-reserved	non-reserved
+MESSAGE_OCTET_LENGTH	 	non-reserved	non-reserved	non-reserved
+MESSAGE_TEXT	 	non-reserved	non-reserved	non-reserved
+METHOD	 	reserved	reserved	 
+MIN	 	reserved	reserved	reserved
+MINUTE	non-reserved	reserved	reserved	reserved
+MINVALUE	non-reserved	non-reserved	non-reserved	 
+MOD	 	reserved	reserved	 
+MODE	non-reserved	 	 	 
+MODIFIES	 	reserved	reserved	 
+MODULE	 	reserved	reserved	reserved
+MONTH	non-reserved	reserved	reserved	reserved
+MORE	 	non-reserved	non-reserved	non-reserved
+MOVE	non-reserved	 	 	 
+MULTISET	 	reserved	reserved	 
+MUMPS	 	non-reserved	non-reserved	non-reserved
+NAME	non-reserved	non-reserved	non-reserved	non-reserved
+NAMES	non-reserved	non-reserved	non-reserved	reserved
+NAMESPACE	 	non-reserved	non-reserved	 
+NATIONAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
+NATURAL	reserved (can be function or type)	reserved	reserved	reserved
+NCHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
+NCLOB	 	reserved	reserved	 
+NESTING	 	non-reserved	non-reserved	 
+NEW	 	reserved	reserved	 
+NEXT	non-reserved	non-reserved	non-reserved	reserved
+NFC	 	non-reserved	non-reserved	 
+NFD	 	non-reserved	non-reserved	 
+NFKC	 	non-reserved	non-reserved	 
+NFKD	 	non-reserved	non-reserved	 
+NIL	 	non-reserved	non-reserved	 
+NO	non-reserved	reserved	reserved	reserved
+NONE	non-reserved (cannot be function or type)	reserved	reserved	 
+NORMALIZE	 	reserved	reserved	 
+NORMALIZED	 	non-reserved	non-reserved	 
+NOT	reserved	reserved	reserved	reserved
+NOTHING	non-reserved	 	 	 
+NOTIFY	non-reserved	 	 	 
+NOTNULL	reserved (can be function or type)	 	 	 
+NOWAIT	non-reserved	 	 	 
+NTH_VALUE	 	reserved	reserved	 
+NTILE	 	reserved	reserved	 
+NULL	reserved	reserved	reserved	reserved
+NULLABLE	 	non-reserved	non-reserved	non-reserved
+NULLIF	non-reserved (cannot be function or type)	reserved	reserved	reserved
+NULLS	non-reserved	non-reserved	non-reserved	 
+NUMBER	 	non-reserved	non-reserved	non-reserved
+NUMERIC	non-reserved (cannot be function or type)	reserved	reserved	reserved
+OBJECT	non-reserved	non-reserved	non-reserved	 
+OCCURRENCES_REGEX	 	reserved	reserved	 
+OCTETS	 	non-reserved	non-reserved	 
+OCTET_LENGTH	 	reserved	reserved	reserved
+OF	non-reserved	reserved	reserved	reserved
+OFF	non-reserved	non-reserved	non-reserved	 
+OFFSET	reserved	reserved	reserved	 
+OIDS	non-reserved	 	 	 
+OLD	 	reserved	reserved	 
+ON	reserved	reserved	reserved	reserved
+ONLY	reserved	reserved	reserved	reserved
+OPEN	 	reserved	reserved	reserved
+OPERATOR	non-reserved	 	 	 
+OPTION	non-reserved	non-reserved	non-reserved	reserved
+OPTIONS	non-reserved	non-reserved	non-reserved	 
+OR	reserved	reserved	reserved	reserved
+ORDER	reserved	reserved	reserved	reserved
+ORDERING	 	non-reserved	non-reserved	 
+ORDINALITY	 	non-reserved	non-reserved	 
+OTHERS	 	non-reserved	non-reserved	 
+OUT	non-reserved (cannot be function or type)	reserved	reserved	 
+OUTER	reserved (can be function or type)	reserved	reserved	reserved
+OUTPUT	 	non-reserved	non-reserved	reserved
+OVER	reserved (can be function or type)	reserved	reserved	 
+OVERLAPS	reserved (can be function or type)	reserved	reserved	reserved
+OVERLAY	non-reserved (cannot be function or type)	reserved	reserved	 
+OVERRIDING	 	non-reserved	non-reserved	 
+OWNED	non-reserved	 	 	 
+OWNER	non-reserved	 	 	 
+P	 	non-reserved	non-reserved	 
+PAD	 	non-reserved	non-reserved	reserved
+PARAMETER	 	reserved	reserved	 
+PARAMETER_MODE	 	non-reserved	non-reserved	 
+PARAMETER_NAME	 	non-reserved	non-reserved	 
+PARAMETER_ORDINAL_POSITION	 	non-reserved	non-reserved	 
+PARAMETER_SPECIFIC_CATALOG	 	non-reserved	non-reserved	 
+PARAMETER_SPECIFIC_NAME	 	non-reserved	non-reserved	 
+PARAMETER_SPECIFIC_SCHEMA	 	non-reserved	non-reserved	 
+PARSER	non-reserved	 	 	 
+PARTIAL	non-reserved	non-reserved	non-reserved	reserved
+PARTITION	non-reserved	reserved	reserved	 
+PASCAL	 	non-reserved	non-reserved	non-reserved
+PASSING	non-reserved	non-reserved	non-reserved	 
+PASSTHROUGH	 	non-reserved	non-reserved	 
+PASSWORD	non-reserved	 	 	 
+PATH	 	non-reserved	non-reserved	 
+PERCENT	 	reserved	 	 
+PERCENTILE_CONT	 	reserved	reserved	 
+PERCENTILE_DISC	 	reserved	reserved	 
+PERCENT_RANK	 	reserved	reserved	 
+PERIOD	 	reserved	 	 
+PERMISSION	 	non-reserved	non-reserved	 
+PLACING	reserved	non-reserved	non-reserved	 
+PLANS	non-reserved	 	 	 
+PLI	 	non-reserved	non-reserved	non-reserved
+PORTION	 	reserved	 	 
+POSITION	non-reserved (cannot be function or type)	reserved	reserved	reserved
+POSITION_REGEX	 	reserved	reserved	 
+POWER	 	reserved	reserved	 
+PRECEDES	 	reserved	 	 
+PRECEDING	non-reserved	non-reserved	non-reserved	 
+PRECISION	non-reserved (cannot be function or type)	reserved	reserved	reserved
+PREPARE	non-reserved	reserved	reserved	reserved
+PREPARED	non-reserved	 	 	 
+PRESERVE	non-reserved	non-reserved	non-reserved	reserved
+PRIMARY	reserved	reserved	reserved	reserved
+PRIOR	non-reserved	non-reserved	non-reserved	reserved
+PRIVILEGES	non-reserved	non-reserved	non-reserved	reserved
+PROCEDURAL	non-reserved	 	 	 
+PROCEDURE	non-reserved	reserved	reserved	reserved
+PROGRAM	non-reserved	 	 	 
+PUBLIC	 	non-reserved	non-reserved	reserved
+QUOTE	non-reserved	 	 	 
+RANGE	non-reserved	reserved	reserved	 
+RANK	 	reserved	reserved	 
+READ	non-reserved	non-reserved	non-reserved	reserved
+READS	 	reserved	reserved	 
+REAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
+REASSIGN	non-reserved	 	 	 
+RECHECK	non-reserved	 	 	 
+RECOVERY	 	non-reserved	non-reserved	 
+RECURSIVE	non-reserved	reserved	reserved	 
+REF	non-reserved	reserved	reserved	 
+REFERENCES	reserved	reserved	reserved	reserved
+REFERENCING	 	reserved	reserved	 
+REFRESH	non-reserved	 	 	 
+REGR_AVGX	 	reserved	reserved	 
+REGR_AVGY	 	reserved	reserved	 
+REGR_COUNT	 	reserved	reserved	 
+REGR_INTERCEPT	 	reserved	reserved	 
+REGR_R2	 	reserved	reserved	 
+REGR_SLOPE	 	reserved	reserved	 
+REGR_SXX	 	reserved	reserved	 
+REGR_SXY	 	reserved	reserved	 
+REGR_SYY	 	reserved	reserved	 
+REINDEX	non-reserved	 	 	 
+RELATIVE	non-reserved	non-reserved	non-reserved	reserved
+RELEASE	non-reserved	reserved	reserved	 
+RENAME	non-reserved	 	 	 
+REPEATABLE	non-reserved	non-reserved	non-reserved	non-reserved
+REPLACE	non-reserved	 	 	 
+REPLICA	non-reserved	 	 	 
+REQUIRING	 	non-reserved	non-reserved	 
+RESET	non-reserved	 	 	 
+RESPECT	 	non-reserved	non-reserved	 
+RESTART	non-reserved	non-reserved	non-reserved	 
+RESTORE	 	non-reserved	non-reserved	 
+RESTRICT	non-reserved	non-reserved	non-reserved	reserved
+RESULT	 	reserved	reserved	 
+RETURN	 	reserved	reserved	 
+RETURNED_CARDINALITY	 	non-reserved	non-reserved	 
+RETURNED_LENGTH	 	non-reserved	non-reserved	non-reserved
+RETURNED_OCTET_LENGTH	 	non-reserved	non-reserved	non-reserved
+RETURNED_SQLSTATE	 	non-reserved	non-reserved	non-reserved
+RETURNING	reserved	non-reserved	non-reserved	 
+RETURNS	non-reserved	reserved	reserved	 
+REVOKE	non-reserved	reserved	reserved	reserved
+RIGHT	reserved (can be function or type)	reserved	reserved	reserved
+ROLE	non-reserved	non-reserved	non-reserved	 
+ROLLBACK	non-reserved	reserved	reserved	reserved
+ROLLUP	 	reserved	reserved	 
+ROUTINE	 	non-reserved	non-reserved	 
+ROUTINE_CATALOG	 	non-reserved	non-reserved	 
+ROUTINE_NAME	 	non-reserved	non-reserved	 
+ROUTINE_SCHEMA	 	non-reserved	non-reserved	 
+ROW	non-reserved (cannot be function or type)	reserved	reserved	 
+ROWS	non-reserved	reserved	reserved	reserved
+ROW_COUNT	 	non-reserved	non-reserved	non-reserved
+ROW_NUMBER	 	reserved	reserved	 
+RULE	non-reserved	 	 	 
+SAVEPOINT	non-reserved	reserved	reserved	 
+SCALE	 	non-reserved	non-reserved	non-reserved
+SCHEMA	non-reserved	non-reserved	non-reserved	reserved
+SCHEMA_NAME	 	non-reserved	non-reserved	non-reserved
+SCOPE	 	reserved	reserved	 
+SCOPE_CATALOG	 	non-reserved	non-reserved	 
+SCOPE_NAME	 	non-reserved	non-reserved	 
+SCOPE_SCHEMA	 	non-reserved	non-reserved	 
+SCROLL	non-reserved	reserved	reserved	reserved
+SEARCH	non-reserved	reserved	reserved	 
+SECOND	non-reserved	reserved	reserved	reserved
+SECTION	 	non-reserved	non-reserved	reserved
+SECURITY	non-reserved	non-reserved	non-reserved	 
+SELECT	reserved	reserved	reserved	reserved
+SELECTIVE	 	non-reserved	non-reserved	 
+SELF	 	non-reserved	non-reserved	 
+SENSITIVE	 	reserved	reserved	 
+SEQUENCE	non-reserved	non-reserved	non-reserved	 
+SEQUENCES	non-reserved	 	 	 
+SERIALIZABLE	non-reserved	non-reserved	non-reserved	non-reserved
+SERVER	non-reserved	non-reserved	non-reserved	 
+SERVER_NAME	 	non-reserved	non-reserved	non-reserved
+SESSION	non-reserved	non-reserved	non-reserved	reserved
+SESSION_USER	reserved	reserved	reserved	reserved
+SET	non-reserved	reserved	reserved	reserved
+SETOF	non-reserved (cannot be function or type)	 	 	 
+SETS	 	non-reserved	non-reserved	 
+SHARE	non-reserved	 	 	 
+SHOW	non-reserved	 	 	 
+SIMILAR	reserved (can be function or type)	reserved	reserved	 
+SIMPLE	non-reserved	non-reserved	non-reserved	 
+SIZE	 	non-reserved	non-reserved	reserved
+SMALLINT	non-reserved (cannot be function or type)	reserved	reserved	reserved
+SNAPSHOT	non-reserved	 	 	 
+SOME	reserved	reserved	reserved	reserved
+SOURCE	 	non-reserved	non-reserved	 
+SPACE	 	non-reserved	non-reserved	reserved
+SPECIFIC	 	reserved	reserved	 
+SPECIFICTYPE	 	reserved	reserved	 
+SPECIFIC_NAME	 	non-reserved	non-reserved	 
+SQL	 	reserved	reserved	reserved
+SQLCODE	 	 	 	reserved
+SQLERROR	 	 	 	reserved
+SQLEXCEPTION	 	reserved	reserved	 
+SQLSTATE	 	reserved	reserved	reserved
+SQLWARNING	 	reserved	reserved	 
+SQRT	 	reserved	reserved	 
+STABLE	non-reserved	 	 	 
+STANDALONE	non-reserved	non-reserved	non-reserved	 
+START	non-reserved	reserved	reserved	 
+STATE	 	non-reserved	non-reserved	 
+STATEMENT	non-reserved	non-reserved	non-reserved	 
+STATIC	 	reserved	reserved	 
+STATISTICS	non-reserved	 	 	 
+STDDEV_POP	 	reserved	reserved	 
+STDDEV_SAMP	 	reserved	reserved	 
+STDIN	non-reserved	 	 	 
+STDOUT	non-reserved	 	 	 
+STORAGE	non-reserved	 	 	 
+STRICT	non-reserved	 	 	 
+STRIP	non-reserved	non-reserved	non-reserved	 
+STRUCTURE	 	non-reserved	non-reserved	 
+STYLE	 	non-reserved	non-reserved	 
+SUBCLASS_ORIGIN	 	non-reserved	non-reserved	non-reserved
+SUBMULTISET	 	reserved	reserved	 
+SUBSTRING	non-reserved (cannot be function or type)	reserved	reserved	reserved
+SUBSTRING_REGEX	 	reserved	reserved	 
+SUCCEEDS	 	reserved	 	 
+SUM	 	reserved	reserved	reserved
+SYMMETRIC	reserved	reserved	reserved	 
+SYSID	non-reserved	 	 	 
+SYSTEM	non-reserved	reserved	reserved	 
+SYSTEM_TIME	 	reserved	 	 
+SYSTEM_USER	 	reserved	reserved	reserved
+T	 	non-reserved	non-reserved	 
+TABLE	reserved	reserved	reserved	reserved
+TABLES	non-reserved	 	 	 
+TABLESAMPLE	 	reserved	reserved	 
+TABLESPACE	non-reserved	 	 	 
+TABLE_NAME	 	non-reserved	non-reserved	non-reserved
+TEMP	non-reserved	 	 	 
+TEMPLATE	non-reserved	 	 	 
+TEMPORARY	non-reserved	non-reserved	non-reserved	reserved
+TEXT	non-reserved	 	 	 
+THEN	reserved	reserved	reserved	reserved
+TIES	 	non-reserved	non-reserved	 
+TIME	non-reserved (cannot be function or type)	reserved	reserved	reserved
+TIMESTAMP	non-reserved (cannot be function or type)	reserved	reserved	reserved
+TIMEZONE_HOUR	 	reserved	reserved	reserved
+TIMEZONE_MINUTE	 	reserved	reserved	reserved
+TO	reserved	reserved	reserved	reserved
+TOKEN	 	non-reserved	non-reserved	 
+TOP_LEVEL_COUNT	 	non-reserved	non-reserved	 
+TRAILING	reserved	reserved	reserved	reserved
+TRANSACTION	non-reserved	non-reserved	non-reserved	reserved
+TRANSACTIONS_COMMITTED	 	non-reserved	non-reserved	 
+TRANSACTIONS_ROLLED_BACK	 	non-reserved	non-reserved	 
+TRANSACTION_ACTIVE	 	non-reserved	non-reserved	 
+TRANSFORM	 	non-reserved	non-reserved	 
+TRANSFORMS	 	non-reserved	non-reserved	 
+TRANSLATE	 	reserved	reserved	reserved
+TRANSLATE_REGEX	 	reserved	reserved	 
+TRANSLATION	 	reserved	reserved	reserved
+TREAT	non-reserved (cannot be function or type)	reserved	reserved	 
+TRIGGER	non-reserved	reserved	reserved	 
+TRIGGER_CATALOG	 	non-reserved	non-reserved	 
+TRIGGER_NAME	 	non-reserved	non-reserved	 
+TRIGGER_SCHEMA	 	non-reserved	non-reserved	 
+TRIM	non-reserved (cannot be function or type)	reserved	reserved	reserved
+TRIM_ARRAY	 	reserved	reserved	 
+TRUE	reserved	reserved	reserved	reserved
+TRUNCATE	non-reserved	reserved	reserved	 
+TRUSTED	non-reserved	 	 	 
+TYPE	non-reserved	non-reserved	non-reserved	non-reserved
+TYPES	non-reserved	 	 	 
+UESCAPE	 	reserved	reserved	 
+UNBOUNDED	non-reserved	non-reserved	non-reserved	 
+UNCOMMITTED	non-reserved	non-reserved	non-reserved	non-reserved
+UNDER	 	non-reserved	non-reserved	 
+UNENCRYPTED	non-reserved	 	 	 
+UNION	reserved	reserved	reserved	reserved
+UNIQUE	reserved	reserved	reserved	reserved
+UNKNOWN	non-reserved	reserved	reserved	reserved
+UNLINK	 	non-reserved	non-reserved	 
+UNLISTEN	non-reserved	 	 	 
+UNLOGGED	non-reserved	 	 	 
+UNNAMED	 	non-reserved	non-reserved	non-reserved
+UNNEST	 	reserved	reserved	 
+UNTIL	non-reserved	 	 	 
+UNTYPED	 	non-reserved	non-reserved	 
+UPDATE	non-reserved	reserved	reserved	reserved
+UPPER	 	reserved	reserved	reserved
+URI	 	non-reserved	non-reserved	 
+USAGE	 	non-reserved	non-reserved	reserved
+USER	reserved	reserved	reserved	reserved
+USER_DEFINED_TYPE_CATALOG	 	non-reserved	non-reserved	 
+USER_DEFINED_TYPE_CODE	 	non-reserved	non-reserved	 
+USER_DEFINED_TYPE_NAME	 	non-reserved	non-reserved	 
+USER_DEFINED_TYPE_SCHEMA	 	non-reserved	non-reserved	 
+USING	reserved	reserved	reserved	reserved
+VACUUM	non-reserved	 	 	 
+VALID	non-reserved	non-reserved	non-reserved	 
+VALIDATE	non-reserved	 	 	 
+VALIDATOR	non-reserved	 	 	 
+VALUE	non-reserved	reserved	reserved	reserved
+VALUES	non-reserved (cannot be function or type)	reserved	reserved	reserved
+VALUE_OF	 	reserved	 	 
+VARBINARY	 	reserved	reserved	 
+VARCHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
+VARIADIC	reserved	 	 	 
+VARYING	non-reserved	reserved	reserved	reserved
+VAR_POP	 	reserved	reserved	 
+VAR_SAMP	 	reserved	reserved	 
+VERBOSE	reserved (can be function or type)	 	 	 
+VERSION	non-reserved	non-reserved	non-reserved	 
+VERSIONING	 	reserved	 	 
+VIEW	non-reserved	non-reserved	non-reserved	reserved
+VOLATILE	non-reserved	 	 	 
+WHEN	reserved	reserved	reserved	reserved
+WHENEVER	 	reserved	reserved	reserved
+WHERE	reserved	reserved	reserved	reserved
+WHITESPACE	non-reserved	non-reserved	non-reserved	 
+WIDTH_BUCKET	 	reserved	reserved	 
+WINDOW	reserved	reserved	reserved	 
+WITH	reserved	reserved	reserved	reserved
+WITHIN	 	reserved	reserved	 
+WITHOUT	non-reserved	reserved	reserved	 
+WORK	non-reserved	non-reserved	non-reserved	reserved
+WRAPPER	non-reserved	non-reserved	non-reserved	 
+WRITE	non-reserved	non-reserved	non-reserved	reserved
+XML	non-reserved	reserved	reserved	 
+XMLAGG	 	reserved	reserved	 
+XMLATTRIBUTES	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLBINARY	 	reserved	reserved	 
+XMLCAST	 	reserved	reserved	 
+XMLCOMMENT	 	reserved	reserved	 
+XMLCONCAT	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLDECLARATION	 	non-reserved	non-reserved	 
+XMLDOCUMENT	 	reserved	reserved	 
+XMLELEMENT	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLEXISTS	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLFOREST	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLITERATE	 	reserved	reserved	 
+XMLNAMESPACES	 	reserved	reserved	 
+XMLPARSE	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLPI	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLQUERY	 	reserved	reserved	 
+XMLROOT	non-reserved (cannot be function or type)	 	 	 
+XMLSCHEMA	 	non-reserved	non-reserved	 
+XMLSERIALIZE	non-reserved (cannot be function or type)	reserved	reserved	 
+XMLTABLE	 	reserved	reserved	 
+XMLTEXT	 	reserved	reserved	 
+XMLVALIDATE	 	reserved	reserved	 
+YEAR	non-reserved	reserved	reserved	reserved
+YES	non-reserved	non-reserved	non-reserved	 
+ZONE	non-reserved	non-reserved	non-reserved	reserved

+ 1095 - 0
postgres_dialect.go

@@ -0,0 +1,1095 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	RegisterDialect("postgres", &postgres{})
+// }
+// from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
+var (
+	postgresReservedWords = map[string]bool{
+		"A":                     true,
+		"ABORT":                 true,
+		"ABS":                   true,
+		"ABSENT":                true,
+		"ABSOLUTE":              true,
+		"ACCESS":                true,
+		"ACCORDING":             true,
+		"ACTION":                true,
+		"ADA":                   true,
+		"ADD":                   true,
+		"ADMIN":                 true,
+		"AFTER":                 true,
+		"AGGREGATE":             true,
+		"ALL":                   true,
+		"ALLOCATE":              true,
+		"ALSO":                  true,
+		"ALTER":                 true,
+		"ALWAYS":                true,
+		"ANALYSE":               true,
+		"ANALYZE":               true,
+		"AND":                   true,
+		"ANY":                   true,
+		"ARE":                   true,
+		"ARRAY":                 true,
+		"ARRAY_AGG":             true,
+		"ARRAY_MAX_CARDINALITY": true,
+		"AS":                               true,
+		"ASC":                              true,
+		"ASENSITIVE":                       true,
+		"ASSERTION":                        true,
+		"ASSIGNMENT":                       true,
+		"ASYMMETRIC":                       true,
+		"AT":                               true,
+		"ATOMIC":                           true,
+		"ATTRIBUTE":                        true,
+		"ATTRIBUTES":                       true,
+		"AUTHORIZATION":                    true,
+		"AVG":                              true,
+		"BACKWARD":                         true,
+		"BASE64":                           true,
+		"BEFORE":                           true,
+		"BEGIN":                            true,
+		"BEGIN_FRAME":                      true,
+		"BEGIN_PARTITION":                  true,
+		"BERNOULLI":                        true,
+		"BETWEEN":                          true,
+		"BIGINT":                           true,
+		"BINARY":                           true,
+		"BIT":                              true,
+		"BIT_LENGTH":                       true,
+		"BLOB":                             true,
+		"BLOCKED":                          true,
+		"BOM":                              true,
+		"BOOLEAN":                          true,
+		"BOTH":                             true,
+		"BREADTH":                          true,
+		"BY":                               true,
+		"C":                                true,
+		"CACHE":                            true,
+		"CALL":                             true,
+		"CALLED":                           true,
+		"CARDINALITY":                      true,
+		"CASCADE":                          true,
+		"CASCADED":                         true,
+		"CASE":                             true,
+		"CAST":                             true,
+		"CATALOG":                          true,
+		"CATALOG_NAME":                     true,
+		"CEIL":                             true,
+		"CEILING":                          true,
+		"CHAIN":                            true,
+		"CHAR":                             true,
+		"CHARACTER":                        true,
+		"CHARACTERISTICS":                  true,
+		"CHARACTERS":                       true,
+		"CHARACTER_LENGTH":                 true,
+		"CHARACTER_SET_CATALOG":            true,
+		"CHARACTER_SET_NAME":               true,
+		"CHARACTER_SET_SCHEMA":             true,
+		"CHAR_LENGTH":                      true,
+		"CHECK":                            true,
+		"CHECKPOINT":                       true,
+		"CLASS":                            true,
+		"CLASS_ORIGIN":                     true,
+		"CLOB":                             true,
+		"CLOSE":                            true,
+		"CLUSTER":                          true,
+		"COALESCE":                         true,
+		"COBOL":                            true,
+		"COLLATE":                          true,
+		"COLLATION":                        true,
+		"COLLATION_CATALOG":                true,
+		"COLLATION_NAME":                   true,
+		"COLLATION_SCHEMA":                 true,
+		"COLLECT":                          true,
+		"COLUMN":                           true,
+		"COLUMNS":                          true,
+		"COLUMN_NAME":                      true,
+		"COMMAND_FUNCTION":                 true,
+		"COMMAND_FUNCTION_CODE":            true,
+		"COMMENT":                          true,
+		"COMMENTS":                         true,
+		"COMMIT":                           true,
+		"COMMITTED":                        true,
+		"CONCURRENTLY":                     true,
+		"CONDITION":                        true,
+		"CONDITION_NUMBER":                 true,
+		"CONFIGURATION":                    true,
+		"CONNECT":                          true,
+		"CONNECTION":                       true,
+		"CONNECTION_NAME":                  true,
+		"CONSTRAINT":                       true,
+		"CONSTRAINTS":                      true,
+		"CONSTRAINT_CATALOG":               true,
+		"CONSTRAINT_NAME":                  true,
+		"CONSTRAINT_SCHEMA":                true,
+		"CONSTRUCTOR":                      true,
+		"CONTAINS":                         true,
+		"CONTENT":                          true,
+		"CONTINUE":                         true,
+		"CONTROL":                          true,
+		"CONVERSION":                       true,
+		"CONVERT":                          true,
+		"COPY":                             true,
+		"CORR":                             true,
+		"CORRESPONDING":                    true,
+		"COST":                             true,
+		"COUNT":                            true,
+		"COVAR_POP":                        true,
+		"COVAR_SAMP":                       true,
+		"CREATE":                           true,
+		"CROSS":                            true,
+		"CSV":                              true,
+		"CUBE":                             true,
+		"CUME_DIST":                        true,
+		"CURRENT":                          true,
+		"CURRENT_CATALOG":                  true,
+		"CURRENT_DATE":                     true,
+		"CURRENT_DEFAULT_TRANSFORM_GROUP":  true,
+		"CURRENT_PATH":                     true,
+		"CURRENT_ROLE":                     true,
+		"CURRENT_ROW":                      true,
+		"CURRENT_SCHEMA":                   true,
+		"CURRENT_TIME":                     true,
+		"CURRENT_TIMESTAMP":                true,
+		"CURRENT_TRANSFORM_GROUP_FOR_TYPE": true,
+		"CURRENT_USER":                     true,
+		"CURSOR":                           true,
+		"CURSOR_NAME":                      true,
+		"CYCLE":                            true,
+		"DATA":                             true,
+		"DATABASE":                         true,
+		"DATALINK":                         true,
+		"DATE":                             true,
+		"DATETIME_INTERVAL_CODE":      true,
+		"DATETIME_INTERVAL_PRECISION": true,
+		"DAY":                        true,
+		"DB":                         true,
+		"DEALLOCATE":                 true,
+		"DEC":                        true,
+		"DECIMAL":                    true,
+		"DECLARE":                    true,
+		"DEFAULT":                    true,
+		"DEFAULTS":                   true,
+		"DEFERRABLE":                 true,
+		"DEFERRED":                   true,
+		"DEFINED":                    true,
+		"DEFINER":                    true,
+		"DEGREE":                     true,
+		"DELETE":                     true,
+		"DELIMITER":                  true,
+		"DELIMITERS":                 true,
+		"DENSE_RANK":                 true,
+		"DEPTH":                      true,
+		"DEREF":                      true,
+		"DERIVED":                    true,
+		"DESC":                       true,
+		"DESCRIBE":                   true,
+		"DESCRIPTOR":                 true,
+		"DETERMINISTIC":              true,
+		"DIAGNOSTICS":                true,
+		"DICTIONARY":                 true,
+		"DISABLE":                    true,
+		"DISCARD":                    true,
+		"DISCONNECT":                 true,
+		"DISPATCH":                   true,
+		"DISTINCT":                   true,
+		"DLNEWCOPY":                  true,
+		"DLPREVIOUSCOPY":             true,
+		"DLURLCOMPLETE":              true,
+		"DLURLCOMPLETEONLY":          true,
+		"DLURLCOMPLETEWRITE":         true,
+		"DLURLPATH":                  true,
+		"DLURLPATHONLY":              true,
+		"DLURLPATHWRITE":             true,
+		"DLURLSCHEME":                true,
+		"DLURLSERVER":                true,
+		"DLVALUE":                    true,
+		"DO":                         true,
+		"DOCUMENT":                   true,
+		"DOMAIN":                     true,
+		"DOUBLE":                     true,
+		"DROP":                       true,
+		"DYNAMIC":                    true,
+		"DYNAMIC_FUNCTION":           true,
+		"DYNAMIC_FUNCTION_CODE":      true,
+		"EACH":                       true,
+		"ELEMENT":                    true,
+		"ELSE":                       true,
+		"EMPTY":                      true,
+		"ENABLE":                     true,
+		"ENCODING":                   true,
+		"ENCRYPTED":                  true,
+		"END":                        true,
+		"END-EXEC":                   true,
+		"END_FRAME":                  true,
+		"END_PARTITION":              true,
+		"ENFORCED":                   true,
+		"ENUM":                       true,
+		"EQUALS":                     true,
+		"ESCAPE":                     true,
+		"EVENT":                      true,
+		"EVERY":                      true,
+		"EXCEPT":                     true,
+		"EXCEPTION":                  true,
+		"EXCLUDE":                    true,
+		"EXCLUDING":                  true,
+		"EXCLUSIVE":                  true,
+		"EXEC":                       true,
+		"EXECUTE":                    true,
+		"EXISTS":                     true,
+		"EXP":                        true,
+		"EXPLAIN":                    true,
+		"EXPRESSION":                 true,
+		"EXTENSION":                  true,
+		"EXTERNAL":                   true,
+		"EXTRACT":                    true,
+		"FALSE":                      true,
+		"FAMILY":                     true,
+		"FETCH":                      true,
+		"FILE":                       true,
+		"FILTER":                     true,
+		"FINAL":                      true,
+		"FIRST":                      true,
+		"FIRST_VALUE":                true,
+		"FLAG":                       true,
+		"FLOAT":                      true,
+		"FLOOR":                      true,
+		"FOLLOWING":                  true,
+		"FOR":                        true,
+		"FORCE":                      true,
+		"FOREIGN":                    true,
+		"FORTRAN":                    true,
+		"FORWARD":                    true,
+		"FOUND":                      true,
+		"FRAME_ROW":                  true,
+		"FREE":                       true,
+		"FREEZE":                     true,
+		"FROM":                       true,
+		"FS":                         true,
+		"FULL":                       true,
+		"FUNCTION":                   true,
+		"FUNCTIONS":                  true,
+		"FUSION":                     true,
+		"G":                          true,
+		"GENERAL":                    true,
+		"GENERATED":                  true,
+		"GET":                        true,
+		"GLOBAL":                     true,
+		"GO":                         true,
+		"GOTO":                       true,
+		"GRANT":                      true,
+		"GRANTED":                    true,
+		"GREATEST":                   true,
+		"GROUP":                      true,
+		"GROUPING":                   true,
+		"GROUPS":                     true,
+		"HANDLER":                    true,
+		"HAVING":                     true,
+		"HEADER":                     true,
+		"HEX":                        true,
+		"HIERARCHY":                  true,
+		"HOLD":                       true,
+		"HOUR":                       true,
+		"ID":                         true,
+		"IDENTITY":                   true,
+		"IF":                         true,
+		"IGNORE":                     true,
+		"ILIKE":                      true,
+		"IMMEDIATE":                  true,
+		"IMMEDIATELY":                true,
+		"IMMUTABLE":                  true,
+		"IMPLEMENTATION":             true,
+		"IMPLICIT":                   true,
+		"IMPORT":                     true,
+		"IN":                         true,
+		"INCLUDING":                  true,
+		"INCREMENT":                  true,
+		"INDENT":                     true,
+		"INDEX":                      true,
+		"INDEXES":                    true,
+		"INDICATOR":                  true,
+		"INHERIT":                    true,
+		"INHERITS":                   true,
+		"INITIALLY":                  true,
+		"INLINE":                     true,
+		"INNER":                      true,
+		"INOUT":                      true,
+		"INPUT":                      true,
+		"INSENSITIVE":                true,
+		"INSERT":                     true,
+		"INSTANCE":                   true,
+		"INSTANTIABLE":               true,
+		"INSTEAD":                    true,
+		"INT":                        true,
+		"INTEGER":                    true,
+		"INTEGRITY":                  true,
+		"INTERSECT":                  true,
+		"INTERSECTION":               true,
+		"INTERVAL":                   true,
+		"INTO":                       true,
+		"INVOKER":                    true,
+		"IS":                         true,
+		"ISNULL":                     true,
+		"ISOLATION":                  true,
+		"JOIN":                       true,
+		"K":                          true,
+		"KEY":                        true,
+		"KEY_MEMBER":                 true,
+		"KEY_TYPE":                   true,
+		"LABEL":                      true,
+		"LAG":                        true,
+		"LANGUAGE":                   true,
+		"LARGE":                      true,
+		"LAST":                       true,
+		"LAST_VALUE":                 true,
+		"LATERAL":                    true,
+		"LC_COLLATE":                 true,
+		"LC_CTYPE":                   true,
+		"LEAD":                       true,
+		"LEADING":                    true,
+		"LEAKPROOF":                  true,
+		"LEAST":                      true,
+		"LEFT":                       true,
+		"LENGTH":                     true,
+		"LEVEL":                      true,
+		"LIBRARY":                    true,
+		"LIKE":                       true,
+		"LIKE_REGEX":                 true,
+		"LIMIT":                      true,
+		"LINK":                       true,
+		"LISTEN":                     true,
+		"LN":                         true,
+		"LOAD":                       true,
+		"LOCAL":                      true,
+		"LOCALTIME":                  true,
+		"LOCALTIMESTAMP":             true,
+		"LOCATION":                   true,
+		"LOCATOR":                    true,
+		"LOCK":                       true,
+		"LOWER":                      true,
+		"M":                          true,
+		"MAP":                        true,
+		"MAPPING":                    true,
+		"MATCH":                      true,
+		"MATCHED":                    true,
+		"MATERIALIZED":               true,
+		"MAX":                        true,
+		"MAXVALUE":                   true,
+		"MAX_CARDINALITY":            true,
+		"MEMBER":                     true,
+		"MERGE":                      true,
+		"MESSAGE_LENGTH":             true,
+		"MESSAGE_OCTET_LENGTH":       true,
+		"MESSAGE_TEXT":               true,
+		"METHOD":                     true,
+		"MIN":                        true,
+		"MINUTE":                     true,
+		"MINVALUE":                   true,
+		"MOD":                        true,
+		"MODE":                       true,
+		"MODIFIES":                   true,
+		"MODULE":                     true,
+		"MONTH":                      true,
+		"MORE":                       true,
+		"MOVE":                       true,
+		"MULTISET":                   true,
+		"MUMPS":                      true,
+		"NAME":                       true,
+		"NAMES":                      true,
+		"NAMESPACE":                  true,
+		"NATIONAL":                   true,
+		"NATURAL":                    true,
+		"NCHAR":                      true,
+		"NCLOB":                      true,
+		"NESTING":                    true,
+		"NEW":                        true,
+		"NEXT":                       true,
+		"NFC":                        true,
+		"NFD":                        true,
+		"NFKC":                       true,
+		"NFKD":                       true,
+		"NIL":                        true,
+		"NO":                         true,
+		"NONE":                       true,
+		"NORMALIZE":                  true,
+		"NORMALIZED":                 true,
+		"NOT":                        true,
+		"NOTHING":                    true,
+		"NOTIFY":                     true,
+		"NOTNULL":                    true,
+		"NOWAIT":                     true,
+		"NTH_VALUE":                  true,
+		"NTILE":                      true,
+		"NULL":                       true,
+		"NULLABLE":                   true,
+		"NULLIF":                     true,
+		"NULLS":                      true,
+		"NUMBER":                     true,
+		"NUMERIC":                    true,
+		"OBJECT":                     true,
+		"OCCURRENCES_REGEX":          true,
+		"OCTETS":                     true,
+		"OCTET_LENGTH":               true,
+		"OF":                         true,
+		"OFF":                        true,
+		"OFFSET":                     true,
+		"OIDS":                       true,
+		"OLD":                        true,
+		"ON":                         true,
+		"ONLY":                       true,
+		"OPEN":                       true,
+		"OPERATOR":                   true,
+		"OPTION":                     true,
+		"OPTIONS":                    true,
+		"OR":                         true,
+		"ORDER":                      true,
+		"ORDERING":                   true,
+		"ORDINALITY":                 true,
+		"OTHERS":                     true,
+		"OUT":                        true,
+		"OUTER":                      true,
+		"OUTPUT":                     true,
+		"OVER":                       true,
+		"OVERLAPS":                   true,
+		"OVERLAY":                    true,
+		"OVERRIDING":                 true,
+		"OWNED":                      true,
+		"OWNER":                      true,
+		"P":                          true,
+		"PAD":                        true,
+		"PARAMETER":                  true,
+		"PARAMETER_MODE":             true,
+		"PARAMETER_NAME":             true,
+		"PARAMETER_ORDINAL_POSITION": true,
+		"PARAMETER_SPECIFIC_CATALOG": true,
+		"PARAMETER_SPECIFIC_NAME":    true,
+		"PARAMETER_SPECIFIC_SCHEMA":  true,
+		"PARSER":                     true,
+		"PARTIAL":                    true,
+		"PARTITION":                  true,
+		"PASCAL":                     true,
+		"PASSING":                    true,
+		"PASSTHROUGH":                true,
+		"PASSWORD":                   true,
+		"PATH":                       true,
+		"PERCENT":                    true,
+		"PERCENTILE_CONT":            true,
+		"PERCENTILE_DISC":            true,
+		"PERCENT_RANK":               true,
+		"PERIOD":                     true,
+		"PERMISSION":                 true,
+		"PLACING":                    true,
+		"PLANS":                      true,
+		"PLI":                        true,
+		"PORTION":                    true,
+		"POSITION":                   true,
+		"POSITION_REGEX":             true,
+		"POWER":                      true,
+		"PRECEDES":                   true,
+		"PRECEDING":                  true,
+		"PRECISION":                  true,
+		"PREPARE":                    true,
+		"PREPARED":                   true,
+		"PRESERVE":                   true,
+		"PRIMARY":                    true,
+		"PRIOR":                      true,
+		"PRIVILEGES":                 true,
+		"PROCEDURAL":                 true,
+		"PROCEDURE":                  true,
+		"PROGRAM":                    true,
+		"PUBLIC":                     true,
+		"QUOTE":                      true,
+		"RANGE":                      true,
+		"RANK":                       true,
+		"READ":                       true,
+		"READS":                      true,
+		"REAL":                       true,
+		"REASSIGN":                   true,
+		"RECHECK":                    true,
+		"RECOVERY":                   true,
+		"RECURSIVE":                  true,
+		"REF":                        true,
+		"REFERENCES":                 true,
+		"REFERENCING":                true,
+		"REFRESH":                    true,
+		"REGR_AVGX":                  true,
+		"REGR_AVGY":                  true,
+		"REGR_COUNT":                 true,
+		"REGR_INTERCEPT":             true,
+		"REGR_R2":                    true,
+		"REGR_SLOPE":                 true,
+		"REGR_SXX":                   true,
+		"REGR_SXY":                   true,
+		"REGR_SYY":                   true,
+		"REINDEX":                    true,
+		"RELATIVE":                   true,
+		"RELEASE":                    true,
+		"RENAME":                     true,
+		"REPEATABLE":                 true,
+		"REPLACE":                    true,
+		"REPLICA":                    true,
+		"REQUIRING":                  true,
+		"RESET":                      true,
+		"RESPECT":                    true,
+		"RESTART":                    true,
+		"RESTORE":                    true,
+		"RESTRICT":                   true,
+		"RESULT":                     true,
+		"RETURN":                     true,
+		"RETURNED_CARDINALITY":       true,
+		"RETURNED_LENGTH":            true,
+		"RETURNED_OCTET_LENGTH":      true,
+		"RETURNED_SQLSTATE":          true,
+		"RETURNING":                  true,
+		"RETURNS":                    true,
+		"REVOKE":                     true,
+		"RIGHT":                      true,
+		"ROLE":                       true,
+		"ROLLBACK":                   true,
+		"ROLLUP":                     true,
+		"ROUTINE":                    true,
+		"ROUTINE_CATALOG":            true,
+		"ROUTINE_NAME":               true,
+		"ROUTINE_SCHEMA":             true,
+		"ROW":                        true,
+		"ROWS":                       true,
+		"ROW_COUNT":                  true,
+		"ROW_NUMBER":                 true,
+		"RULE":                       true,
+		"SAVEPOINT":                  true,
+		"SCALE":                      true,
+		"SCHEMA":                     true,
+		"SCHEMA_NAME":                true,
+		"SCOPE":                      true,
+		"SCOPE_CATALOG":              true,
+		"SCOPE_NAME":                 true,
+		"SCOPE_SCHEMA":               true,
+		"SCROLL":                     true,
+		"SEARCH":                     true,
+		"SECOND":                     true,
+		"SECTION":                    true,
+		"SECURITY":                   true,
+		"SELECT":                     true,
+		"SELECTIVE":                  true,
+		"SELF":                       true,
+		"SENSITIVE":                  true,
+		"SEQUENCE":                   true,
+		"SEQUENCES":                  true,
+		"SERIALIZABLE":               true,
+		"SERVER":                     true,
+		"SERVER_NAME":                true,
+		"SESSION":                    true,
+		"SESSION_USER":               true,
+		"SET":                        true,
+		"SETOF":                      true,
+		"SETS":                       true,
+		"SHARE":                      true,
+		"SHOW":                       true,
+		"SIMILAR":                    true,
+		"SIMPLE":                     true,
+		"SIZE":                       true,
+		"SMALLINT":                   true,
+		"SNAPSHOT":                   true,
+		"SOME":                       true,
+		"SOURCE":                     true,
+		"SPACE":                      true,
+		"SPECIFIC":                   true,
+		"SPECIFICTYPE":               true,
+		"SPECIFIC_NAME":              true,
+		"SQL":                        true,
+		"SQLCODE":                    true,
+		"SQLERROR":                   true,
+		"SQLEXCEPTION":               true,
+		"SQLSTATE":                   true,
+		"SQLWARNING":                 true,
+		"SQRT":                       true,
+		"STABLE":                     true,
+		"STANDALONE":                 true,
+		"START":                      true,
+		"STATE":                      true,
+		"STATEMENT":                  true,
+		"STATIC":                     true,
+		"STATISTICS":                 true,
+		"STDDEV_POP":                 true,
+		"STDDEV_SAMP":                true,
+		"STDIN":                      true,
+		"STDOUT":                     true,
+		"STORAGE":                    true,
+		"STRICT":                     true,
+		"STRIP":                      true,
+		"STRUCTURE":                  true,
+		"STYLE":                      true,
+		"SUBCLASS_ORIGIN":            true,
+		"SUBMULTISET":                true,
+		"SUBSTRING":                  true,
+		"SUBSTRING_REGEX":            true,
+		"SUCCEEDS":                   true,
+		"SUM":                        true,
+		"SYMMETRIC":                  true,
+		"SYSID":                      true,
+		"SYSTEM":                     true,
+		"SYSTEM_TIME":                true,
+		"SYSTEM_USER":                true,
+		"T":                          true,
+		"TABLE":                      true,
+		"TABLES":                     true,
+		"TABLESAMPLE":                true,
+		"TABLESPACE":                 true,
+		"TABLE_NAME":                 true,
+		"TEMP":                       true,
+		"TEMPLATE":                   true,
+		"TEMPORARY":                  true,
+		"TEXT":                       true,
+		"THEN":                       true,
+		"TIES":                       true,
+		"TIME":                       true,
+		"TIMESTAMP":                  true,
+		"TIMEZONE_HOUR":              true,
+		"TIMEZONE_MINUTE":            true,
+		"TO":                         true,
+		"TOKEN":                      true,
+		"TOP_LEVEL_COUNT":            true,
+		"TRAILING":                   true,
+		"TRANSACTION":                true,
+		"TRANSACTIONS_COMMITTED":     true,
+		"TRANSACTIONS_ROLLED_BACK":   true,
+		"TRANSACTION_ACTIVE":         true,
+		"TRANSFORM":                  true,
+		"TRANSFORMS":                 true,
+		"TRANSLATE":                  true,
+		"TRANSLATE_REGEX":            true,
+		"TRANSLATION":                true,
+		"TREAT":                      true,
+		"TRIGGER":                    true,
+		"TRIGGER_CATALOG":            true,
+		"TRIGGER_NAME":               true,
+		"TRIGGER_SCHEMA":             true,
+		"TRIM":                       true,
+		"TRIM_ARRAY":                 true,
+		"TRUE":                       true,
+		"TRUNCATE":                   true,
+		"TRUSTED":                    true,
+		"TYPE":                       true,
+		"TYPES":                      true,
+		"UESCAPE":                    true,
+		"UNBOUNDED":                  true,
+		"UNCOMMITTED":                true,
+		"UNDER":                      true,
+		"UNENCRYPTED":                true,
+		"UNION":                      true,
+		"UNIQUE":                     true,
+		"UNKNOWN":                    true,
+		"UNLINK":                     true,
+		"UNLISTEN":                   true,
+		"UNLOGGED":                   true,
+		"UNNAMED":                    true,
+		"UNNEST":                     true,
+		"UNTIL":                      true,
+		"UNTYPED":                    true,
+		"UPDATE":                     true,
+		"UPPER":                      true,
+		"URI":                        true,
+		"USAGE":                      true,
+		"USER":                       true,
+		"USER_DEFINED_TYPE_CATALOG": true,
+		"USER_DEFINED_TYPE_CODE":    true,
+		"USER_DEFINED_TYPE_NAME":    true,
+		"USER_DEFINED_TYPE_SCHEMA":  true,
+		"USING":                     true,
+		"VACUUM":                    true,
+		"VALID":                     true,
+		"VALIDATE":                  true,
+		"VALIDATOR":                 true,
+		"VALUE":                     true,
+		"VALUES":                    true,
+		"VALUE_OF":                  true,
+		"VARBINARY":                 true,
+		"VARCHAR":                   true,
+		"VARIADIC":                  true,
+		"VARYING":                   true,
+		"VAR_POP":                   true,
+		"VAR_SAMP":                  true,
+		"VERBOSE":                   true,
+		"VERSION":                   true,
+		"VERSIONING":                true,
+		"VIEW":                      true,
+		"VOLATILE":                  true,
+		"WHEN":                      true,
+		"WHENEVER":                  true,
+		"WHERE":                     true,
+		"WHITESPACE":                true,
+		"WIDTH_BUCKET":              true,
+		"WINDOW":                    true,
+		"WITH":                      true,
+		"WITHIN":                    true,
+		"WITHOUT":                   true,
+		"WORK":                      true,
+		"WRAPPER":                   true,
+		"WRITE":                     true,
+		"XML":                       true,
+		"XMLAGG":                    true,
+		"XMLATTRIBUTES":             true,
+		"XMLBINARY":                 true,
+		"XMLCAST":                   true,
+		"XMLCOMMENT":                true,
+		"XMLCONCAT":                 true,
+		"XMLDECLARATION":            true,
+		"XMLDOCUMENT":               true,
+		"XMLELEMENT":                true,
+		"XMLEXISTS":                 true,
+		"XMLFOREST":                 true,
+		"XMLITERATE":                true,
+		"XMLNAMESPACES":             true,
+		"XMLPARSE":                  true,
+		"XMLPI":                     true,
+		"XMLQUERY":                  true,
+		"XMLROOT":                   true,
+		"XMLSCHEMA":                 true,
+		"XMLSERIALIZE":              true,
+		"XMLTABLE":                  true,
+		"XMLTEXT":                   true,
+		"XMLVALIDATE":               true,
+		"YEAR":                      true,
+		"YES":                       true,
+		"ZONE":                      true,
+	}
+)
+
+type postgres struct {
+	core.Base
+}
+
+func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *postgres) SqlType(c *core.Column) string {
+	var res string
+	switch t := c.SQLType.Name; t {
+	case core.TinyInt:
+		res = core.SmallInt
+		return res
+	case core.MediumInt, core.Int, core.Integer:
+		if c.IsAutoIncrement {
+			return core.Serial
+		}
+		return core.Integer
+	case core.Serial, core.BigSerial:
+		c.IsAutoIncrement = true
+		c.Nullable = false
+		res = t
+	case core.Binary, core.VarBinary:
+		return core.Bytea
+	case core.DateTime:
+		res = core.TimeStamp
+	case core.TimeStampz:
+		return "timestamp with time zone"
+	case core.Float:
+		res = core.Real
+	case core.TinyText, core.MediumText, core.LongText:
+		res = core.Text
+	case core.NVarchar:
+		res = core.Varchar
+	case core.Uuid:
+		res = core.Uuid
+	case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob:
+		return core.Bytea
+	case core.Double:
+		return "DOUBLE PRECISION"
+	default:
+		if c.IsAutoIncrement {
+			return core.Serial
+		}
+		res = t
+	}
+
+	var hasLen1 bool = (c.Length > 0)
+	var hasLen2 bool = (c.Length2 > 0)
+	if hasLen2 {
+		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
+	} else if hasLen1 {
+		res += "(" + strconv.Itoa(c.Length) + ")"
+	}
+	return res
+}
+
+func (db *postgres) SupportInsertMany() bool {
+	return true
+}
+
+func (db *postgres) IsReserved(name string) bool {
+	_, ok := postgresReservedWords[name]
+	return ok
+}
+
+func (db *postgres) Quote(name string) string {
+	return "\"" + name + "\""
+}
+
+func (db *postgres) QuoteStr() string {
+	return "\""
+}
+
+func (db *postgres) AutoIncrStr() string {
+	return ""
+}
+
+func (db *postgres) SupportEngine() bool {
+	return false
+}
+
+func (db *postgres) SupportCharset() bool {
+	return false
+}
+
+func (db *postgres) IndexOnTable() bool {
+	return false
+}
+
+func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{tableName, idxName}
+	return `SELECT indexname FROM pg_indexes ` +
+		`WHERE tablename = ? AND indexname = ?`, args
+}
+
+func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
+}
+
+/*func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{tableName, colName}
+	return "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ?" +
+		" AND column_name = ?", args
+}*/
+
+func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string {
+	return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
+		tableName, col.Name, db.SqlType(col))
+}
+
+func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
+	quote := db.Quote
+	//var unique string
+	var idxName string = index.Name
+	if !strings.HasPrefix(idxName, "UQE_") &&
+		!strings.HasPrefix(idxName, "IDX_") {
+		if index.Type == core.UniqueType {
+			idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
+		} else {
+			idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
+		}
+	}
+	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
+}
+
+func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
+	args := []interface{}{tableName, colName}
+	query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
+		" AND column_name = $2"
+	rows, err := db.DB().Query(query, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", query, args)
+	}
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	return rows.Next(), nil
+}
+
+func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{tableName}
+	s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
+    CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
+    CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
+FROM pg_attribute f
+    JOIN pg_class c ON c.oid = f.attrelid JOIN pg_type t ON t.oid = f.atttypid
+    LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum
+    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
+    LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
+    LEFT JOIN pg_class AS g ON p.confrelid = g.oid
+    LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
+WHERE c.relkind = 'r'::char AND c.relname = $1 AND f.attnum > 0 ORDER BY f.attnum;`
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+
+	for rows.Next() {
+		col := new(core.Column)
+		col.Indexes = make(map[string]bool)
+
+		var colName, isNullable, dataType string
+		var maxLenStr, colDefault, numPrecision, numRadix *string
+		var isPK, isUnique bool
+		err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &numPrecision, &numRadix, &isPK, &isUnique)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		//fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, numPrecision, numRadix, isPK, isUnique)
+		var maxLen int
+		if maxLenStr != nil {
+			maxLen, err = strconv.Atoi(*maxLenStr)
+			if err != nil {
+				return nil, nil, err
+			}
+		}
+
+		col.Name = strings.Trim(colName, `" `)
+
+		if colDefault != nil || isPK {
+			if isPK {
+				col.IsPrimaryKey = true
+			} else {
+				col.Default = *colDefault
+			}
+		}
+
+		if colDefault != nil && strings.HasPrefix(*colDefault, "nextval(") {
+			col.IsAutoIncrement = true
+		}
+
+		col.Nullable = (isNullable == "YES")
+
+		switch dataType {
+		case "character varying", "character":
+			col.SQLType = core.SQLType{core.Varchar, 0, 0}
+		case "timestamp without time zone":
+			col.SQLType = core.SQLType{core.DateTime, 0, 0}
+		case "timestamp with time zone":
+			col.SQLType = core.SQLType{core.TimeStampz, 0, 0}
+		case "double precision":
+			col.SQLType = core.SQLType{core.Double, 0, 0}
+		case "boolean":
+			col.SQLType = core.SQLType{core.Bool, 0, 0}
+		case "time without time zone":
+			col.SQLType = core.SQLType{core.Time, 0, 0}
+		default:
+			col.SQLType = core.SQLType{strings.ToUpper(dataType), 0, 0}
+		}
+		if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
+			return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", dataType))
+		}
+
+		col.Length = maxLen
+
+		if col.SQLType.IsText() || col.SQLType.IsTime() {
+			if col.Default != "" {
+				col.Default = "'" + col.Default + "'"
+			} else {
+				if col.DefaultIsEmpty {
+					col.Default = "''"
+				}
+			}
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+
+	return colSeq, cols, nil
+}
+
+func (db *postgres) GetTables() ([]*core.Table, error) {
+	args := []interface{}{}
+	s := "SELECT tablename FROM pg_tables where schemaname = 'public'"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		var name string
+		err = rows.Scan(&name)
+		if err != nil {
+			return nil, err
+		}
+		table.Name = name
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{tableName}
+	s := "SELECT indexname, indexdef FROM pg_indexes WHERE schemaname='public' AND tablename=$1"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var indexType int
+		var indexName, indexdef string
+		var colNames []string
+		err = rows.Scan(&indexName, &indexdef)
+		if err != nil {
+			return nil, err
+		}
+		indexName = strings.Trim(indexName, `" `)
+		if strings.HasSuffix(indexName, "_pkey") {
+			continue
+		}
+		if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
+			indexType = core.UniqueType
+		} else {
+			indexType = core.IndexType
+		}
+		cs := strings.Split(indexdef, "(")
+		colNames = strings.Split(cs[1][0:len(cs[1])-1], ",")
+
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			newIdxName := indexName[5+len(tableName) : len(indexName)]
+			if newIdxName != "" {
+				indexName = newIdxName
+			}
+		}
+
+		index := &core.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
+		for _, colName := range colNames {
+			index.Cols = append(index.Cols, strings.Trim(colName, `" `))
+		}
+		indexes[index.Name] = index
+	}
+	return indexes, nil
+}
+
+func (db *postgres) Filters() []core.Filter {
+	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{"$", 1}}
+}

+ 119 - 0
pq_driver.go

@@ -0,0 +1,119 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"net/url"
+	"sort"
+	"strings"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	core.RegisterDriver("postgres", &pqDriver{})
+// }
+
+type pqDriver struct {
+}
+
+type values map[string]string
+
+func (vs values) Set(k, v string) {
+	vs[k] = v
+}
+
+func (vs values) Get(k string) (v string) {
+	return vs[k]
+}
+
+func errorf(s string, args ...interface{}) {
+	panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
+}
+
+func parseURL(connstr string) (string, error) {
+	u, err := url.Parse(connstr)
+	if err != nil {
+		return "", err
+	}
+
+	if u.Scheme != "postgres" {
+		return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
+	}
+
+	var kvs []string
+	escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
+	accrue := func(k, v string) {
+		if v != "" {
+			kvs = append(kvs, k+"="+escaper.Replace(v))
+		}
+	}
+
+	if u.User != nil {
+		v := u.User.Username()
+		accrue("user", v)
+
+		v, _ = u.User.Password()
+		accrue("password", v)
+	}
+
+	i := strings.Index(u.Host, ":")
+	if i < 0 {
+		accrue("host", u.Host)
+	} else {
+		accrue("host", u.Host[:i])
+		accrue("port", u.Host[i+1:])
+	}
+
+	if u.Path != "" {
+		accrue("dbname", u.Path[1:])
+	}
+
+	q := u.Query()
+	for k := range q {
+		accrue(k, q.Get(k))
+	}
+
+	sort.Strings(kvs) // Makes testing easier (not a performance concern)
+	return strings.Join(kvs, " "), nil
+}
+
+func parseOpts(name string, o values) {
+	if len(name) == 0 {
+		return
+	}
+
+	name = strings.TrimSpace(name)
+
+	ps := strings.Split(name, " ")
+	for _, p := range ps {
+		kv := strings.Split(p, "=")
+		if len(kv) < 2 {
+			errorf("invalid option: %q", p)
+		}
+		o.Set(kv[0], kv[1])
+	}
+}
+
+func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	db := &core.Uri{DbType: core.POSTGRES}
+	o := make(values)
+	var err error
+	if strings.HasPrefix(dataSourceName, "postgres://") {
+		dataSourceName, err = parseURL(dataSourceName)
+		if err != nil {
+			return nil, err
+		}
+	}
+	parseOpts(dataSourceName, o)
+
+	db.DbName = o.Get("dbname")
+	if db.DbName == "" {
+		return nil, errors.New("dbname is empty")
+	}
+	return db, nil
+}

+ 46 - 0
processors.go

@@ -0,0 +1,46 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+// Executed before an object is initially persisted to the database
+type BeforeInsertProcessor interface {
+	BeforeInsert()
+}
+
+// Executed before an object is updated
+type BeforeUpdateProcessor interface {
+	BeforeUpdate()
+}
+
+// Executed before an object is deleted
+type BeforeDeleteProcessor interface {
+	BeforeDelete()
+}
+
+type BeforeSetProcessor interface {
+	BeforeSet(string, Cell)
+}
+
+// !nashtsai! TODO enable BeforeValidateProcessor when xorm start to support validations
+//// Executed before an object is validated
+//type BeforeValidateProcessor interface {
+//    BeforeValidate()
+//}
+// --
+
+// Executed after an object is persisted to the database
+type AfterInsertProcessor interface {
+	AfterInsert()
+}
+
+// Executed after an object has been updated
+type AfterUpdateProcessor interface {
+	AfterUpdate()
+}
+
+// Executed after an object has been deleted
+type AfterDeleteProcessor interface {
+	AfterDelete()
+}

+ 145 - 0
rows.go

@@ -0,0 +1,145 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"database/sql"
+	"fmt"
+	"reflect"
+
+	"github.com/xormplus/core"
+)
+
+type Rows struct {
+	NoTypeCheck bool
+
+	session     *Session
+	stmt        *core.Stmt
+	rows        *core.Rows
+	fields      []string
+	fieldsCount int
+	beanType    reflect.Type
+	lastError   error
+}
+
+func newRows(session *Session, bean interface{}) (*Rows, error) {
+	rows := new(Rows)
+	rows.session = session
+	rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
+
+	defer rows.session.Statement.Init()
+
+	var sqlStr string
+	var args []interface{}
+	rows.session.Statement.RefTable = rows.session.Engine.TableInfo(bean)
+	if rows.session.Statement.RawSQL == "" {
+		sqlStr, args = rows.session.Statement.genGetSql(bean)
+	} else {
+		sqlStr = rows.session.Statement.RawSQL
+		args = rows.session.Statement.RawParams
+	}
+
+	for _, filter := range rows.session.Engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, rows.session.Statement.RefTable)
+	}
+
+	rows.session.Engine.logSQL(sqlStr, args)
+	var err error
+	rows.stmt, err = rows.session.DB().Prepare(sqlStr)
+	if err != nil {
+		rows.lastError = err
+		defer rows.Close()
+		return nil, err
+	}
+
+	rows.rows, err = rows.stmt.Query(args...)
+	if err != nil {
+		rows.lastError = err
+		defer rows.Close()
+		return nil, err
+	}
+
+	rows.fields, err = rows.rows.Columns()
+	if err != nil {
+		rows.lastError = err
+		defer rows.Close()
+		return nil, err
+	}
+	rows.fieldsCount = len(rows.fields)
+
+	return rows, nil
+}
+
+// move cursor to next record, return false if end has reached
+func (rows *Rows) Next() bool {
+	if rows.lastError == nil && rows.rows != nil {
+		hasNext := rows.rows.Next()
+		if !hasNext {
+			rows.lastError = sql.ErrNoRows
+		}
+		return hasNext
+	}
+	return false
+}
+
+// Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close.
+func (rows *Rows) Err() error {
+	return rows.lastError
+}
+
+// scan row record to bean properties
+func (rows *Rows) Scan(bean interface{}) error {
+	if rows.lastError != nil {
+		return rows.lastError
+	}
+
+	if !rows.NoTypeCheck && reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType {
+		return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
+	}
+
+	return rows.session.row2Bean(rows.rows, rows.fields, rows.fieldsCount, bean)
+
+	// result, err := row2map(rows.rows, rows.fields) // !nashtsai! TODO remove row2map then scanMapIntoStruct conversation for better performance
+	// if err == nil {
+	// 	err = rows.session.scanMapIntoStruct(bean, result)
+	// }
+	// return err
+}
+
+// // Columns returns the column names. Columns returns an error if the rows are closed, or if the rows are from QueryRow and there was a deferred error.
+// func (rows *Rows) Columns() ([]string, error) {
+// 	if rows.lastError == nil && rows.rows != nil {
+// 		return rows.rows.Columns()
+// 	}
+// 	return nil, rows.lastError
+// }
+
+// close session if session.IsAutoClose is true, and claimed any opened resources
+func (rows *Rows) Close() error {
+	if rows.session.IsAutoClose {
+		defer rows.session.Close()
+	}
+
+	if rows.lastError == nil {
+		if rows.rows != nil {
+			rows.lastError = rows.rows.Close()
+			if rows.lastError != nil {
+				defer rows.stmt.Close()
+				return rows.lastError
+			}
+		}
+		if rows.stmt != nil {
+			rows.lastError = rows.stmt.Close()
+		}
+	} else {
+		if rows.stmt != nil {
+			defer rows.stmt.Close()
+		}
+		if rows.rows != nil {
+			defer rows.rows.Close()
+		}
+	}
+	return rows.lastError
+}

+ 4055 - 0
session.go

@@ -0,0 +1,4055 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"database/sql"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"hash/crc32"
+	"reflect"
+
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+// Struct Session keep a pointer to sql.DB and provides all execution of all
+// kind of database operations.
+type Session struct {
+	db                     *core.DB
+	Engine                 *Engine
+	Tx                     *core.Tx
+	Statement              Statement
+	IsAutoCommit           bool
+	IsCommitedOrRollbacked bool
+	TransType              string
+	IsAutoClose            bool
+
+	// Automatically reset the statement after operations that execute a SQL
+	// query such as Count(), Find(), Get(), ...
+	AutoResetStatement bool
+
+	// !nashtsai! storing these beans due to yet committed tx
+	afterInsertBeans map[interface{}]*[]func(interface{})
+	afterUpdateBeans map[interface{}]*[]func(interface{})
+	afterDeleteBeans map[interface{}]*[]func(interface{})
+	// --
+
+	beforeClosures []func(interface{})
+	afterClosures  []func(interface{})
+
+	stmtCache   map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
+	cascadeDeep int
+}
+
+// Method Init reset the session as the init status.
+func (session *Session) Init() {
+	session.Statement.Init()
+	session.Statement.Engine = session.Engine
+	session.IsAutoCommit = true
+	session.IsCommitedOrRollbacked = false
+	session.IsAutoClose = false
+	session.AutoResetStatement = true
+
+	// !nashtsai! is lazy init better?
+	session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0)
+	session.afterUpdateBeans = make(map[interface{}]*[]func(interface{}), 0)
+	session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
+	session.beforeClosures = make([]func(interface{}), 0)
+	session.afterClosures = make([]func(interface{}), 0)
+}
+
+// Method Close release the connection from pool
+func (session *Session) Close() {
+	for _, v := range session.stmtCache {
+		v.Close()
+	}
+
+	if session.db != nil {
+		// When Close be called, if session is a transaction and do not call
+		// Commit or Rollback, then call Rollback.
+		if session.Tx != nil && !session.IsCommitedOrRollbacked {
+			session.Rollback()
+		}
+		session.Tx = nil
+		session.stmtCache = nil
+		session.Init()
+		session.db = nil
+	}
+}
+
+func (session *Session) resetStatement() {
+	if session.AutoResetStatement {
+		session.Statement.Init()
+	}
+}
+
+// Method Sql provides raw sql input parameter. When you have a complex SQL statement
+// and cannot use Where, Id, In and etc. Methods to describe, you can use Sql.
+func (session *Session) Sql(querystring string, args ...interface{}) *Session {
+	session.Statement.Sql(querystring, args...)
+	return session
+}
+
+// Method Where provides custom query condition.
+func (session *Session) Where(querystring string, args ...interface{}) *Session {
+	session.Statement.Where(querystring, args...)
+	return session
+}
+
+// Method Where provides custom query condition.
+func (session *Session) And(querystring string, args ...interface{}) *Session {
+	session.Statement.And(querystring, args...)
+	return session
+}
+
+// Method Where provides custom query condition.
+func (session *Session) Or(querystring string, args ...interface{}) *Session {
+	session.Statement.Or(querystring, args...)
+	return session
+}
+
+// Method Id provides converting id as a query condition
+func (session *Session) Id(id interface{}) *Session {
+	session.Statement.Id(id)
+	return session
+}
+
+// Apply before Processor, affected bean is passed to closure arg
+func (session *Session) Before(closures func(interface{})) *Session {
+	if closures != nil {
+		session.beforeClosures = append(session.beforeClosures, closures)
+	}
+	return session
+}
+
+// Apply after Processor, affected bean is passed to closure arg
+func (session *Session) After(closures func(interface{})) *Session {
+	if closures != nil {
+		session.afterClosures = append(session.afterClosures, closures)
+	}
+	return session
+}
+
+// Method core.Table can input a string or pointer to struct for special a table to operate.
+func (session *Session) Table(tableNameOrBean interface{}) *Session {
+	session.Statement.Table(tableNameOrBean)
+	return session
+}
+
+// set the table alias
+func (session *Session) Alias(alias string) *Session {
+	session.Statement.Alias(alias)
+	return session
+}
+
+// Method In provides a query string like "id in (1, 2, 3)"
+func (session *Session) In(column string, args ...interface{}) *Session {
+	session.Statement.In(column, args...)
+	return session
+}
+
+// Method In provides a query string like "count = count + 1"
+func (session *Session) Incr(column string, arg ...interface{}) *Session {
+	session.Statement.Incr(column, arg...)
+	return session
+}
+
+// Method Decr provides a query string like "count = count - 1"
+func (session *Session) Decr(column string, arg ...interface{}) *Session {
+	session.Statement.Decr(column, arg...)
+	return session
+}
+
+// Method SetExpr provides a query string like "column = {expression}"
+func (session *Session) SetExpr(column string, expression string) *Session {
+	session.Statement.SetExpr(column, expression)
+	return session
+}
+
+// Method Cols provides some columns to special
+func (session *Session) Cols(columns ...string) *Session {
+	session.Statement.Cols(columns...)
+	return session
+}
+
+func (session *Session) AllCols() *Session {
+	session.Statement.AllCols()
+	return session
+}
+
+func (session *Session) MustCols(columns ...string) *Session {
+	session.Statement.MustCols(columns...)
+	return session
+}
+
+func (session *Session) NoCascade() *Session {
+	session.Statement.UseCascade = false
+	return session
+}
+
+// Xorm automatically retrieve condition according struct, but
+// if struct has bool field, it will ignore them. So use UseBool
+// to tell system to do not ignore them.
+// If no paramters, it will use all the bool field of struct, or
+// it will use paramters's columns
+func (session *Session) UseBool(columns ...string) *Session {
+	session.Statement.UseBool(columns...)
+	return session
+}
+
+// use for distinct columns. Caution: when you are using cache,
+// distinct will not be cached because cache system need id,
+// but distinct will not provide id
+func (session *Session) Distinct(columns ...string) *Session {
+	session.Statement.Distinct(columns...)
+	return session
+}
+
+// Only not use the paramters as select or update columns
+func (session *Session) Omit(columns ...string) *Session {
+	session.Statement.Omit(columns...)
+	return session
+}
+
+// Method NoAutoTime means do not automatically give created field and updated field
+// the current time on the current session temporarily
+func (session *Session) NoAutoTime() *Session {
+	session.Statement.UseAutoTime = false
+	return session
+}
+
+// Method Limit provide limit and offset query condition
+func (session *Session) Limit(limit int, start ...int) *Session {
+	session.Statement.Limit(limit, start...)
+	return session
+}
+
+// Method OrderBy provide order by query condition, the input parameter is the content
+// after order by on a sql statement.
+func (session *Session) OrderBy(order string) *Session {
+	session.Statement.OrderBy(order)
+	return session
+}
+
+// Method Desc provide desc order by query condition, the input parameters are columns.
+func (session *Session) Desc(colNames ...string) *Session {
+	session.Statement.Desc(colNames...)
+	return session
+}
+
+// Method Asc provide asc order by query condition, the input parameters are columns.
+func (session *Session) Asc(colNames ...string) *Session {
+	session.Statement.Asc(colNames...)
+	return session
+}
+
+// Method StoreEngine is only avialble mysql dialect currently
+func (session *Session) StoreEngine(storeEngine string) *Session {
+	session.Statement.StoreEngine = storeEngine
+	return session
+}
+
+// Method Charset is only avialble mysql dialect currently
+func (session *Session) Charset(charset string) *Session {
+	session.Statement.Charset = charset
+	return session
+}
+
+// Method Cascade indicates if loading sub Struct
+func (session *Session) Cascade(trueOrFalse ...bool) *Session {
+	if len(trueOrFalse) >= 1 {
+		session.Statement.UseCascade = trueOrFalse[0]
+	}
+	return session
+}
+
+// Method NoCache ask this session do not retrieve data from cache system and
+// get data from database directly.
+func (session *Session) NoCache() *Session {
+	session.Statement.UseCache = false
+	return session
+}
+
+//The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
+func (session *Session) Join(join_operator string, tablename interface{}, condition string) *Session {
+	session.Statement.Join(join_operator, tablename, condition)
+	return session
+}
+
+// Generate Group By statement
+func (session *Session) GroupBy(keys string) *Session {
+	session.Statement.GroupBy(keys)
+	return session
+}
+
+// Generate Having statement
+func (session *Session) Having(conditions string) *Session {
+	session.Statement.Having(conditions)
+	return session
+}
+
+func (session *Session) DB() *core.DB {
+	if session.db == nil {
+		session.db = session.Engine.db
+		session.stmtCache = make(map[uint32]*core.Stmt, 0)
+	}
+	return session.db
+}
+
+// Begin a transaction
+func (session *Session) Begin() error {
+	if session.IsAutoCommit {
+		tx, err := session.DB().Begin()
+		if err != nil {
+			return err
+		}
+		session.IsAutoCommit = false
+		session.IsCommitedOrRollbacked = false
+		session.Tx = tx
+
+		session.Engine.logSQL("BEGIN TRANSACTION")
+	}
+	return nil
+}
+
+// When using transaction, you can rollback if any error
+func (session *Session) Rollback() error {
+	if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
+		session.Engine.logSQL(session.Engine.dialect.RollBackStr())
+		session.IsCommitedOrRollbacked = true
+		return session.Tx.Rollback()
+	}
+	return nil
+}
+
+// When using transaction, Commit will commit all operations.
+func (session *Session) Commit() error {
+	if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
+		session.Engine.logSQL("COMMIT")
+		session.IsCommitedOrRollbacked = true
+		var err error
+		if err = session.Tx.Commit(); err == nil {
+			// handle processors after tx committed
+
+			closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
+
+				if closuresPtr != nil {
+					for _, closure := range *closuresPtr {
+						closure(bean)
+					}
+				}
+			}
+
+			for bean, closuresPtr := range session.afterInsertBeans {
+				closureCallFunc(closuresPtr, bean)
+
+				if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
+					processor.AfterInsert()
+				}
+			}
+			for bean, closuresPtr := range session.afterUpdateBeans {
+				closureCallFunc(closuresPtr, bean)
+
+				if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
+					processor.AfterUpdate()
+				}
+			}
+			for bean, closuresPtr := range session.afterDeleteBeans {
+				closureCallFunc(closuresPtr, bean)
+
+				if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
+					processor.AfterDelete()
+				}
+			}
+			cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
+				if len(*slices) > 0 {
+					*slices = make(map[interface{}]*[]func(interface{}), 0)
+				}
+			}
+			cleanUpFunc(&session.afterInsertBeans)
+			cleanUpFunc(&session.afterUpdateBeans)
+			cleanUpFunc(&session.afterDeleteBeans)
+		}
+		return err
+	}
+	return nil
+}
+
+func cleanupProcessorsClosures(slices *[]func(interface{})) {
+	if len(*slices) > 0 {
+		*slices = make([]func(interface{}), 0)
+	}
+}
+
+func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]byte) error {
+	dataStruct := rValue(obj)
+	if dataStruct.Kind() != reflect.Struct {
+		return errors.New("Expected a pointer to a struct")
+	}
+
+	var col *core.Column
+	table := session.Engine.autoMapType(dataStruct)
+
+	for key, data := range objMap {
+		if col = table.GetColumn(key); col == nil {
+			session.Engine.LogWarn(fmt.Sprintf("struct %v's has not field %v. %v",
+				table.Type.Name(), key, table.ColumnsSeq()))
+			continue
+		}
+
+		fieldName := col.FieldName
+		fieldPath := strings.Split(fieldName, ".")
+		var fieldValue reflect.Value
+		if len(fieldPath) > 2 {
+			session.Engine.LogError("Unsupported mutliderive", fieldName)
+			continue
+		} else if len(fieldPath) == 2 {
+			parentField := dataStruct.FieldByName(fieldPath[0])
+			if parentField.IsValid() {
+				fieldValue = parentField.FieldByName(fieldPath[1])
+			}
+		} else {
+			fieldValue = dataStruct.FieldByName(fieldName)
+		}
+		if !fieldValue.IsValid() || !fieldValue.CanSet() {
+			session.Engine.LogWarn("table %v's column %v is not valid or cannot set",
+				table.Name, key)
+			continue
+		}
+
+		err := session.bytes2Value(col, &fieldValue, data)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+//Execute sql
+func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Result, error) {
+	stmt, err := session.doPrepare(sqlStr)
+	if err != nil {
+		return nil, err
+	}
+	//defer stmt.Close()
+
+	res, err := stmt.Exec(args...)
+	if err != nil {
+		return nil, err
+	}
+	return res, nil
+}
+
+func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
+	for _, filter := range session.Engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+
+	session.Engine.logSQL(sqlStr, args...)
+
+	return session.Engine.LogSQLExecutionTime(sqlStr, args, func() (sql.Result, error) {
+		if session.IsAutoCommit {
+			//oci8 can not auto commit (github.com/mattn/go-oci8)
+			if session.Engine.dialect.DBType() == core.ORACLE {
+				session.Begin()
+				r, err := session.Tx.Exec(sqlStr, args...)
+				session.Commit()
+				return r, err
+			}
+			return session.innerExec(sqlStr, args...)
+		}
+		return session.Tx.Exec(sqlStr, args...)
+	})
+}
+
+// Exec raw sql
+func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.exec(sqlStr, args...)
+}
+
+// this function create a table according a bean
+func (session *Session) CreateTable(bean interface{}) error {
+	session.Statement.RefTable = session.Engine.TableInfo(bean)
+
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.createOneTable()
+}
+
+// create indexes
+func (session *Session) CreateIndexes(bean interface{}) error {
+	session.Statement.RefTable = session.Engine.TableInfo(bean)
+
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sqls := session.Statement.genIndexSQL()
+	for _, sqlStr := range sqls {
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// create uniques
+func (session *Session) CreateUniques(bean interface{}) error {
+	session.Statement.RefTable = session.Engine.TableInfo(bean)
+
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sqls := session.Statement.genUniqueSQL()
+	for _, sqlStr := range sqls {
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (session *Session) createOneTable() error {
+	sqlStr := session.Statement.genCreateTableSQL()
+	session.Engine.LogDebug("create table sql: [", sqlStr, "]")
+	_, err := session.exec(sqlStr)
+	return err
+}
+
+// to be deleted
+func (session *Session) createAll() error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	for _, table := range session.Engine.Tables {
+		session.Statement.RefTable = table
+		err := session.createOneTable()
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// drop indexes
+func (session *Session) DropIndexes(bean interface{}) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sqls := session.Statement.genDelIndexSQL()
+	for _, sqlStr := range sqls {
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// drop table will drop table if exist, if drop failed, it will return error
+func (session *Session) DropTable(beanOrTableName interface{}) error {
+	tableName, err := session.Engine.tableName(beanOrTableName)
+	if err != nil {
+		return err
+	}
+
+	var needDrop = true
+	if !session.Engine.dialect.SupportDropIfExists() {
+		sqlStr, args := session.Engine.dialect.TableCheckSql(tableName)
+		results, err := session.query(sqlStr, args...)
+		if err != nil {
+			return err
+		}
+		needDrop = len(results) > 0
+	}
+
+	if needDrop {
+		sqlStr := session.Engine.Dialect().DropTableSql(tableName)
+		_, err = session.exec(sqlStr)
+		return err
+	}
+	return nil
+}
+
+func (statement *Statement) JoinColumns(cols []*core.Column) string {
+	var colnames = make([]string, len(cols))
+	for i, col := range cols {
+		colnames[i] = statement.Engine.Quote(statement.TableName()) +
+			"." + statement.Engine.Quote(col.Name)
+	}
+	return strings.Join(colnames, ", ")
+}
+
+func (statement *Statement) convertIdSql(sqlStr string) string {
+	if statement.RefTable != nil {
+		cols := statement.RefTable.PKColumns()
+		if len(cols) == 0 {
+			return ""
+		}
+
+		colstrs := statement.JoinColumns(cols)
+		sqls := splitNNoCase(sqlStr, "from", 2)
+		if len(sqls) != 2 {
+			return ""
+		}
+		return fmt.Sprintf("SELECT %s FROM %v", colstrs, sqls[1])
+	}
+	return ""
+}
+
+func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interface{}) (has bool, err error) {
+	// if has no reftable, then don't use cache currently
+	if session.Statement.RefTable == nil ||
+		session.Statement.JoinStr != "" ||
+		session.Statement.RawSQL != "" ||
+		session.Tx != nil {
+		return false, ErrCacheFailed
+	}
+
+	for _, filter := range session.Engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+	newsql := session.Statement.convertIdSql(sqlStr)
+	if newsql == "" {
+		return false, ErrCacheFailed
+	}
+
+	cacher := session.Engine.getCacher2(session.Statement.RefTable)
+	tableName := session.Statement.TableName()
+	session.Engine.LogDebug("[cacheGet] find sql:", newsql, args)
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
+	table := session.Statement.RefTable
+	if err != nil {
+		var res = make([]string, len(table.PrimaryKeys))
+		rows, err := session.DB().Query(newsql, args...)
+		if err != nil {
+			return false, err
+		}
+		defer rows.Close()
+
+		if rows.Next() {
+			err = rows.ScanSlice(&res)
+			if err != nil {
+				return false, err
+			}
+		} else {
+			return false, ErrCacheFailed
+		}
+
+		var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
+		for i, col := range table.PKColumns() {
+			if col.SQLType.IsText() {
+				pk[i] = res[i]
+			} else if col.SQLType.IsNumeric() {
+				n, err := strconv.ParseInt(res[i], 10, 64)
+				if err != nil {
+					return false, err
+				}
+				pk[i] = n
+			} else {
+				return false, errors.New("unsupported")
+			}
+		}
+
+		ids = []core.PK{pk}
+		session.Engine.LogDebug("[cacheGet] cache ids:", newsql, ids)
+		err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
+		if err != nil {
+			return false, err
+		}
+	} else {
+		session.Engine.LogDebug("[cacheGet] cache hit sql:", newsql)
+	}
+
+	if len(ids) > 0 {
+		structValue := reflect.Indirect(reflect.ValueOf(bean))
+		id := ids[0]
+		session.Engine.LogDebug("[cacheGet] get bean:", tableName, id)
+		sid, err := id.ToString()
+		if err != nil {
+			return false, err
+		}
+		cacheBean := cacher.GetBean(tableName, sid)
+		if cacheBean == nil {
+			newSession := session.Engine.NewSession()
+			defer newSession.Close()
+			cacheBean = reflect.New(structValue.Type()).Interface()
+			newSession.Id(id).NoCache()
+			if session.Statement.AltTableName != "" {
+				newSession.Table(session.Statement.AltTableName)
+			}
+			if !session.Statement.UseCascade {
+				newSession.NoCascade()
+			}
+			has, err = newSession.Get(cacheBean)
+			if err != nil || !has {
+				return has, err
+			}
+
+			session.Engine.LogDebug("[cacheGet] cache bean:", tableName, id, cacheBean)
+			cacher.PutBean(tableName, sid, cacheBean)
+		} else {
+			session.Engine.LogDebug("[cacheGet] cache hit bean:", tableName, id, cacheBean)
+			has = true
+		}
+		structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean)))
+
+		return has, nil
+	}
+	return false, nil
+}
+
+func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
+	if session.Statement.RefTable == nil ||
+		indexNoCase(sqlStr, "having") != -1 ||
+		indexNoCase(sqlStr, "group by") != -1 ||
+		session.Tx != nil {
+		return ErrCacheFailed
+	}
+
+	for _, filter := range session.Engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+
+	newsql := session.Statement.convertIdSql(sqlStr)
+	if newsql == "" {
+		return ErrCacheFailed
+	}
+
+	table := session.Statement.RefTable
+	cacher := session.Engine.getCacher2(table)
+	ids, err := core.GetCacheSql(cacher, session.Statement.TableName(), newsql, args)
+	if err != nil {
+		rows, err := session.DB().Query(newsql, args...)
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+
+		var i int
+		ids = make([]core.PK, 0)
+		for rows.Next() {
+			i++
+			if i > 500 {
+				session.Engine.LogDebug("[cacheFind] ids length > 500, no cache")
+				return ErrCacheFailed
+			}
+			var res = make([]string, len(table.PrimaryKeys))
+			err = rows.ScanSlice(&res)
+			if err != nil {
+				return err
+			}
+
+			var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
+			for i, col := range table.PKColumns() {
+				if col.SQLType.IsNumeric() {
+					n, err := strconv.ParseInt(res[i], 10, 64)
+					if err != nil {
+						return err
+					}
+					pk[i] = n
+				} else if col.SQLType.IsText() {
+					pk[i] = res[i]
+				} else {
+					return errors.New("not supported")
+				}
+			}
+
+			ids = append(ids, pk)
+		}
+
+		tableName := session.Statement.TableName()
+
+		session.Engine.LogDebug("[cacheFind] cache sql:", ids, tableName, newsql, args)
+		err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
+		if err != nil {
+			return err
+		}
+	} else {
+		session.Engine.LogDebug("[cacheFind] cache hit sql:", newsql, args)
+	}
+
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+
+	ididxes := make(map[string]int)
+	var ides []core.PK = make([]core.PK, 0)
+	var temps []interface{} = make([]interface{}, len(ids))
+	tableName := session.Statement.TableName()
+	for idx, id := range ids {
+		sid, err := id.ToString()
+		if err != nil {
+			return err
+		}
+		bean := cacher.GetBean(tableName, sid)
+		if bean == nil {
+			ides = append(ides, id)
+			ididxes[sid] = idx
+		} else {
+			session.Engine.LogDebug("[cacheFind] cache hit bean:", tableName, id, bean)
+
+			pk := session.Engine.IdOf(bean)
+			xid, err := pk.ToString()
+			if err != nil {
+				return err
+			}
+
+			if sid != xid {
+				session.Engine.LogError("[cacheFind] error cache", xid, sid, bean)
+				return ErrCacheFailed
+			}
+			temps[idx] = bean
+		}
+	}
+
+	if len(ides) > 0 {
+		newSession := session.Engine.NewSession()
+		defer newSession.Close()
+
+		slices := reflect.New(reflect.SliceOf(t))
+		beans := slices.Interface()
+
+		if len(table.PrimaryKeys) == 1 {
+			ff := make([]interface{}, 0)
+			for _, ie := range ides {
+				ff = append(ff, ie[0])
+			}
+
+			newSession.In(table.PrimaryKeys[0], ff...)
+		} else {
+			var kn = make([]string, 0)
+			for _, name := range table.PrimaryKeys {
+				kn = append(kn, name+" = ?")
+			}
+			condi := "(" + strings.Join(kn, " AND ") + ")"
+			for _, ie := range ides {
+				newSession.Or(condi, ie...)
+			}
+		}
+
+		err = newSession.NoCache().Find(beans)
+		if err != nil {
+			return err
+		}
+
+		vs := reflect.Indirect(reflect.ValueOf(beans))
+		for i := 0; i < vs.Len(); i++ {
+			rv := vs.Index(i)
+			if rv.Kind() != reflect.Ptr {
+				rv = rv.Addr()
+			}
+			bean := rv.Interface()
+			id := session.Engine.IdOf(bean)
+			sid, err := id.ToString()
+			if err != nil {
+				return err
+			}
+
+			temps[ididxes[sid]] = bean
+			session.Engine.LogDebug("[cacheFind] cache bean:", tableName, id, bean, temps)
+			cacher.PutBean(tableName, sid, bean)
+		}
+	}
+
+	for j := 0; j < len(temps); j++ {
+		bean := temps[j]
+		if bean == nil {
+			session.Engine.LogWarn("[cacheFind] cache no hit:", tableName, ids[j], temps)
+			// return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
+			continue
+		}
+		if sliceValue.Kind() == reflect.Slice {
+			if t.Kind() == reflect.Ptr {
+				sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean)))
+			} else {
+				sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean))))
+			}
+		} else if sliceValue.Kind() == reflect.Map {
+			var key core.PK = ids[j]
+			keyType := sliceValue.Type().Key()
+			var ikey interface{}
+			if len(key) == 1 {
+				ikey, err = Atot(fmt.Sprintf("%v", key[0]), keyType)
+				if err != nil {
+					return err
+				}
+			} else {
+				if keyType.Kind() != reflect.Slice {
+					return errors.New("table have multiple primary keys, key is not core.PK or slice")
+				}
+				ikey = key
+			}
+
+			if t.Kind() == reflect.Ptr {
+				sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean))
+			} else {
+				sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean)))
+			}
+		}
+	}
+
+	return nil
+}
+
+// IterFunc only use by Iterate
+type IterFunc func(idx int, bean interface{}) error
+
+// Return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields
+// are conditions.
+func (session *Session) Rows(bean interface{}) (*Rows, error) {
+	return newRows(session, bean)
+}
+
+// Iterate record by record handle records from table, condiBeans's non-empty fields
+// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
+// map[int64]*Struct
+func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
+	rows, err := session.Rows(bean)
+	if err != nil {
+		return err
+	}
+	defer rows.Close()
+	//b := reflect.New(iterator.beanType).Interface()
+	i := 0
+	for rows.Next() {
+		b := reflect.New(rows.beanType).Interface()
+		err = rows.Scan(b)
+		if err != nil {
+			return err
+		}
+		err = fun(i, b)
+		if err != nil {
+			return err
+		}
+		i++
+	}
+	return err
+}
+
+func (session *Session) doPrepare(sqlStr string) (stmt *core.Stmt, err error) {
+	crc := crc32.ChecksumIEEE([]byte(sqlStr))
+	// TODO try hash(sqlStr+len(sqlStr))
+	var has bool
+	stmt, has = session.stmtCache[crc]
+	if !has {
+		stmt, err = session.DB().Prepare(sqlStr)
+		if err != nil {
+			return nil, err
+		}
+		session.stmtCache[crc] = stmt
+	}
+	return
+}
+
+// get retrieve one record from database, bean's non-empty fields
+// will be as conditions
+func (session *Session) Get(bean interface{}) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	session.Statement.Limit(1)
+	var sqlStr string
+	var args []interface{}
+
+	if session.Statement.RefTable == nil {
+		session.Statement.RefTable = session.Engine.TableInfo(bean)
+	}
+
+	if session.Statement.RawSQL == "" {
+		sqlStr, args = session.Statement.genGetSql(bean)
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	if session.Statement.JoinStr == "" {
+		if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil &&
+			session.Statement.UseCache &&
+			!session.Statement.unscoped {
+			has, err := session.cacheGet(bean, sqlStr, args...)
+			if err != ErrCacheFailed {
+				return has, err
+			}
+		}
+	}
+
+	var rawRows *core.Rows
+	var err error
+	session.queryPreprocess(&sqlStr, args...)
+	if session.IsAutoCommit {
+		stmt, errPrepare := session.doPrepare(sqlStr)
+		if errPrepare != nil {
+			return false, errPrepare
+		}
+		// defer stmt.Close() // !nashtsai! don't close due to stmt is cached and bounded to this session
+		rawRows, err = stmt.Query(args...)
+	} else {
+		rawRows, err = session.Tx.Query(sqlStr, args...)
+	}
+	if err != nil {
+		return false, err
+	}
+
+	defer rawRows.Close()
+
+	if rawRows.Next() {
+		if fields, err := rawRows.Columns(); err == nil {
+			err = session.row2Bean(rawRows, fields, len(fields), bean)
+		}
+		return true, err
+	}
+	return false, nil
+}
+
+// get retrieve one record from database, bean's non-empty fields
+// will be as conditions
+//func (session *Session) GetWithDateFormat(dateFormat string, bean interface{}) (bool, error) {
+//	defer session.resetStatement()
+//	if session.IsAutoClose {
+//		defer session.Close()
+//	}
+
+//	session.Statement.Limit(1)
+//	var sqlStr string
+//	var args []interface{}
+
+//	if session.Statement.RefTable == nil {
+//		session.Statement.RefTable = session.Engine.TableInfo(bean)
+//	}
+
+//	if session.Statement.RawSQL == "" {
+//		sqlStr, args = session.Statement.genGetSql(bean)
+//	} else {
+//		sqlStr = session.Statement.RawSQL
+//		args = session.Statement.RawParams
+//	}
+
+//	if session.Statement.JoinStr == "" {
+//		if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil &&
+//			session.Statement.UseCache &&
+//			!session.Statement.unscoped {
+//			has, err := session.cacheGet(bean, sqlStr, args...)
+//			if err != ErrCacheFailed {
+//				return has, err
+//			}
+//		}
+//	}
+
+//	var rawRows *core.Rows
+//	var err error
+//	session.queryPreprocess(&sqlStr, args...)
+//	if session.IsAutoCommit {
+//		stmt, errPrepare := session.doPrepare(sqlStr)
+//		if errPrepare != nil {
+//			return false, errPrepare
+//		}
+//		// defer stmt.Close() // !nashtsai! don't close due to stmt is cached and bounded to this session
+//		rawRows, err = stmt.Query(args...)
+//	} else {
+//		rawRows, err = session.Tx.Query(sqlStr, args...)
+//	}
+//	if err != nil {
+//		return false, err
+//	}
+
+//	defer rawRows.Close()
+
+//	if rawRows.Next() {
+//		if fields, err := rawRows.Columns(); err == nil {
+//			err = session.row2BeanWithDateFormat(dateFormat, rawRows, fields, len(fields), bean)
+//		}
+//		return true, err
+//	}
+//	return false, nil
+//}
+
+//func (session *Session) GetToJsonStringWithDateFormat(dateFormat string, bean interface{}) (bool, string, error) {
+////	has, err, data := session.GetToMap(dateFormat, bean)
+//	has, err:=session.Get(bean)
+//	fmt.Println("数据库查询bean:%#v", bean)
+////	fmt.Println("数据库查询data:%#v", data)
+//	if !has || err != nil {
+//		return false, "", err
+//	}
+
+////		tmpBeanMap := Struct2MapWithDateFormat(dateFormat, bean)
+
+////	result, err1 := JSONString(data, true)
+////result, err1 := JSONString(tmpBeanMap, true)
+//result, err1 := JSONString(bean, true)
+//	if err1 != nil {
+//		return false, "", err
+//	}
+//	return true, result, nil
+//}
+
+func Struct2Map(obj interface{}) map[string]interface{} {
+	t := reflect.TypeOf(obj)
+	v := reflect.ValueOf(obj)
+
+	var data = make(map[string]interface{})
+	for i := 0; i < t.NumField(); i++ {
+		data[t.Field(i).Name] = v.Field(i).Interface()
+	}
+	return data
+}
+
+//func Struct2MapWithDateFormat(dateFormat string, obj interface{}) map[string]interface{} {
+//	t := reflect.TypeOf(obj)
+//	v := reflect.ValueOf(obj)
+
+//	var data = make(map[string]interface{})
+//	for i := 0; i < t.NumField(); i++ {
+//		if t.Field(i).Type == core.TimeType {
+//			data[t.Field(i).Name] = v.Field(i).Interface().(time.Time).Format(dateFormat)
+//		} else {
+//			data[t.Field(i).Name] = v.Field(i).Interface()
+//		}
+
+//	}
+//	return data
+//}
+
+// Count counts the records. bean's non-empty fields
+// are conditions.
+func (session *Session) Count(bean interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	var sqlStr string
+	var args []interface{}
+	if session.Statement.RawSQL == "" {
+		sqlStr, args = session.Statement.genCountSql(bean)
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	resultsSlice, err := session.query(sqlStr, args...)
+	if err != nil {
+		return 0, err
+	}
+
+	var total int64 = 0
+	if len(resultsSlice) > 0 {
+		results := resultsSlice[0]
+		for _, value := range results {
+			total, err = strconv.ParseInt(string(value), 10, 64)
+			break
+		}
+	}
+
+	return int64(total), err
+}
+
+func Atot(s string, tp reflect.Type) (interface{}, error) {
+	var err error
+	var result interface{}
+	switch tp.Kind() {
+	case reflect.Int:
+		result, err = strconv.Atoi(s)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as int: " + err.Error())
+		}
+	case reflect.Int8:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as int16: " + err.Error())
+		}
+		result = int8(x)
+	case reflect.Int16:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as int16: " + err.Error())
+		}
+		result = int16(x)
+	case reflect.Int32:
+		x, err := strconv.Atoi(s)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as int32: " + err.Error())
+		}
+		result = int32(x)
+	case reflect.Int64:
+		result, err = strconv.ParseInt(s, 10, 64)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as int64: " + err.Error())
+		}
+	case reflect.Uint:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as uint: " + err.Error())
+		}
+		result = uint(x)
+	case reflect.Uint8:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as uint8: " + err.Error())
+		}
+		result = uint8(x)
+	case reflect.Uint16:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as uint16: " + err.Error())
+		}
+		result = uint16(x)
+	case reflect.Uint32:
+		x, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as uint32: " + err.Error())
+		}
+		result = uint32(x)
+	case reflect.Uint64:
+		result, err = strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, errors.New("convert " + s + " as uint64: " + err.Error())
+		}
+	case reflect.String:
+		result = s
+	default:
+		panic("unsupported convert type")
+	}
+	return result, nil
+}
+
+// Find retrieve records from table, condiBeans's non-empty fields
+// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
+// map[int64]*Struct
+func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+	if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
+		return errors.New("needs a pointer to a slice or a map")
+	}
+
+	sliceElementType := sliceValue.Type().Elem()
+	var table *core.Table
+	if session.Statement.RefTable == nil {
+		if sliceElementType.Kind() == reflect.Ptr {
+			if sliceElementType.Elem().Kind() == reflect.Struct {
+				pv := reflect.New(sliceElementType.Elem())
+				table = session.Engine.autoMapType(pv.Elem())
+			} else {
+				return errors.New("slice type")
+			}
+		} else if sliceElementType.Kind() == reflect.Struct {
+			pv := reflect.New(sliceElementType)
+			table = session.Engine.autoMapType(pv.Elem())
+		} else {
+			return errors.New("slice type")
+		}
+		session.Statement.RefTable = table
+	} else {
+		table = session.Statement.RefTable
+	}
+
+	if len(condiBean) > 0 {
+		colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true,
+			false, true, session.Statement.allUseBool, session.Statement.useAllCols,
+			session.Statement.unscoped, session.Statement.mustColumnMap)
+		session.Statement.ConditionStr = strings.Join(colNames, " AND ")
+		session.Statement.BeanArgs = args
+	} else {
+		// !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given.
+		// See https://github.com/go-xorm/xorm/issues/179
+		if col := table.DeletedColumn(); col != nil && !session.Statement.unscoped { // tag "deleted" is enabled
+			session.Statement.ConditionStr = fmt.Sprintf("(%v IS NULL or %v = '0001-01-01 00:00:00') ",
+				session.Engine.Quote(col.Name), session.Engine.Quote(col.Name))
+		}
+	}
+
+	var sqlStr string
+	var args []interface{}
+	if session.Statement.RawSQL == "" {
+		var columnStr string = session.Statement.ColumnStr
+		if session.Statement.JoinStr == "" {
+			if columnStr == "" {
+				if session.Statement.GroupByStr != "" {
+					columnStr = session.Statement.Engine.Quote(strings.Replace(session.Statement.GroupByStr, ",", session.Engine.Quote(","), -1))
+				} else {
+					columnStr = session.Statement.genColumnStr()
+				}
+			}
+		} else {
+			if columnStr == "" {
+				if session.Statement.GroupByStr != "" {
+					columnStr = session.Statement.Engine.Quote(strings.Replace(session.Statement.GroupByStr, ",", session.Engine.Quote(","), -1))
+				} else {
+					columnStr = "*"
+				}
+			}
+		}
+
+		session.Statement.attachInSql()
+
+		sqlStr = session.Statement.genSelectSql(columnStr)
+		args = append(session.Statement.Params, session.Statement.BeanArgs...)
+		// for mssql and use limit
+		qs := strings.Count(sqlStr, "?")
+		if len(args)*2 == qs {
+			args = append(args, args...)
+		}
+	} else {
+		sqlStr = session.Statement.RawSQL
+		args = session.Statement.RawParams
+	}
+
+	var err error
+	if session.Statement.JoinStr == "" {
+		if cacher := session.Engine.getCacher2(table); cacher != nil &&
+			session.Statement.UseCache &&
+			!session.Statement.IsDistinct &&
+			!session.Statement.unscoped {
+			err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
+			if err != ErrCacheFailed {
+				return err
+			}
+			err = nil // !nashtsai! reset err to nil for ErrCacheFailed
+			session.Engine.LogWarn("Cache Find Failed")
+		}
+	}
+
+	if sliceValue.Kind() != reflect.Map {
+		var rawRows *core.Rows
+		var stmt *core.Stmt
+
+		session.queryPreprocess(&sqlStr, args...)
+
+		if session.IsAutoCommit {
+			stmt, err = session.doPrepare(sqlStr)
+			if err != nil {
+				return err
+			}
+			rawRows, err = stmt.Query(args...)
+		} else {
+			rawRows, err = session.Tx.Query(sqlStr, args...)
+		}
+		if err != nil {
+			return err
+		}
+		defer rawRows.Close()
+
+		fields, err := rawRows.Columns()
+		if err != nil {
+			return err
+		}
+
+		fieldsCount := len(fields)
+
+		var newElemFunc func() reflect.Value
+		if sliceElementType.Kind() == reflect.Ptr {
+			newElemFunc = func() reflect.Value {
+				return reflect.New(sliceElementType.Elem())
+			}
+		} else {
+			newElemFunc = func() reflect.Value {
+				return reflect.New(sliceElementType)
+			}
+		}
+
+		var sliceValueSetFunc func(*reflect.Value)
+
+		if sliceValue.Kind() == reflect.Slice {
+			if sliceElementType.Kind() == reflect.Ptr {
+				sliceValueSetFunc = func(newValue *reflect.Value) {
+					sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(newValue.Interface())))
+				}
+			} else {
+				sliceValueSetFunc = func(newValue *reflect.Value) {
+					sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(newValue.Interface()))))
+				}
+			}
+		}
+
+		var newValue reflect.Value = newElemFunc()
+		dataStruct := rValue(newValue.Interface())
+		if dataStruct.Kind() != reflect.Struct {
+			return errors.New("Expected a pointer to a struct")
+		}
+
+		table := session.Engine.autoMapType(dataStruct)
+
+		return session.rows2Beans(rawRows, fields, fieldsCount, table, newElemFunc, sliceValueSetFunc)
+	} else {
+		resultsSlice, err := session.query(sqlStr, args...)
+		if err != nil {
+			return err
+		}
+
+		keyType := sliceValue.Type().Key()
+
+		for _, results := range resultsSlice {
+			var newValue reflect.Value
+			if sliceElementType.Kind() == reflect.Ptr {
+				newValue = reflect.New(sliceElementType.Elem())
+			} else {
+				newValue = reflect.New(sliceElementType)
+			}
+			err := session.scanMapIntoStruct(newValue.Interface(), results)
+			if err != nil {
+				return err
+			}
+			var key interface{}
+			// if there is only one pk, we can put the id as map key.
+			if len(table.PrimaryKeys) == 1 {
+				key, err = Atot(string(results[table.PrimaryKeys[0]]), keyType)
+				if err != nil {
+					return err
+				}
+			} else {
+				if keyType.Kind() != reflect.Slice {
+					panic("don't support multiple primary key's map has non-slice key type")
+				} else {
+					keys := core.PK{}
+					for _, pk := range table.PrimaryKeys {
+						skey, err := Atot(string(results[pk]), keyType)
+						if err != nil {
+							return err
+						}
+						keys = append(keys, skey)
+					}
+					key = keys
+				}
+			}
+
+			if sliceElementType.Kind() == reflect.Ptr {
+				sliceValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(newValue.Interface()))
+			} else {
+				sliceValue.SetMapIndex(reflect.ValueOf(key), reflect.Indirect(reflect.ValueOf(newValue.Interface())))
+			}
+		}
+	}
+	return nil
+}
+
+// func (session *Session) queryRows(rawStmt **sql.Stmt, rawRows **sql.Rows, sqlStr string, args ...interface{}) error {
+// 	var err error
+// 	if session.IsAutoCommit {
+// 		*rawStmt, err = session.doPrepare(sqlStr)
+// 		if err != nil {
+// 			return err
+// 		}
+// 		*rawRows, err = (*rawStmt).Query(args...)
+// 	} else {
+// 		*rawRows, err = session.Tx.Query(sqlStr, args...)
+// 	}
+// 	return err
+// }
+
+// Test if database is ok
+func (session *Session) Ping() error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.DB().Ping()
+}
+
+/*
+func (session *Session) isColumnExist(tableName string, col *core.Column) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	return session.Engine.dialect.IsColumnExist(tableName, col)
+	//sqlStr, args := session.Engine.dialect.ColumnCheckSql(tableName, colName)
+	//results, err := session.query(sqlStr, args...)
+	//return len(results) > 0, err
+}*/
+
+func (engine *Engine) tableName(beanOrTableName interface{}) (string, error) {
+	v := rValue(beanOrTableName)
+	if v.Type().Kind() == reflect.String {
+		return beanOrTableName.(string), nil
+	} else if v.Type().Kind() == reflect.Struct {
+		table := engine.autoMapType(v)
+		return table.Name, nil
+	}
+	return "", errors.New("bean should be a struct or struct's point")
+}
+
+func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) {
+	tableName, err := session.Engine.tableName(beanOrTableName)
+	if err != nil {
+		return false, err
+	}
+
+	return session.isTableExist(tableName)
+}
+
+func (session *Session) isTableExist(tableName string) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	sqlStr, args := session.Engine.dialect.TableCheckSql(tableName)
+	results, err := session.query(sqlStr, args...)
+	return len(results) > 0, err
+}
+
+func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
+	v := rValue(bean)
+	t := v.Type()
+
+	if t.Kind() == reflect.String {
+		return session.isTableEmpty(bean.(string))
+	} else if t.Kind() == reflect.Struct {
+		session.Engine.autoMapType(v)
+		rows, err := session.Count(bean)
+		return rows == 0, err
+	}
+	return false, errors.New("bean should be a struct or struct's point")
+}
+
+func (session *Session) isTableEmpty(tableName string) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	var total int64
+	sql := fmt.Sprintf("select count(*) from %s", session.Engine.Quote(tableName))
+	err := session.DB().QueryRow(sql).Scan(&total)
+	session.Engine.logSQL(sql)
+	if err != nil {
+		return true, err
+	}
+
+	return total == 0, nil
+}
+
+func (session *Session) isIndexExist(tableName, idxName string, unique bool) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	var idx string
+	if unique {
+		idx = uniqueName(tableName, idxName)
+	} else {
+		idx = indexName(tableName, idxName)
+	}
+	sqlStr, args := session.Engine.dialect.IndexCheckSql(tableName, idx)
+	results, err := session.query(sqlStr, args...)
+	return len(results) > 0, err
+}
+
+// find if index is exist according cols
+func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	indexes, err := session.Engine.dialect.GetIndexes(tableName)
+	if err != nil {
+		return false, err
+	}
+
+	for _, index := range indexes {
+		if sliceEq(index.Cols, cols) {
+			if unique {
+				return index.Type == core.UniqueType, nil
+			} else {
+				return index.Type == core.IndexType, nil
+			}
+		}
+	}
+	return false, nil
+}
+
+func (session *Session) addColumn(colName string) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	col := session.Statement.RefTable.GetColumn(colName)
+	sql, args := session.Statement.genAddColumnStr(col)
+	_, err := session.exec(sql, args...)
+	return err
+}
+
+func (session *Session) addIndex(tableName, idxName string) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	index := session.Statement.RefTable.Indexes[idxName]
+	sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index)
+
+	_, err := session.exec(sqlStr)
+	return err
+}
+
+func (session *Session) addUnique(tableName, uqeName string) error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+	index := session.Statement.RefTable.Indexes[uqeName]
+	sqlStr := session.Engine.dialect.CreateIndexSql(tableName, index)
+	_, err := session.exec(sqlStr)
+	return err
+}
+
+// To be deleted
+func (session *Session) dropAll() error {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	for _, table := range session.Engine.Tables {
+		session.Statement.Init()
+		session.Statement.RefTable = table
+		sqlStr := session.Engine.Dialect().DropTableSql(session.Statement.TableName())
+		_, err := session.exec(sqlStr)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) *reflect.Value {
+	var col *core.Column
+	if col = table.GetColumnIdx(key, idx); col == nil {
+		session.Engine.LogWarn(fmt.Sprintf("table %v's has not column %v. %v", table.Name, key, table.Columns()))
+		return nil
+	}
+
+	fieldValue, err := col.ValueOfV(dataStruct)
+	if err != nil {
+		session.Engine.LogError(err)
+		return nil
+	}
+
+	if !fieldValue.IsValid() || !fieldValue.CanSet() {
+		session.Engine.LogWarn("table %v's column %v is not valid or cannot set",
+			table.Name, key)
+		return nil
+	}
+	return fieldValue
+}
+
+type Cell *interface{}
+
+func (session *Session) rows2Beans(rows *core.Rows, fields []string, fieldsCount int,
+	table *core.Table, newElemFunc func() reflect.Value,
+	sliceValueSetFunc func(*reflect.Value)) error {
+
+	for rows.Next() {
+		var newValue reflect.Value = newElemFunc()
+		bean := newValue.Interface()
+		dataStruct := rValue(bean)
+		err := session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table)
+		if err != nil {
+			return err
+		}
+		sliceValueSetFunc(&newValue)
+
+	}
+	return nil
+}
+
+func (session *Session) row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error {
+	dataStruct := rValue(bean)
+	if dataStruct.Kind() != reflect.Struct {
+		return errors.New("Expected a pointer to a struct")
+	}
+
+	table := session.Engine.autoMapType(dataStruct)
+	return session._row2Bean(rows, fields, fieldsCount, bean, &dataStruct, table)
+}
+
+func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) error {
+	scanResults := make([]interface{}, fieldsCount)
+	for i := 0; i < len(fields); i++ {
+		var cell interface{}
+		scanResults[i] = &cell
+	}
+	if err := rows.Scan(scanResults...); err != nil {
+		return err
+	}
+
+	if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet {
+		for ii, key := range fields {
+			b.BeforeSet(key, Cell(scanResults[ii].(*interface{})))
+		}
+	}
+
+	var tempMap = make(map[string]int)
+	for ii, key := range fields {
+		var idx int
+		var ok bool
+		if idx, ok = tempMap[strings.ToLower(key)]; !ok {
+			idx = 0
+		} else {
+			idx = idx + 1
+		}
+		tempMap[strings.ToLower(key)] = idx
+
+		if fieldValue := session.getField(dataStruct, key, table, idx); fieldValue != nil {
+			rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
+
+			//if row is null then ignore
+			if rawValue.Interface() == nil {
+				continue
+			}
+
+			if fieldValue.CanAddr() {
+				if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+					if data, err := value2Bytes(&rawValue); err == nil {
+						structConvert.FromDB(data)
+					} else {
+						session.Engine.LogError(err)
+					}
+					continue
+				}
+			}
+
+			if _, ok := fieldValue.Interface().(core.Conversion); ok {
+				if data, err := value2Bytes(&rawValue); err == nil {
+					if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
+						fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
+					}
+					fieldValue.Interface().(core.Conversion).FromDB(data)
+				} else {
+					session.Engine.LogError(err)
+				}
+				continue
+			}
+
+			rawValueType := reflect.TypeOf(rawValue.Interface())
+			vv := reflect.ValueOf(rawValue.Interface())
+
+			fieldType := fieldValue.Type()
+			hasAssigned := false
+
+			switch fieldType.Kind() {
+
+			case reflect.Complex64, reflect.Complex128:
+				if rawValueType.Kind() == reflect.String {
+					hasAssigned = true
+					x := reflect.New(fieldType)
+					err := json.Unmarshal([]byte(vv.String()), x.Interface())
+					if err != nil {
+						session.Engine.LogError(err)
+						return err
+					}
+					fieldValue.Set(x.Elem())
+				}
+			case reflect.Slice, reflect.Array:
+				switch rawValueType.Kind() {
+				case reflect.Slice, reflect.Array:
+					switch rawValueType.Elem().Kind() {
+					case reflect.Uint8:
+						if fieldType.Elem().Kind() == reflect.Uint8 {
+							hasAssigned = true
+							fieldValue.Set(vv)
+						}
+					}
+				}
+			case reflect.String:
+				if rawValueType.Kind() == reflect.String {
+					hasAssigned = true
+					fieldValue.SetString(vv.String())
+				}
+			case reflect.Bool:
+				if rawValueType.Kind() == reflect.Bool {
+					hasAssigned = true
+					fieldValue.SetBool(vv.Bool())
+				}
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				switch rawValueType.Kind() {
+				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+					hasAssigned = true
+					fieldValue.SetInt(vv.Int())
+				}
+			case reflect.Float32, reflect.Float64:
+				switch rawValueType.Kind() {
+				case reflect.Float32, reflect.Float64:
+					hasAssigned = true
+					fieldValue.SetFloat(vv.Float())
+				}
+			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+				switch rawValueType.Kind() {
+				case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+					hasAssigned = true
+					fieldValue.SetUint(vv.Uint())
+				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+					hasAssigned = true
+					fieldValue.SetUint(uint64(vv.Int()))
+				}
+			case reflect.Struct:
+				if fieldType.ConvertibleTo(core.TimeType) {
+					if rawValueType == core.TimeType {
+						hasAssigned = true
+
+						t := vv.Convert(core.TimeType).Interface().(time.Time)
+						z, _ := t.Zone()
+						if len(z) == 0 || t.Year() == 0 { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
+							session.Engine.LogDebug("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
+							t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
+								t.Minute(), t.Second(), t.Nanosecond(), time.Local)
+						}
+						// !nashtsai! convert to engine location
+						t = t.In(session.Engine.TZLocation)
+						fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+
+						// t = fieldValue.Interface().(time.Time)
+						// z, _ = t.Zone()
+						// session.Engine.LogDebug("fieldValue key[%v]: %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
+					} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
+						rawValueType == core.Int32Type {
+						hasAssigned = true
+						t := time.Unix(vv.Int(), 0).In(session.Engine.TZLocation)
+						vv = reflect.ValueOf(t)
+						fieldValue.Set(vv)
+					}
+				} else if session.Statement.UseCascade {
+					table := session.Engine.autoMapType(*fieldValue)
+					if table != nil {
+						if len(table.PrimaryKeys) > 1 {
+							panic("unsupported composited primary key cascade")
+						}
+						var pk = make(core.PK, len(table.PrimaryKeys))
+						switch rawValueType.Kind() {
+						case reflect.Int64:
+							pk[0] = vv.Int()
+						case reflect.Int:
+							pk[0] = int(vv.Int())
+						case reflect.Int32:
+							pk[0] = int32(vv.Int())
+						case reflect.Int16:
+							pk[0] = int16(vv.Int())
+						case reflect.Int8:
+							pk[0] = int8(vv.Int())
+						case reflect.Uint64:
+							pk[0] = vv.Uint()
+						case reflect.Uint:
+							pk[0] = uint(vv.Uint())
+						case reflect.Uint32:
+							pk[0] = uint32(vv.Uint())
+						case reflect.Uint16:
+							pk[0] = uint16(vv.Uint())
+						case reflect.Uint8:
+							pk[0] = uint8(vv.Uint())
+						case reflect.String:
+							pk[0] = vv.String()
+						default:
+							panic("unsupported primary key type cascade")
+						}
+
+						if !isPKZero(pk) {
+							// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+							// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+							// property to be fetched lazily
+							structInter := reflect.New(fieldValue.Type())
+							newsession := session.Engine.NewSession()
+							defer newsession.Close()
+							has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
+							if err != nil {
+								return err
+							}
+							if has {
+								v := structInter.Elem().Interface()
+								fieldValue.Set(reflect.ValueOf(v))
+							} else {
+								return errors.New("cascade obj is not exist!")
+							}
+						}
+					} else {
+						session.Engine.LogError("unsupported struct type in Scan: ", fieldValue.Type().String())
+					}
+				}
+			case reflect.Ptr:
+				// !nashtsai! TODO merge duplicated codes above
+				//typeStr := fieldType.String()
+				switch fieldType {
+				// following types case matching ptr's native type, therefore assign ptr directly
+				case core.PtrStringType:
+					if rawValueType.Kind() == reflect.String {
+						x := vv.String()
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrBoolType:
+					if rawValueType.Kind() == reflect.Bool {
+						x := vv.Bool()
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrTimeType:
+					if rawValueType == core.PtrTimeType {
+						hasAssigned = true
+						var x time.Time = rawValue.Interface().(time.Time)
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrFloat64Type:
+					if rawValueType.Kind() == reflect.Float64 {
+						x := vv.Float()
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrUint64Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint64 = uint64(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrInt64Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						x := vv.Int()
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrFloat32Type:
+					if rawValueType.Kind() == reflect.Float64 {
+						var x float32 = float32(vv.Float())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrIntType:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x int = int(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrInt32Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x int32 = int32(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrInt8Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x int8 = int8(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrInt16Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x int16 = int16(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrUintType:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint = uint(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrUint32Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint32 = uint32(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.Uint8Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint8 = uint8(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.Uint16Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint16 = uint16(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.Complex64Type:
+					var x complex64
+					err := json.Unmarshal([]byte(vv.String()), &x)
+					if err != nil {
+						session.Engine.LogError(err)
+					} else {
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+					hasAssigned = true
+				case core.Complex128Type:
+					var x complex128
+					err := json.Unmarshal([]byte(vv.String()), &x)
+					if err != nil {
+						session.Engine.LogError(err)
+					} else {
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+					hasAssigned = true
+				} // switch fieldType
+				// default:
+				// 	session.Engine.LogError("unsupported type in Scan: ", reflect.TypeOf(v).String())
+			} // switch fieldType.Kind()
+
+			// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
+			if !hasAssigned {
+				data, err := value2Bytes(&rawValue)
+				if err == nil {
+					session.bytes2Value(table.GetColumn(key), fieldValue, data)
+				} else {
+					session.Engine.LogError(err.Error())
+				}
+			}
+		}
+	}
+	return nil
+
+}
+
+func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
+	for _, filter := range session.Engine.dialect.Filters() {
+		*sqlStr = filter.Do(*sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+
+	session.Engine.logSQL(*sqlStr, paramStr...)
+}
+
+func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
+
+	session.queryPreprocess(&sqlStr, paramStr...)
+
+	if session.IsAutoCommit {
+		return session.innerQuery(session.DB(), sqlStr, paramStr...)
+	}
+	return session.txQuery(session.Tx, sqlStr, paramStr...)
+}
+
+func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) {
+	rows, err := tx.Query(sqlStr, params...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2maps(rows)
+}
+
+func (session *Session) innerQuery(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) {
+	stmt, rows, err := session.Engine.LogSQLQueryTime(sqlStr, params, func() (*core.Stmt, *core.Rows, error) {
+		stmt, err := db.Prepare(sqlStr)
+		if err != nil {
+			return stmt, nil, err
+		}
+		rows, err := stmt.Query(params...)
+
+		return stmt, rows, err
+	})
+	if rows != nil {
+		defer rows.Close()
+	}
+	if stmt != nil {
+		defer stmt.Close()
+	}
+	if err != nil {
+		return nil, err
+	}
+	return rows2maps(rows)
+}
+
+// Exec a raw sql and return records as []map[string][]byte
+func (session *Session) Query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.query(sqlStr, paramStr...)
+}
+
+// =============================
+// for string
+// =============================
+func (session *Session) Query2(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]string, err error) {
+	session.queryPreprocess(&sqlStr, paramStr...)
+
+	if session.IsAutoCommit {
+		return query2(session.DB(), sqlStr, paramStr...)
+	}
+	return txQuery2(session.Tx, sqlStr, paramStr...)
+}
+
+// insert one or more beans
+func (session *Session) Insert(beans ...interface{}) (int64, error) {
+	var affected int64 = 0
+	var err error
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	for _, bean := range beans {
+		sliceValue := reflect.Indirect(reflect.ValueOf(bean))
+		if sliceValue.Kind() == reflect.Slice {
+			size := sliceValue.Len()
+			if size > 0 {
+				if session.Engine.SupportInsertMany() {
+					cnt, err := session.innerInsertMulti(bean)
+					if err != nil {
+						return affected, err
+					}
+					affected += cnt
+				} else {
+					for i := 0; i < size; i++ {
+						cnt, err := session.innerInsert(sliceValue.Index(i).Interface())
+						if err != nil {
+							return affected, err
+						}
+						affected += cnt
+					}
+				}
+			}
+		} else {
+			cnt, err := session.innerInsert(bean)
+			if err != nil {
+				return affected, err
+			}
+			affected += cnt
+		}
+	}
+
+	return affected, err
+}
+
+func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error) {
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+	if sliceValue.Kind() != reflect.Slice {
+		return 0, errors.New("needs a pointer to a slice")
+	}
+
+	bean := sliceValue.Index(0).Interface()
+	elementValue := rValue(bean)
+	//sliceElementType := elementValue.Type()
+
+	table := session.Engine.autoMapType(elementValue)
+	session.Statement.RefTable = table
+
+	size := sliceValue.Len()
+
+	colNames := make([]string, 0)
+	colMultiPlaces := make([]string, 0)
+	var args = make([]interface{}, 0)
+	cols := make([]*core.Column, 0)
+
+	for i := 0; i < size; i++ {
+		elemValue := sliceValue.Index(i).Interface()
+		colPlaces := make([]string, 0)
+
+		// handle BeforeInsertProcessor
+		// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
+		for _, closure := range session.beforeClosures {
+			closure(elemValue)
+		}
+
+		if processor, ok := interface{}(elemValue).(BeforeInsertProcessor); ok {
+			processor.BeforeInsert()
+		}
+		// --
+
+		if i == 0 {
+			for _, col := range table.Columns() {
+				fieldValue := reflect.Indirect(reflect.ValueOf(elemValue)).FieldByName(col.FieldName)
+				if col.IsAutoIncrement && fieldValue.Int() == 0 {
+					continue
+				}
+				if col.MapType == core.ONLYFROMDB {
+					continue
+				}
+				if col.IsDeleted {
+					continue
+				}
+				if session.Statement.ColumnStr != "" {
+					if _, ok := session.Statement.columnMap[col.Name]; !ok {
+						continue
+					}
+				}
+				if session.Statement.OmitStr != "" {
+					if _, ok := session.Statement.columnMap[col.Name]; ok {
+						continue
+					}
+				}
+				if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
+					val, t := session.Engine.NowTime2(col.SQLType.Name)
+					args = append(args, val)
+
+					var colName = col.Name
+					session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+						col := table.GetColumn(colName)
+						setColumnTime(bean, col, t)
+					})
+				} else {
+					arg, err := session.value2Interface(col, fieldValue)
+					if err != nil {
+						return 0, err
+					}
+					args = append(args, arg)
+				}
+
+				colNames = append(colNames, col.Name)
+				cols = append(cols, col)
+				colPlaces = append(colPlaces, "?")
+			}
+		} else {
+			for _, col := range cols {
+				fieldValue := reflect.Indirect(reflect.ValueOf(elemValue)).FieldByName(col.FieldName)
+				if col.IsAutoIncrement && fieldValue.Int() == 0 {
+					continue
+				}
+				if col.MapType == core.ONLYFROMDB {
+					continue
+				}
+				if col.IsDeleted {
+					continue
+				}
+				if session.Statement.ColumnStr != "" {
+					if _, ok := session.Statement.columnMap[col.Name]; !ok {
+						continue
+					}
+				}
+				if session.Statement.OmitStr != "" {
+					if _, ok := session.Statement.columnMap[col.Name]; ok {
+						continue
+					}
+				}
+				if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
+					val, t := session.Engine.NowTime2(col.SQLType.Name)
+					args = append(args, val)
+
+					var colName = col.Name
+					session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+						col := table.GetColumn(colName)
+						setColumnTime(bean, col, t)
+					})
+				} else {
+					arg, err := session.value2Interface(col, fieldValue)
+					if err != nil {
+						return 0, err
+					}
+					args = append(args, arg)
+				}
+
+				colPlaces = append(colPlaces, "?")
+			}
+		}
+		colMultiPlaces = append(colMultiPlaces, strings.Join(colPlaces, ", "))
+	}
+	cleanupProcessorsClosures(&session.beforeClosures)
+
+	statement := fmt.Sprintf("INSERT INTO %v%v%v (%v%v%v) VALUES (%v)",
+		session.Engine.QuoteStr(),
+		session.Statement.TableName(),
+		session.Engine.QuoteStr(),
+		session.Engine.QuoteStr(),
+		strings.Join(colNames, session.Engine.QuoteStr()+", "+session.Engine.QuoteStr()),
+		session.Engine.QuoteStr(),
+		strings.Join(colMultiPlaces, "),("))
+
+	res, err := session.exec(statement, args...)
+	if err != nil {
+		return 0, err
+	}
+
+	if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+		session.cacheInsert(session.Statement.TableName())
+	}
+
+	lenAfterClosures := len(session.afterClosures)
+	for i := 0; i < size; i++ {
+		elemValue := sliceValue.Index(i).Interface()
+		// handle AfterInsertProcessor
+		if session.IsAutoCommit {
+			// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
+			for _, closure := range session.afterClosures {
+				closure(elemValue)
+			}
+			if processor, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
+				processor.AfterInsert()
+			}
+		} else {
+			if lenAfterClosures > 0 {
+				if value, has := session.afterInsertBeans[elemValue]; has && value != nil {
+					*value = append(*value, session.afterClosures...)
+				} else {
+					afterClosures := make([]func(interface{}), lenAfterClosures)
+					copy(afterClosures, session.afterClosures)
+					session.afterInsertBeans[elemValue] = &afterClosures
+				}
+			} else {
+				if _, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
+					session.afterInsertBeans[elemValue] = nil
+				}
+			}
+		}
+	}
+	cleanupProcessorsClosures(&session.afterClosures)
+	return res.RowsAffected()
+}
+
+// Insert multiple records
+func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
+	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
+	if sliceValue.Kind() == reflect.Slice {
+		if sliceValue.Len() > 0 {
+			defer session.resetStatement()
+			if session.IsAutoClose {
+				defer session.Close()
+			}
+			return session.innerInsertMulti(rowsSlicePtr)
+		} else {
+			return 0, nil
+		}
+	} else {
+		return 0, ErrParamsType
+	}
+}
+
+func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) {
+	sdata := strings.TrimSpace(string(data))
+	var x time.Time
+	var err error
+
+	if sdata == "0000-00-00 00:00:00" ||
+		sdata == "0001-01-01 00:00:00" {
+	} else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column
+		// time stamp
+		sd, err := strconv.ParseInt(sdata, 10, 64)
+		if err == nil {
+			x = time.Unix(0, sd)
+			// !nashtsai! HACK mymysql driver is casuing Local location being change to CHAT and cause wrong time conversion
+			x = x.In(time.UTC)
+			x = time.Date(x.Year(), x.Month(), x.Day(), x.Hour(),
+				x.Minute(), x.Second(), x.Nanosecond(), session.Engine.TZLocation)
+			session.Engine.LogDebugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		} else {
+			session.Engine.LogDebugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		}
+	} else if len(sdata) > 19 {
+
+		x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation)
+		session.Engine.LogDebugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		if err != nil {
+			x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation)
+			session.Engine.LogDebugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		}
+		if err != nil {
+			x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation)
+			session.Engine.LogDebugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+		}
+
+	} else if len(sdata) == 19 {
+		x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation)
+		session.Engine.LogDebugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+	} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
+		x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation)
+		session.Engine.LogDebugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+	} else if col.SQLType.Name == core.Time {
+		if strings.Contains(sdata, " ") {
+			ssd := strings.Split(sdata, " ")
+			sdata = ssd[1]
+		}
+
+		sdata = strings.TrimSpace(sdata)
+		if session.Engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
+			sdata = sdata[len(sdata)-8:]
+		}
+
+		st := fmt.Sprintf("2006-01-02 %v", sdata)
+		x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation)
+		session.Engine.LogDebugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
+	} else {
+		outErr = errors.New(fmt.Sprintf("unsupported time format %v", sdata))
+		return
+	}
+	if err != nil {
+		outErr = errors.New(fmt.Sprintf("unsupported time format %v: %v", sdata, err))
+		return
+	}
+	outTime = x
+	return
+}
+
+// convert a db data([]byte) to a field value
+func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error {
+	if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+		return structConvert.FromDB(data)
+	}
+
+	if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
+		return structConvert.FromDB(data)
+	}
+
+	var v interface{}
+	key := col.Name
+	fieldType := fieldValue.Type()
+
+	switch fieldType.Kind() {
+	case reflect.Complex64, reflect.Complex128:
+		x := reflect.New(fieldType)
+
+		err := json.Unmarshal(data, x.Interface())
+		if err != nil {
+			session.Engine.LogError(err)
+			return err
+		}
+		fieldValue.Set(x.Elem())
+	case reflect.Slice, reflect.Array, reflect.Map:
+		v = data
+		t := fieldType.Elem()
+		k := t.Kind()
+		if col.SQLType.IsText() {
+			x := reflect.New(fieldType)
+			err := json.Unmarshal(data, x.Interface())
+			if err != nil {
+				session.Engine.LogError(err)
+				return err
+			}
+			fieldValue.Set(x.Elem())
+		} else if col.SQLType.IsBlob() {
+			if k == reflect.Uint8 {
+				fieldValue.Set(reflect.ValueOf(v))
+			} else {
+				x := reflect.New(fieldType)
+				err := json.Unmarshal(data, x.Interface())
+				if err != nil {
+					session.Engine.LogError(err)
+					return err
+				}
+				fieldValue.Set(x.Elem())
+			}
+		} else {
+			return ErrUnSupportedType
+		}
+	case reflect.String:
+		fieldValue.SetString(string(data))
+	case reflect.Bool:
+		d := string(data)
+		v, err := strconv.ParseBool(d)
+		if err != nil {
+			return fmt.Errorf("arg %v as bool: %s", key, err.Error())
+		}
+		fieldValue.Set(reflect.ValueOf(v))
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		sdata := string(data)
+		var x int64
+		var err error
+		// for mysql, when use bit, it returned \x01
+		if col.SQLType.Name == core.Bit &&
+			session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
+			if len(data) == 1 {
+				x = int64(data[0])
+			} else {
+				x = 0
+			}
+		} else if strings.HasPrefix(sdata, "0x") {
+			x, err = strconv.ParseInt(sdata, 16, 64)
+		} else if strings.HasPrefix(sdata, "0") {
+			x, err = strconv.ParseInt(sdata, 8, 64)
+		} else if strings.ToLower(sdata) == "true" {
+			x = 1
+		} else if strings.ToLower(sdata) == "false" {
+			x = 0
+		} else {
+			x, err = strconv.ParseInt(sdata, 10, 64)
+		}
+		if err != nil {
+			return fmt.Errorf("arg %v as int: %s", key, err.Error())
+		}
+		fieldValue.SetInt(x)
+	case reflect.Float32, reflect.Float64:
+		x, err := strconv.ParseFloat(string(data), 64)
+		if err != nil {
+			return fmt.Errorf("arg %v as float64: %s", key, err.Error())
+		}
+		fieldValue.SetFloat(x)
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+		x, err := strconv.ParseUint(string(data), 10, 64)
+		if err != nil {
+			return fmt.Errorf("arg %v as int: %s", key, err.Error())
+		}
+		fieldValue.SetUint(x)
+	//Currently only support Time type
+	case reflect.Struct:
+		if fieldType.ConvertibleTo(core.TimeType) {
+			x, err := session.byte2Time(col, data)
+			if err != nil {
+				return err
+			}
+			v = x
+			fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
+		} else if session.Statement.UseCascade {
+			table := session.Engine.autoMapType(*fieldValue)
+			if table != nil {
+				if len(table.PrimaryKeys) > 1 {
+					panic("unsupported composited primary key cascade")
+				}
+				var pk = make(core.PK, len(table.PrimaryKeys))
+				rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
+				switch rawValueType.Kind() {
+				case reflect.Int64:
+					x, err := strconv.ParseInt(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = x
+				case reflect.Int:
+					x, err := strconv.ParseInt(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = int(x)
+				case reflect.Int32:
+					x, err := strconv.ParseInt(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = int32(x)
+				case reflect.Int16:
+					x, err := strconv.ParseInt(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = int16(x)
+				case reflect.Int8:
+					x, err := strconv.ParseInt(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = int8(x)
+				case reflect.Uint64:
+					x, err := strconv.ParseUint(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = x
+				case reflect.Uint:
+					x, err := strconv.ParseUint(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = uint(x)
+				case reflect.Uint32:
+					x, err := strconv.ParseUint(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = uint32(x)
+				case reflect.Uint16:
+					x, err := strconv.ParseUint(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = uint16(x)
+				case reflect.Uint8:
+					x, err := strconv.ParseUint(string(data), 10, 64)
+					if err != nil {
+						return fmt.Errorf("arg %v as int: %s", key, err.Error())
+					}
+					pk[0] = uint8(x)
+				case reflect.String:
+					pk[0] = string(data)
+				default:
+					panic("unsupported primary key type cascade")
+				}
+
+				if !isPKZero(pk) {
+					// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+					// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+					// property to be fetched lazily
+					structInter := reflect.New(fieldValue.Type())
+					newsession := session.Engine.NewSession()
+					defer newsession.Close()
+					has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
+					if err != nil {
+						return err
+					}
+					if has {
+						v = structInter.Elem().Interface()
+						fieldValue.Set(reflect.ValueOf(v))
+					} else {
+						return errors.New("cascade obj is not exist!")
+					}
+				}
+			} else {
+				return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
+			}
+		}
+	case reflect.Ptr:
+		// !nashtsai! TODO merge duplicated codes above
+		//typeStr := fieldType.String()
+		switch fieldType {
+		// case "*string":
+		case core.PtrStringType:
+			x := string(data)
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*bool":
+		case core.PtrBoolType:
+			d := string(data)
+			v, err := strconv.ParseBool(d)
+			if err != nil {
+				return fmt.Errorf("arg %v as bool: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&v))
+		// case "*complex64":
+		case core.PtrComplex64Type:
+			var x complex64
+			err := json.Unmarshal(data, &x)
+			if err != nil {
+				session.Engine.LogError(err)
+				return err
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*complex128":
+		case core.PtrComplex128Type:
+			var x complex128
+			err := json.Unmarshal(data, &x)
+			if err != nil {
+				session.Engine.LogError(err)
+				return err
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*float64":
+		case core.PtrFloat64Type:
+			x, err := strconv.ParseFloat(string(data), 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as float64: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*float32":
+		case core.PtrFloat32Type:
+			var x float32
+			x1, err := strconv.ParseFloat(string(data), 32)
+			if err != nil {
+				return fmt.Errorf("arg %v as float32: %s", key, err.Error())
+			}
+			x = float32(x1)
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*time.Time":
+		case core.PtrTimeType:
+			x, err := session.byte2Time(col, data)
+			if err != nil {
+				return err
+			}
+			v = x
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*uint64":
+		case core.PtrUint64Type:
+			var x uint64
+			x, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*uint":
+		case core.PtrUintType:
+			var x uint
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint(x1)
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*uint32":
+		case core.PtrUint32Type:
+			var x uint32
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint32(x1)
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*uint8":
+		case core.PtrUint8Type:
+			var x uint8
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint8(x1)
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*uint16":
+		case core.PtrUint16Type:
+			var x uint16
+			x1, err := strconv.ParseUint(string(data), 10, 64)
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			x = uint16(x1)
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*int64":
+		case core.PtrInt64Type:
+			sdata := string(data)
+			var x int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.Engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int64(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x, err = strconv.ParseInt(sdata, 16, 64)
+			} else if strings.HasPrefix(sdata, "0") {
+				x, err = strconv.ParseInt(sdata, 8, 64)
+			} else {
+				x, err = strconv.ParseInt(sdata, 10, 64)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*int":
+		case core.PtrIntType:
+			sdata := string(data)
+			var x int
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.Engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*int32":
+		case core.PtrInt32Type:
+			sdata := string(data)
+			var x int32
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				session.Engine.dialect.DBType() == core.MYSQL {
+				if len(data) == 1 {
+					x = int32(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int32(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int32(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int32(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*int8":
+		case core.PtrInt8Type:
+			sdata := string(data)
+			var x int8
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.Engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int8(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int8(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int8(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int8(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		// case "*int16":
+		case core.PtrInt16Type:
+			sdata := string(data)
+			var x int16
+			var x1 int64
+			var err error
+			// for mysql, when use bit, it returned \x01
+			if col.SQLType.Name == core.Bit &&
+				strings.Contains(session.Engine.DriverName(), "mysql") {
+				if len(data) == 1 {
+					x = int16(data[0])
+				} else {
+					x = 0
+				}
+			} else if strings.HasPrefix(sdata, "0x") {
+				x1, err = strconv.ParseInt(sdata, 16, 64)
+				x = int16(x1)
+			} else if strings.HasPrefix(sdata, "0") {
+				x1, err = strconv.ParseInt(sdata, 8, 64)
+				x = int16(x1)
+			} else {
+				x1, err = strconv.ParseInt(sdata, 10, 64)
+				x = int16(x1)
+			}
+			if err != nil {
+				return fmt.Errorf("arg %v as int: %s", key, err.Error())
+			}
+			fieldValue.Set(reflect.ValueOf(&x))
+		default:
+			if fieldType.Elem().Kind() == reflect.Struct {
+				if session.Statement.UseCascade {
+					structInter := reflect.New(fieldType.Elem())
+					table := session.Engine.autoMapType(structInter.Elem())
+					if table != nil {
+						if len(table.PrimaryKeys) > 1 {
+							panic("unsupported composited primary key cascade")
+						}
+						var pk = make(core.PK, len(table.PrimaryKeys))
+						rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
+						switch rawValueType.Kind() {
+						case reflect.Int64:
+							x, err := strconv.ParseInt(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = x
+						case reflect.Int:
+							x, err := strconv.ParseInt(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = int(x)
+						case reflect.Int32:
+							x, err := strconv.ParseInt(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = int32(x)
+						case reflect.Int16:
+							x, err := strconv.ParseInt(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = int16(x)
+						case reflect.Int8:
+							x, err := strconv.ParseInt(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = x
+						case reflect.Uint64:
+							x, err := strconv.ParseUint(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = x
+						case reflect.Uint:
+							x, err := strconv.ParseUint(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = uint(x)
+						case reflect.Uint32:
+							x, err := strconv.ParseUint(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = uint32(x)
+						case reflect.Uint16:
+							x, err := strconv.ParseUint(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = uint16(x)
+						case reflect.Uint8:
+							x, err := strconv.ParseUint(string(data), 10, 64)
+							if err != nil {
+								return fmt.Errorf("arg %v as int: %s", key, err.Error())
+							}
+
+							pk[0] = uint8(x)
+						case reflect.String:
+							pk[0] = string(data)
+						default:
+							panic("unsupported primary key type cascade")
+						}
+
+						if !isPKZero(pk) {
+							// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+							// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+							// property to be fetched lazily
+							newsession := session.Engine.NewSession()
+							defer newsession.Close()
+							has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
+							if err != nil {
+								return err
+							}
+							if has {
+								v = structInter.Interface()
+								fieldValue.Set(reflect.ValueOf(v))
+							} else {
+								return errors.New("cascade obj is not exist!")
+							}
+						}
+					}
+				} else {
+					return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
+				}
+			}
+			return fmt.Errorf("unsupported type in Scan: %s", reflect.TypeOf(v).String())
+		}
+	default:
+		return fmt.Errorf("unsupported type in Scan: %s", reflect.TypeOf(v).String())
+	}
+
+	return nil
+}
+
+// convert a field value of a struct to interface for put into db
+func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) {
+	if fieldValue.CanAddr() {
+		if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+			data, err := fieldConvert.ToDB()
+			if err != nil {
+				return 0, err
+			} else {
+				return string(data), nil
+			}
+		}
+	}
+
+	if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
+		data, err := fieldConvert.ToDB()
+		if err != nil {
+			return 0, err
+		} else {
+			return string(data), nil
+		}
+	}
+
+	fieldType := fieldValue.Type()
+	k := fieldType.Kind()
+	if k == reflect.Ptr {
+		if fieldValue.IsNil() {
+			return nil, nil
+		} else if !fieldValue.IsValid() {
+			session.Engine.LogWarn("the field[", col.FieldName, "] is invalid")
+			return nil, nil
+		} else {
+			// !nashtsai! deference pointer type to instance type
+			fieldValue = fieldValue.Elem()
+			fieldType = fieldValue.Type()
+			k = fieldType.Kind()
+		}
+	}
+
+	switch k {
+	case reflect.Bool:
+		return fieldValue.Bool(), nil
+	case reflect.String:
+		return fieldValue.String(), nil
+	case reflect.Struct:
+		if fieldType.ConvertibleTo(core.TimeType) {
+			t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
+			if session.Engine.dialect.DBType() == core.MSSQL {
+				if t.IsZero() {
+					return nil, nil
+				}
+			}
+			tf := session.Engine.FormatTime(col.SQLType.Name, t)
+			return tf, nil
+		}
+		if fieldTable, ok := session.Engine.Tables[fieldValue.Type()]; ok {
+			if len(fieldTable.PrimaryKeys) == 1 {
+				pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
+				return pkField.Interface(), nil
+			} else {
+				return 0, fmt.Errorf("no primary key for col %v", col.Name)
+			}
+		} else {
+			return 0, fmt.Errorf("Unsupported type %v", fieldValue.Type())
+		}
+	case reflect.Complex64, reflect.Complex128:
+		bytes, err := json.Marshal(fieldValue.Interface())
+		if err != nil {
+			session.Engine.LogError(err)
+			return 0, err
+		}
+		return string(bytes), nil
+	case reflect.Array, reflect.Slice, reflect.Map:
+		if !fieldValue.IsValid() {
+			return fieldValue.Interface(), nil
+		}
+
+		if col.SQLType.IsText() {
+			bytes, err := json.Marshal(fieldValue.Interface())
+			if err != nil {
+				session.Engine.LogError(err)
+				return 0, err
+			}
+			return string(bytes), nil
+		} else if col.SQLType.IsBlob() {
+			var bytes []byte
+			var err error
+			if (k == reflect.Array || k == reflect.Slice) &&
+				(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
+				bytes = fieldValue.Bytes()
+			} else {
+				bytes, err = json.Marshal(fieldValue.Interface())
+				if err != nil {
+					session.Engine.LogError(err)
+					return 0, err
+				}
+			}
+			return bytes, nil
+		} else {
+			return nil, ErrUnSupportedType
+		}
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+		return int64(fieldValue.Uint()), nil
+	default:
+		return fieldValue.Interface(), nil
+	}
+}
+
+func (session *Session) innerInsert(bean interface{}) (int64, error) {
+	table := session.Engine.TableInfo(bean)
+	session.Statement.RefTable = table
+
+	// handle BeforeInsertProcessor
+	for _, closure := range session.beforeClosures {
+		closure(bean)
+	}
+	cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
+
+	if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok {
+		processor.BeforeInsert()
+	}
+	// --
+
+	colNames, args, err := genCols(table, session, bean, false, false)
+	if err != nil {
+		return 0, err
+	}
+
+	// insert expr columns, override if exists
+	exprColumns := session.Statement.getExpr()
+	exprColVals := make([]string, 0, len(exprColumns))
+	for _, v := range exprColumns {
+		// remove the expr columns
+		for i, colName := range colNames {
+			if colName == v.colName {
+				colNames = append(colNames[:i], colNames[i+1:]...)
+				args = append(args[:i], args[i+1:]...)
+			}
+		}
+
+		// append expr column to the end
+		colNames = append(colNames, v.colName)
+		exprColVals = append(exprColVals, v.expr)
+	}
+
+	colPlaces := strings.Repeat("?, ", len(colNames)-len(exprColumns))
+	if len(exprColVals) > 0 {
+		colPlaces = colPlaces + strings.Join(exprColVals, ", ")
+	} else {
+		colPlaces = colPlaces[0 : len(colPlaces)-2]
+	}
+
+	sqlStr := fmt.Sprintf("INSERT INTO %v%v%v (%v%v%v) VALUES (%v)",
+		session.Engine.QuoteStr(),
+		session.Statement.TableName(),
+		session.Engine.QuoteStr(),
+		session.Engine.QuoteStr(),
+		strings.Join(colNames, session.Engine.Quote(", ")),
+		session.Engine.QuoteStr(),
+		colPlaces)
+
+	handleAfterInsertProcessorFunc := func(bean interface{}) {
+
+		if session.IsAutoCommit {
+			for _, closure := range session.afterClosures {
+				closure(bean)
+			}
+			if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
+				processor.AfterInsert()
+			}
+		} else {
+			lenAfterClosures := len(session.afterClosures)
+			if lenAfterClosures > 0 {
+				if value, has := session.afterInsertBeans[bean]; has && value != nil {
+					*value = append(*value, session.afterClosures...)
+				} else {
+					afterClosures := make([]func(interface{}), lenAfterClosures)
+					copy(afterClosures, session.afterClosures)
+					session.afterInsertBeans[bean] = &afterClosures
+				}
+
+			} else {
+				if _, ok := interface{}(bean).(AfterInsertProcessor); ok {
+					session.afterInsertBeans[bean] = nil
+				}
+			}
+		}
+		cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
+	}
+
+	// for postgres, many of them didn't implement lastInsertId, so we should
+	// implemented it ourself.
+
+	if session.Engine.DriverName() != core.POSTGRES || table.AutoIncrement == "" {
+		res, err := session.exec(sqlStr, args...)
+		if err != nil {
+			return 0, err
+		} else {
+			handleAfterInsertProcessorFunc(bean)
+		}
+
+		if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+			session.cacheInsert(session.Statement.TableName())
+		}
+
+		if table.Version != "" && session.Statement.checkVersion {
+			verValue, err := table.VersionColumn().ValueOf(bean)
+			if err != nil {
+				session.Engine.LogError(err)
+			} else if verValue.IsValid() && verValue.CanSet() {
+				verValue.SetInt(1)
+			}
+		}
+
+		if table.AutoIncrement == "" {
+			return res.RowsAffected()
+		}
+
+		var id int64 = 0
+		id, err = res.LastInsertId()
+		if err != nil || id <= 0 {
+			return res.RowsAffected()
+		}
+
+		aiValue, err := table.AutoIncrColumn().ValueOf(bean)
+		if err != nil {
+			session.Engine.LogError(err)
+		}
+
+		if aiValue == nil || !aiValue.IsValid() /*|| aiValue.Int() != 0*/ || !aiValue.CanSet() {
+			return res.RowsAffected()
+		}
+
+		var v interface{} = id
+		switch aiValue.Type().Kind() {
+		case reflect.Int32:
+			v = int32(id)
+		case reflect.Int:
+			v = int(id)
+		case reflect.Uint32:
+			v = uint32(id)
+		case reflect.Uint64:
+			v = uint64(id)
+		case reflect.Uint:
+			v = uint(id)
+		}
+		aiValue.Set(reflect.ValueOf(v))
+
+		return res.RowsAffected()
+	} else {
+		//assert table.AutoIncrement != ""
+		sqlStr = sqlStr + " RETURNING " + session.Engine.Quote(table.AutoIncrement)
+		res, err := session.query(sqlStr, args...)
+
+		if err != nil {
+			return 0, err
+		} else {
+			handleAfterInsertProcessorFunc(bean)
+		}
+
+		if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+			session.cacheInsert(session.Statement.TableName())
+		}
+
+		if table.Version != "" && session.Statement.checkVersion {
+			verValue, err := table.VersionColumn().ValueOf(bean)
+			if err != nil {
+				session.Engine.LogError(err)
+			} else if verValue.IsValid() && verValue.CanSet() {
+				verValue.SetInt(1)
+			}
+		}
+
+		if len(res) < 1 {
+			return 0, errors.New("insert no error but not returned id")
+		}
+
+		idByte := res[0][table.AutoIncrement]
+		id, err := strconv.ParseInt(string(idByte), 10, 64)
+		if err != nil {
+			return 1, err
+		}
+
+		aiValue, err := table.AutoIncrColumn().ValueOf(bean)
+		if err != nil {
+			session.Engine.LogError(err)
+		}
+
+		if aiValue == nil || !aiValue.IsValid() /*|| aiValue. != 0*/ || !aiValue.CanSet() {
+			return 1, nil
+		}
+
+		var v interface{} = id
+		switch aiValue.Type().Kind() {
+		case reflect.Int32:
+			v = int32(id)
+		case reflect.Int:
+			v = int(id)
+		case reflect.Uint32:
+			v = uint32(id)
+		case reflect.Uint64:
+			v = uint64(id)
+		case reflect.Uint:
+			v = uint(id)
+		}
+		aiValue.Set(reflect.ValueOf(v))
+
+		return 1, nil
+	}
+}
+
+// Method InsertOne insert only one struct into database as a record.
+// The in parameter bean must a struct or a point to struct. The return
+// parameter is inserted and error
+func (session *Session) InsertOne(bean interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	return session.innerInsert(bean)
+}
+
+func (statement *Statement) convertUpdateSql(sqlStr string) (string, string) {
+	if statement.RefTable == nil || len(statement.RefTable.PrimaryKeys) != 1 {
+		return "", ""
+	}
+
+	colstrs := statement.JoinColumns(statement.RefTable.PKColumns())
+	sqls := splitNNoCase(sqlStr, "where", 2)
+	if len(sqls) != 2 {
+		if len(sqls) == 1 {
+			return sqls[0], fmt.Sprintf("SELECT %v FROM %v",
+				colstrs, statement.Engine.Quote(statement.TableName()))
+		}
+		return "", ""
+	}
+
+	var whereStr = sqls[1]
+
+	//TODO: for postgres only, if any other database?
+	var paraStr string
+	if statement.Engine.dialect.DBType() == core.POSTGRES {
+		paraStr = "$"
+	} else if statement.Engine.dialect.DBType() == core.MSSQL {
+		paraStr = ":"
+	}
+
+	if paraStr != "" {
+		if strings.Contains(sqls[1], paraStr) {
+			dollers := strings.Split(sqls[1], paraStr)
+			whereStr = dollers[0]
+			for i, c := range dollers[1:] {
+				ccs := strings.SplitN(c, " ", 2)
+				whereStr += fmt.Sprintf(paraStr+"%v %v", i+1, ccs[1])
+			}
+		}
+	}
+
+	return sqls[0], fmt.Sprintf("SELECT %v FROM %v WHERE %v",
+		colstrs, statement.Engine.Quote(statement.TableName()),
+		whereStr)
+}
+
+func (session *Session) cacheInsert(tables ...string) error {
+	if session.Statement.RefTable == nil {
+		return ErrCacheFailed
+	}
+
+	table := session.Statement.RefTable
+	cacher := session.Engine.getCacher2(table)
+
+	for _, t := range tables {
+		session.Engine.LogDebug("[cache] clear sql:", t)
+		cacher.ClearIds(t)
+	}
+
+	return nil
+}
+
+func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error {
+	if session.Statement.RefTable == nil ||
+		session.Tx != nil {
+		return ErrCacheFailed
+	}
+
+	oldhead, newsql := session.Statement.convertUpdateSql(sqlStr)
+	if newsql == "" {
+		return ErrCacheFailed
+	}
+	for _, filter := range session.Engine.dialect.Filters() {
+		newsql = filter.Do(newsql, session.Engine.dialect, session.Statement.RefTable)
+	}
+	session.Engine.LogDebug("[cacheUpdate] new sql", oldhead, newsql)
+
+	var nStart int
+	if len(args) > 0 {
+		if strings.Index(sqlStr, "?") > -1 {
+			nStart = strings.Count(oldhead, "?")
+		} else {
+			// only for pq, TODO: if any other databse?
+			nStart = strings.Count(oldhead, "$")
+		}
+	}
+	table := session.Statement.RefTable
+	cacher := session.Engine.getCacher2(table)
+	tableName := session.Statement.TableName()
+	session.Engine.LogDebug("[cacheUpdate] get cache sql", newsql, args[nStart:])
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
+	if err != nil {
+		rows, err := session.DB().Query(newsql, args[nStart:]...)
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+
+		ids = make([]core.PK, 0)
+		for rows.Next() {
+			var res = make([]string, len(table.PrimaryKeys))
+			err = rows.ScanSlice(&res)
+			if err != nil {
+				return err
+			}
+			var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
+			for i, col := range table.PKColumns() {
+				if col.SQLType.IsNumeric() {
+					n, err := strconv.ParseInt(res[i], 10, 64)
+					if err != nil {
+						return err
+					}
+					pk[i] = n
+				} else if col.SQLType.IsText() {
+					pk[i] = res[i]
+				} else {
+					return errors.New("not supported")
+				}
+			}
+
+			ids = append(ids, pk)
+		}
+		session.Engine.LogDebug("[cacheUpdate] find updated id", ids)
+	} /*else {
+	    session.Engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args)
+	    cacher.DelIds(tableName, genSqlKey(newsql, args))
+	}*/
+
+	for _, id := range ids {
+		sid, err := id.ToString()
+		if err != nil {
+			return err
+		}
+		if bean := cacher.GetBean(tableName, sid); bean != nil {
+			sqls := splitNNoCase(sqlStr, "where", 2)
+			if len(sqls) == 0 || len(sqls) > 2 {
+				return ErrCacheFailed
+			}
+
+			sqls = splitNNoCase(sqls[0], "set", 2)
+			if len(sqls) != 2 {
+				return ErrCacheFailed
+			}
+			kvs := strings.Split(strings.TrimSpace(sqls[1]), ",")
+			for idx, kv := range kvs {
+				sps := strings.SplitN(kv, "=", 2)
+				sps2 := strings.Split(sps[0], ".")
+				colName := sps2[len(sps2)-1]
+				if strings.Contains(colName, "`") {
+					colName = strings.TrimSpace(strings.Replace(colName, "`", "", -1))
+				} else if strings.Contains(colName, session.Engine.QuoteStr()) {
+					colName = strings.TrimSpace(strings.Replace(colName, session.Engine.QuoteStr(), "", -1))
+				} else {
+					session.Engine.LogDebug("[cacheUpdate] cannot find column", tableName, colName)
+					return ErrCacheFailed
+				}
+
+				if col := table.GetColumn(colName); col != nil {
+					fieldValue, err := col.ValueOf(bean)
+					if err != nil {
+						session.Engine.LogError(err)
+					} else {
+						session.Engine.LogDebug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
+						if col.IsVersion && session.Statement.checkVersion {
+							fieldValue.SetInt(fieldValue.Int() + 1)
+						} else {
+							fieldValue.Set(reflect.ValueOf(args[idx]))
+						}
+					}
+				} else {
+					session.Engine.LogErrorf("[cacheUpdate] ERROR: column %v is not table %v's",
+						colName, table.Name)
+				}
+			}
+
+			session.Engine.LogDebug("[cacheUpdate] update cache", tableName, id, bean)
+			cacher.PutBean(tableName, sid, bean)
+		}
+	}
+	session.Engine.LogDebug("[cacheUpdate] clear cached table sql:", tableName)
+	cacher.ClearIds(tableName)
+	return nil
+}
+
+// Update records, bean's non-empty fields are updated contents,
+// condiBean' non-empty filds are conditions
+// CAUTION:
+//        1.bool will defaultly be updated content nor conditions
+//         You should call UseBool if you have bool to use.
+//        2.float32 & float64 may be not inexact as conditions
+func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	t := rType(bean)
+
+	var colNames []string
+	var args []interface{}
+	var table *core.Table
+
+	// handle before update processors
+	for _, closure := range session.beforeClosures {
+		closure(bean)
+	}
+	cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
+	if processor, ok := interface{}(bean).(BeforeUpdateProcessor); ok {
+		processor.BeforeUpdate()
+	}
+	// --
+
+	var err error
+	if t.Kind() == reflect.Struct {
+		table = session.Engine.TableInfo(bean)
+		session.Statement.RefTable = table
+
+		if session.Statement.ColumnStr == "" {
+			colNames, args = buildUpdates(session.Engine, table, bean, false, false,
+				false, false, session.Statement.allUseBool, session.Statement.useAllCols,
+				session.Statement.mustColumnMap, session.Statement.columnMap, true)
+		} else {
+			colNames, args, err = genCols(table, session, bean, true, true)
+			if err != nil {
+				return 0, err
+			}
+		}
+	} else if t.Kind() == reflect.Map {
+		if session.Statement.RefTable == nil {
+			return 0, ErrTableNotFound
+		}
+		table = session.Statement.RefTable
+		colNames = make([]string, 0)
+		args = make([]interface{}, 0)
+		bValue := reflect.Indirect(reflect.ValueOf(bean))
+
+		for _, v := range bValue.MapKeys() {
+			colNames = append(colNames, session.Engine.Quote(v.String())+" = ?")
+			args = append(args, bValue.MapIndex(v).Interface())
+		}
+	} else {
+		return 0, ErrParamsType
+	}
+
+	if session.Statement.UseAutoTime && table.Updated != "" {
+		colNames = append(colNames, session.Engine.Quote(table.Updated)+" = ?")
+		col := table.UpdatedColumn()
+		val, t := session.Engine.NowTime2(col.SQLType.Name)
+		args = append(args, val)
+
+		var colName = col.Name
+		session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+			col := table.GetColumn(colName)
+			setColumnTime(bean, col, t)
+		})
+	}
+
+	//for update action to like "column = column + ?"
+	incColumns := session.Statement.getInc()
+	for _, v := range incColumns {
+		colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+session.Engine.Quote(v.colName)+" + ?")
+		args = append(args, v.arg)
+	}
+	//for update action to like "column = column - ?"
+	decColumns := session.Statement.getDec()
+	for _, v := range decColumns {
+		colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+session.Engine.Quote(v.colName)+" - ?")
+		args = append(args, v.arg)
+	}
+	//for update action to like "column = expression"
+	exprColumns := session.Statement.getExpr()
+	for _, v := range exprColumns {
+		colNames = append(colNames, session.Engine.Quote(v.colName)+" = "+v.expr)
+	}
+
+	var condiColNames []string
+	var condiArgs []interface{}
+
+	if len(condiBean) > 0 {
+		condiColNames, condiArgs = buildConditions(session.Engine, session.Statement.RefTable, condiBean[0], true, true,
+			false, true, session.Statement.allUseBool, session.Statement.useAllCols,
+			session.Statement.unscoped, session.Statement.mustColumnMap)
+	}
+
+	var condition = ""
+	session.Statement.processIdParam()
+	st := session.Statement
+	defer session.resetStatement()
+	if st.WhereStr != "" {
+		condition = fmt.Sprintf("%v", st.WhereStr)
+	}
+
+	if condition == "" {
+		if len(condiColNames) > 0 {
+			condition = fmt.Sprintf("%v", strings.Join(condiColNames, " "+session.Engine.Dialect().AndStr()+" "))
+		}
+	} else {
+		if len(condiColNames) > 0 {
+			condition = fmt.Sprintf("(%v) %v (%v)", condition,
+				session.Engine.Dialect().AndStr(), strings.Join(condiColNames, " "+session.Engine.Dialect().AndStr()+" "))
+		}
+	}
+
+	var sqlStr, inSql string
+	var inArgs []interface{}
+	doIncVer := false
+	var verValue *reflect.Value
+	if table.Version != "" && session.Statement.checkVersion {
+		if condition != "" {
+			condition = fmt.Sprintf("WHERE (%v) %v %v = ?", condition, session.Engine.Dialect().AndStr(),
+				session.Engine.Quote(table.Version))
+		} else {
+			condition = fmt.Sprintf("WHERE %v = ?", session.Engine.Quote(table.Version))
+		}
+		inSql, inArgs = session.Statement.genInSql()
+		if len(inSql) > 0 {
+			if condition != "" {
+				condition += " " + session.Engine.Dialect().AndStr() + " " + inSql
+			} else {
+				condition = "WHERE " + inSql
+			}
+		}
+
+		if st.LimitN > 0 {
+			condition = condition + fmt.Sprintf(" LIMIT %d", st.LimitN)
+		}
+
+		sqlStr = fmt.Sprintf("UPDATE %v SET %v, %v %v",
+			session.Engine.Quote(session.Statement.TableName()),
+			strings.Join(colNames, ", "),
+			session.Engine.Quote(table.Version)+" = "+session.Engine.Quote(table.Version)+" + 1",
+			condition)
+
+		verValue, err = table.VersionColumn().ValueOf(bean)
+		if err != nil {
+			return 0, err
+		}
+
+		condiArgs = append(condiArgs, verValue.Interface())
+		doIncVer = true
+	} else {
+		if condition != "" {
+			condition = "WHERE " + condition
+		}
+		inSql, inArgs = session.Statement.genInSql()
+		if len(inSql) > 0 {
+			if condition != "" {
+				condition += " " + session.Engine.Dialect().AndStr() + " " + inSql
+			} else {
+				condition = "WHERE " + inSql
+			}
+		}
+
+		if st.LimitN > 0 {
+			condition = condition + fmt.Sprintf(" LIMIT %d", st.LimitN)
+		}
+
+		sqlStr = fmt.Sprintf("UPDATE %v SET %v %v",
+			session.Engine.Quote(session.Statement.TableName()),
+			strings.Join(colNames, ", "),
+			condition)
+	}
+
+	args = append(args, st.Params...)
+	args = append(args, inArgs...)
+	args = append(args, condiArgs...)
+
+	res, err := session.exec(sqlStr, args...)
+	if err != nil {
+		return 0, err
+	} else if doIncVer {
+		if verValue != nil && verValue.IsValid() && verValue.CanSet() {
+			verValue.SetInt(verValue.Int() + 1)
+		}
+	}
+
+	if cacher := session.Engine.getCacher2(table); cacher != nil && session.Statement.UseCache {
+		cacher.ClearIds(session.Statement.TableName())
+		cacher.ClearBeans(session.Statement.TableName())
+	}
+
+	// handle after update processors
+	if session.IsAutoCommit {
+		for _, closure := range session.afterClosures {
+			closure(bean)
+		}
+		if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
+			session.Engine.LogDebug("[event]", session.Statement.TableName(), " has after update processor")
+			processor.AfterUpdate()
+		}
+	} else {
+		lenAfterClosures := len(session.afterClosures)
+		if lenAfterClosures > 0 {
+			if value, has := session.afterUpdateBeans[bean]; has && value != nil {
+				*value = append(*value, session.afterClosures...)
+			} else {
+				afterClosures := make([]func(interface{}), lenAfterClosures)
+				copy(afterClosures, session.afterClosures)
+				session.afterUpdateBeans[bean] = &afterClosures
+			}
+
+		} else {
+			if _, ok := interface{}(bean).(AfterInsertProcessor); ok {
+				session.afterUpdateBeans[bean] = nil
+			}
+		}
+	}
+	cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
+	// --
+
+	return res.RowsAffected()
+}
+
+func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error {
+	if session.Statement.RefTable == nil ||
+		session.Tx != nil {
+		return ErrCacheFailed
+	}
+
+	for _, filter := range session.Engine.dialect.Filters() {
+		sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
+	}
+
+	newsql := session.Statement.convertIdSql(sqlStr)
+	if newsql == "" {
+		return ErrCacheFailed
+	}
+
+	cacher := session.Engine.getCacher2(session.Statement.RefTable)
+	tableName := session.Statement.TableName()
+	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
+	if err != nil {
+		resultsSlice, err := session.query(newsql, args...)
+		if err != nil {
+			return err
+		}
+		ids = make([]core.PK, 0)
+		if len(resultsSlice) > 0 {
+			for _, data := range resultsSlice {
+				var id int64
+				var pk core.PK = make([]interface{}, 0)
+				for _, col := range session.Statement.RefTable.PKColumns() {
+					if v, ok := data[col.Name]; !ok {
+						return errors.New("no id")
+					} else {
+						if col.SQLType.IsText() {
+							pk = append(pk, string(v))
+						} else if col.SQLType.IsNumeric() {
+							id, err = strconv.ParseInt(string(v), 10, 64)
+							if err != nil {
+								return err
+							}
+							pk = append(pk, id)
+						} else {
+							return errors.New("not supported primary key type")
+						}
+					}
+				}
+				ids = append(ids, pk)
+			}
+		}
+	} /*else {
+	    session.Engine.LogDebug("delete cache sql %v", newsql)
+	    cacher.DelIds(tableName, genSqlKey(newsql, args))
+	}*/
+
+	for _, id := range ids {
+		session.Engine.LogDebug("[cacheDelete] delete cache obj", tableName, id)
+		sid, err := id.ToString()
+		if err != nil {
+			return err
+		}
+		cacher.DelBean(tableName, sid)
+	}
+	session.Engine.LogDebug("[cacheDelete] clear cache sql", tableName)
+	cacher.ClearIds(tableName)
+	return nil
+}
+
+// Delete records, bean's non-empty fields are conditions
+func (session *Session) Delete(bean interface{}) (int64, error) {
+	defer session.resetStatement()
+	if session.IsAutoClose {
+		defer session.Close()
+	}
+
+	// handle before delete processors
+	for _, closure := range session.beforeClosures {
+		closure(bean)
+	}
+	cleanupProcessorsClosures(&session.beforeClosures)
+
+	if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
+		processor.BeforeDelete()
+	}
+	// --
+
+	table := session.Engine.TableInfo(bean)
+	session.Statement.RefTable = table
+	colNames, args := buildConditions(session.Engine, table, bean, true, true,
+		false, true, session.Statement.allUseBool, session.Statement.useAllCols,
+		session.Statement.unscoped, session.Statement.mustColumnMap)
+
+	var condition = ""
+	var andStr = session.Engine.dialect.AndStr()
+
+	session.Statement.processIdParam()
+	if session.Statement.WhereStr != "" {
+		condition = session.Statement.WhereStr
+		if len(colNames) > 0 {
+			condition += " " + andStr + " " + strings.Join(colNames, " "+andStr+" ")
+		}
+	} else {
+		condition = strings.Join(colNames, " "+andStr+" ")
+	}
+	inSql, inArgs := session.Statement.genInSql()
+	if len(inSql) > 0 {
+		if len(condition) > 0 {
+			condition += " " + andStr + " "
+		}
+		condition += inSql
+		args = append(args, inArgs...)
+	}
+	if len(condition) == 0 {
+		return 0, ErrNeedDeletedCond
+	}
+
+	sqlStr, sqlStrForCache := "", ""
+	argsForCache := make([]interface{}, 0, len(args)*2)
+	if session.Statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
+		sqlStr = fmt.Sprintf("DELETE FROM %v WHERE %v",
+			session.Engine.Quote(session.Statement.TableName()), condition)
+
+		sqlStrForCache = sqlStr
+		copy(argsForCache, args)
+		argsForCache = append(session.Statement.Params, argsForCache...)
+	} else {
+		// !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache.
+		sqlStrForCache = fmt.Sprintf("DELETE FROM %v WHERE %v",
+			session.Engine.Quote(session.Statement.TableName()), condition)
+		copy(argsForCache, args)
+		argsForCache = append(session.Statement.Params, argsForCache...)
+
+		deletedColumn := table.DeletedColumn()
+		sqlStr = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
+			session.Engine.Quote(session.Statement.TableName()),
+			session.Engine.Quote(deletedColumn.Name),
+			condition)
+
+		// !oinume! Insert NowTime to the head of session.Statement.Params
+		session.Statement.Params = append(session.Statement.Params, "")
+		paramsLen := len(session.Statement.Params)
+		copy(session.Statement.Params[1:paramsLen], session.Statement.Params[0:paramsLen-1])
+
+		val, t := session.Engine.NowTime2(deletedColumn.SQLType.Name)
+		session.Statement.Params[0] = val
+
+		var colName = deletedColumn.Name
+		session.afterClosures = append(session.afterClosures, func(bean interface{}) {
+			col := table.GetColumn(colName)
+			setColumnTime(bean, col, t)
+		})
+	}
+
+	args = append(session.Statement.Params, args...)
+
+	if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache {
+		session.cacheDelete(sqlStrForCache, argsForCache...)
+	}
+
+	res, err := session.exec(sqlStr, args...)
+	if err != nil {
+		return 0, err
+	}
+
+	// handle after delete processors
+	if session.IsAutoCommit {
+		for _, closure := range session.afterClosures {
+			closure(bean)
+		}
+		if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
+			processor.AfterDelete()
+		}
+	} else {
+		lenAfterClosures := len(session.afterClosures)
+		if lenAfterClosures > 0 {
+			if value, has := session.afterDeleteBeans[bean]; has && value != nil {
+				*value = append(*value, session.afterClosures...)
+			} else {
+				afterClosures := make([]func(interface{}), lenAfterClosures)
+				copy(afterClosures, session.afterClosures)
+				session.afterDeleteBeans[bean] = &afterClosures
+			}
+		} else {
+			if _, ok := interface{}(bean).(AfterInsertProcessor); ok {
+				session.afterDeleteBeans[bean] = nil
+			}
+		}
+	}
+	cleanupProcessorsClosures(&session.afterClosures)
+	// --
+
+	return res.RowsAffected()
+}
+
+func (s *Session) Sync2(beans ...interface{}) error {
+	engine := s.Engine
+
+	tables, err := engine.DBMetas()
+	if err != nil {
+		return err
+	}
+
+	structTables := make([]*core.Table, 0)
+
+	for _, bean := range beans {
+		table := engine.TableInfo(bean)
+		structTables = append(structTables, table)
+
+		var oriTable *core.Table
+		for _, tb := range tables {
+			if tb.Name == table.Name {
+				oriTable = tb
+				break
+			}
+		}
+
+		if oriTable == nil {
+			err = engine.StoreEngine(s.Statement.StoreEngine).CreateTable(bean)
+			if err != nil {
+				return err
+			}
+
+			err = engine.CreateUniques(bean)
+			if err != nil {
+				return err
+			}
+
+			err = engine.CreateIndexes(bean)
+			if err != nil {
+				return err
+			}
+		} else {
+			for _, col := range table.Columns() {
+				var oriCol *core.Column
+				for _, col2 := range oriTable.Columns() {
+					if col.Name == col2.Name {
+						oriCol = col2
+						break
+					}
+				}
+
+				if oriCol != nil {
+					expectedType := engine.dialect.SqlType(col)
+					curType := engine.dialect.SqlType(oriCol)
+					if expectedType != curType {
+						if expectedType == core.Text &&
+							strings.HasPrefix(curType, core.Varchar) {
+							// currently only support mysql & postgres
+							if engine.dialect.DBType() == core.MYSQL ||
+								engine.dialect.DBType() == core.POSTGRES {
+								engine.LogInfof("Table %s column %s change type from %s to %s\n",
+									table.Name, col.Name, curType, expectedType)
+								_, err = engine.Exec(engine.dialect.ModifyColumnSql(table.Name, col))
+							} else {
+								engine.LogWarnf("Table %s column %s db type is %s, struct type is %s\n",
+									table.Name, col.Name, curType, expectedType)
+							}
+						} else {
+							engine.LogWarnf("Table %s column %s db type is %s, struct type is %s",
+								table.Name, col.Name, curType, expectedType)
+						}
+					}
+					if col.Default != oriCol.Default {
+						engine.LogWarnf("Table %s Column %s db default is %s, struct default is %s",
+							table.Name, col.Name, oriCol.Default, col.Default)
+					}
+					if col.Nullable != oriCol.Nullable {
+						engine.LogWarnf("Table %s Column %s db nullable is %v, struct nullable is %v",
+							table.Name, col.Name, oriCol.Nullable, col.Nullable)
+					}
+				} else {
+					session := engine.NewSession()
+					session.Statement.RefTable = table
+					defer session.Close()
+					err = session.addColumn(col.Name)
+				}
+				if err != nil {
+					return err
+				}
+			}
+
+			var foundIndexNames = make(map[string]bool)
+
+			for name, index := range table.Indexes {
+				var oriIndex *core.Index
+				for name2, index2 := range oriTable.Indexes {
+					if index.Equal(index2) {
+						oriIndex = index2
+						foundIndexNames[name2] = true
+						break
+					}
+				}
+
+				if oriIndex != nil {
+					if oriIndex.Type != index.Type {
+						sql := engine.dialect.DropIndexSql(table.Name, oriIndex)
+						_, err = engine.Exec(sql)
+						if err != nil {
+							return err
+						}
+						oriIndex = nil
+					}
+				}
+
+				if oriIndex == nil {
+					if index.Type == core.UniqueType {
+						session := engine.NewSession()
+						session.Statement.RefTable = table
+						defer session.Close()
+						err = session.addUnique(table.Name, name)
+					} else if index.Type == core.IndexType {
+						session := engine.NewSession()
+						session.Statement.RefTable = table
+						defer session.Close()
+						err = session.addIndex(table.Name, name)
+					}
+					if err != nil {
+						return err
+					}
+				}
+			}
+
+			for name2, index2 := range oriTable.Indexes {
+				if _, ok := foundIndexNames[name2]; !ok {
+					sql := engine.dialect.DropIndexSql(table.Name, index2)
+					_, err = engine.Exec(sql)
+					if err != nil {
+						return err
+					}
+				}
+			}
+		}
+	}
+
+	for _, table := range tables {
+		var oriTable *core.Table
+		for _, structTable := range structTables {
+			if table.Name == structTable.Name {
+				oriTable = structTable
+				break
+			}
+		}
+
+		if oriTable == nil {
+			engine.LogWarnf("Table %s has no struct to mapping it", table.Name)
+			continue
+		}
+
+		for _, colName := range table.ColumnsSeq() {
+			if oriTable.GetColumn(colName) == nil {
+				engine.LogWarnf("Table %s has column %s but struct has not related field",
+					table.Name, colName)
+			}
+		}
+	}
+	return nil
+}
+
+// Always disable struct tag "deleted"
+func (session *Session) Unscoped() *Session {
+	session.Statement.Unscoped()
+	return session
+}

+ 660 - 0
sessionplus.go

@@ -0,0 +1,660 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"encoding/json"
+	"errors"
+//	"fmt"
+	"reflect"
+	"regexp"
+	"strings"
+	"time"
+
+	"github.com/xormplus/core"
+	"github.com/Chronokeeper/anyxml"
+)
+
+type ResultBean struct {
+	Has bool
+	Result interface{}
+	Err    error
+}
+
+func (resultBean ResultBean) Json() (bool,string, error) {
+	if resultBean.Err != nil {
+		return resultBean.Has,"", resultBean.Err
+	}
+	if !resultBean.Has{
+		return resultBean.Has,"", nil
+	}
+	result,err:= JSONString(resultBean.Result, true)
+	return resultBean.Has,result,err
+}
+
+func (session *Session) GetFirst(bean interface{}) ResultBean {
+	has, err := session.Get(bean)
+	r := ResultBean{Has: has,Result:bean, Err: err}
+	return r
+}
+
+func (resultBean ResultBean) Xml() (bool,string, error) {
+	
+	if resultBean.Err != nil {
+		return false,"", resultBean.Err
+	}
+	if !resultBean.Has{
+		return resultBean.Has,"", nil
+	}
+	has,result,err:=resultBean.Json()
+	if err != nil {
+		return false,"", err
+	}
+	if !has{
+		return has,"", nil
+	}
+	var anydata = []byte(result)
+	var i interface{}
+	err = json.Unmarshal(anydata, &i)
+	if err != nil {
+		return false,"", err
+	}
+	resultByte, err := anyxml.Xml(i)
+	if err != nil {
+		return false,"", err
+	}
+
+	return resultBean.Has,string(resultByte),err
+}
+
+func (resultBean ResultBean) XmlIndent(prefix string, indent string, recordTag string) (bool,string, error) {
+	if resultBean.Err != nil {
+		return false,"", resultBean.Err
+	}
+	if !resultBean.Has{
+		return resultBean.Has,"", nil
+	}
+	has,result,err:=resultBean.Json()
+	if err != nil {
+		return false,"", err
+	}
+	if !has{
+		return has,"", nil
+	}
+	var anydata = []byte(result)
+	var i interface{}
+	err = json.Unmarshal(anydata, &i)
+	if err != nil {
+		return false,"", err
+	}
+	resultByte, err := anyxml.XmlIndent(i,prefix,indent,recordTag)
+	if err != nil {
+		return false,"", err
+	}
+
+	return resultBean.Has,string(resultByte),err
+}
+
+type ResultMap struct {
+	Result []map[string]interface{}
+	Err    error
+}
+
+func (resultMap ResultMap) Json() (string, error) {
+
+	if resultMap.Err != nil {
+		return "", resultMap.Err
+	}
+	return JSONString(resultMap.Result, true)
+}
+
+func (resultMap ResultMap) Xml() (string, error) {
+	if resultMap.Err != nil {
+		return "", resultMap.Err
+	}
+	results, err := anyxml.Xml(resultMap.Result)
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func (resultMap ResultMap) XmlIndent(prefix string, indent string, recordTag string) (string, error) {
+	if resultMap.Err != nil {
+		return "", resultMap.Err
+	}
+
+	results, err := anyxml.XmlIndent(resultMap.Result, prefix, indent, recordTag)
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+// Exec a raw sql and return records as []map[string]interface{}
+func (session *Session) FindAll() ResultMap {
+	sql := session.Statement.RawSQL
+	params := session.Statement.RawParams
+	result, err := session.QueryAll(sql, params...)
+	r := ResultMap{Result: result, Err: err}
+	return r
+}
+
+// Exec a raw sql and return records as []map[string]interface{}
+func (session *Session) FindAllWithDateFormat(dateFormat string) ResultMap {
+	sql := session.Statement.RawSQL
+	params := session.Statement.RawParams
+	result, err := session.QueryAllWithDateFormat(dateFormat, sql, params...)
+	r := ResultMap{Result: result, Err: err}
+	return r
+}
+
+// Exec a raw sql and return records as []map[string]interface{}
+func (session *Session) FindAllByParamMap() ResultMap {
+	sql := session.Statement.RawSQL
+	params := session.Statement.RawParams
+	result, err := session.QueryAllByMap(sql, params[0])
+	r := ResultMap{Result: result, Err: err}
+	return r
+}
+
+func (session *Session) FindAllByParamMapWithDateFormat(dateFormat string) ResultMap {
+	sql := session.Statement.RawSQL
+	params := session.Statement.RawParams
+	results, err := session.QueryAllByMapWithDateFormat(dateFormat, sql, params[0])
+	r := ResultMap{Result: results, Err: err}
+	return r
+}
+
+// =============================
+// for Object
+// =============================
+func (session *Session) QueryAll(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]interface{}, err error) {
+	session.queryPreprocess(&sqlStr, paramStr...)
+
+	if session.IsAutoCommit {
+		return query3(session.DB(), sqlStr, paramStr...)
+	}
+	return txQuery3(session.Tx, sqlStr, paramStr...)
+}
+
+func (session *Session) QueryAllByMap(sqlStr string, paramMap interface{}) (resultsSlice []map[string]interface{}, err error) {
+	sqlStr1, param, _ := core.MapToSlice(sqlStr, paramMap)
+
+	session.queryPreprocess(&sqlStr1, param...)
+
+	if session.IsAutoCommit {
+		return query3(session.DB(), sqlStr1, param...)
+	}
+	return txQuery3(session.Tx, sqlStr1, param...)
+}
+
+func (session *Session) QueryAllByMapWithDateFormat(dateFormat string, sqlStr string, paramMap interface{}) (resultsSlice []map[string]interface{}, err error) {
+	sqlStr1, param, _ := core.MapToSlice(sqlStr, paramMap)
+	session.queryPreprocess(&sqlStr1, param...)
+
+	if session.IsAutoCommit {
+		return query3WithDateFormat(session.DB(), dateFormat, sqlStr1, param...)
+	}
+	return txQuery3WithDateFormat(session.Tx, dateFormat, sqlStr1, param...)
+}
+
+func (session *Session) QueryAllWithDateFormat(dateFormat string, sqlStr string, paramStr ...interface{}) (resultsSlice []map[string]interface{}, err error) {
+	session.queryPreprocess(&sqlStr, paramStr...)
+
+	if session.IsAutoCommit {
+		return query3WithDateFormat(session.DB(), dateFormat, sqlStr, paramStr...)
+	}
+	return txQuery3WithDateFormat(session.Tx, dateFormat, sqlStr, paramStr...)
+}
+
+func (session *Session) QueryAllToJsonString(sql string, paramStr ...interface{}) (string, error) {
+	results, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	return JSONString(results, true)
+}
+
+func (session *Session) QueryAllToXmlString(sql string, paramStr ...interface{}) (string, error) {
+	resultMap, err := session.QueryAll(sql, paramStr...)
+
+	if err != nil {
+		return "", err
+	}
+	results, err := anyxml.Xml(resultMap)
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func (session *Session) QueryAllToXmlIndentString(sql string, prefix string, indent string, paramStr ...interface{}) (string, error) {
+	resultSlice, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	results, err := anyxml.XmlIndent(resultSlice, prefix, indent, "result")
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func (session *Session) QueryAllToXmlStringWithDateFormat(dateFormat string, sql string, paramStr ...interface{}) (string, error) {
+	resultSlice, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	results, err := anyxml.XmlWithDateFormat(dateFormat, resultSlice)
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func (session *Session) QueryAllToXmlIndentStringWithDateFormat(dateFormat string, sql string, prefix string, indent string, paramStr ...interface{}) (string, error) {
+	resultSlice, err := session.QueryAll(sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	results, err := anyxml.XmlIndentWithDateFormat(dateFormat, resultSlice, prefix, indent, "results")
+
+	if err != nil {
+		return "", err
+	}
+	return string(results), nil
+}
+
+func (session *Session) QueryAllByMapToJsonString(sql string, paramMap interface{}) (string, error) {
+	results, err := session.QueryAllByMap(sql, paramMap)
+	if err != nil {
+		return "", err
+	}
+	return JSONString(results, true)
+}
+
+func (session *Session) QueryAllByMapToJsonStringWithDateFormat(dateFormat string, sql string, paramMap interface{}) (string, error) {
+	results, err := session.QueryAllByMapWithDateFormat(dateFormat, sql, paramMap)
+	if err != nil {
+		return "", err
+	}
+	return JSONString(results, true)
+}
+
+func (session *Session) QueryAllToJsonStringWithDateFormat(dateFormat string, sql string, paramStr ...interface{}) (string, error) {
+	results, err := session.QueryAllWithDateFormat(dateFormat, sql, paramStr...)
+	if err != nil {
+		return "", err
+	}
+	return JSONString(results, true)
+}
+
+func (session *Session) row2BeanWithDateFormat(dateFormat string, rows *core.Rows, fields []string, fieldsCount int, bean interface{}) error {
+	dataStruct := rValue(bean)
+	if dataStruct.Kind() != reflect.Struct {
+		return errors.New("Expected a pointer to a struct")
+	}
+
+	table := session.Engine.autoMapType(dataStruct)
+	return session._row2BeanWithDateFormat(dateFormat, rows, fields, fieldsCount, bean, &dataStruct, table)
+}
+
+func (session *Session) _row2BeanWithDateFormat(dateFormat string, rows *core.Rows, fields []string, fieldsCount int, bean interface{}, dataStruct *reflect.Value, table *core.Table) error {
+	scanResults := make([]interface{}, fieldsCount)
+	for i := 0; i < len(fields); i++ {
+		var cell interface{}
+		scanResults[i] = &cell
+	}
+	if err := rows.Scan(scanResults...); err != nil {
+		return err
+	}
+
+	if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet {
+		for ii, key := range fields {
+			b.BeforeSet(key, Cell(scanResults[ii].(*interface{})))
+		}
+	}
+
+	var tempMap = make(map[string]int)
+	for ii, key := range fields {
+		var idx int
+		var ok bool
+		if idx, ok = tempMap[strings.ToLower(key)]; !ok {
+			idx = 0
+		} else {
+			idx = idx + 1
+		}
+		tempMap[strings.ToLower(key)] = idx
+
+		if fieldValue := session.getField(dataStruct, key, table, idx); fieldValue != nil {
+			rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
+
+			//if row is null then ignore
+			if rawValue.Interface() == nil {
+				continue
+			}
+
+			if fieldValue.CanAddr() {
+				if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+					if data, err := value2Bytes(&rawValue); err == nil {
+						structConvert.FromDB(data)
+					} else {
+						session.Engine.LogError(err)
+					}
+					continue
+				}
+			}
+
+			if _, ok := fieldValue.Interface().(core.Conversion); ok {
+				if data, err := value2Bytes(&rawValue); err == nil {
+					if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
+						fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
+					}
+					fieldValue.Interface().(core.Conversion).FromDB(data)
+				} else {
+					session.Engine.LogError(err)
+				}
+				continue
+			}
+
+			rawValueType := reflect.TypeOf(rawValue.Interface())
+			vv := reflect.ValueOf(rawValue.Interface())
+
+			fieldType := fieldValue.Type()
+			hasAssigned := false
+
+			switch fieldType.Kind() {
+
+			case reflect.Complex64, reflect.Complex128:
+				if rawValueType.Kind() == reflect.String {
+					hasAssigned = true
+					x := reflect.New(fieldType)
+					err := json.Unmarshal([]byte(vv.String()), x.Interface())
+					if err != nil {
+						session.Engine.LogError(err)
+						return err
+					}
+					fieldValue.Set(x.Elem())
+				}
+			case reflect.Slice, reflect.Array:
+				switch rawValueType.Kind() {
+				case reflect.Slice, reflect.Array:
+					switch rawValueType.Elem().Kind() {
+					case reflect.Uint8:
+						if fieldType.Elem().Kind() == reflect.Uint8 {
+							hasAssigned = true
+							fieldValue.Set(vv)
+						}
+					}
+				}
+			case reflect.String:
+				if rawValueType.Kind() == reflect.String {
+					hasAssigned = true
+					fieldValue.SetString(vv.String())
+				}
+			case reflect.Bool:
+				if rawValueType.Kind() == reflect.Bool {
+					hasAssigned = true
+					fieldValue.SetBool(vv.Bool())
+				}
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				switch rawValueType.Kind() {
+				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+					hasAssigned = true
+					fieldValue.SetInt(vv.Int())
+				}
+			case reflect.Float32, reflect.Float64:
+				switch rawValueType.Kind() {
+				case reflect.Float32, reflect.Float64:
+					hasAssigned = true
+					fieldValue.SetFloat(vv.Float())
+				}
+			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+				switch rawValueType.Kind() {
+				case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+					hasAssigned = true
+					fieldValue.SetUint(vv.Uint())
+				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+					hasAssigned = true
+					fieldValue.SetUint(uint64(vv.Int()))
+				}
+			case reflect.Struct:
+				if fieldType.ConvertibleTo(core.TimeType) {
+					if rawValueType == core.TimeType {
+						hasAssigned = true
+
+						t := vv.Convert(core.TimeType).Interface().(time.Time)
+						z, _ := t.Zone()
+						if len(z) == 0 || t.Year() == 0 { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
+							session.Engine.LogDebug("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
+							t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
+								t.Minute(), t.Second(), t.Nanosecond(), time.Local)
+						}
+						// !nashtsai! convert to engine location
+						t = t.In(session.Engine.TZLocation)
+						// dateFormat to string
+						loc, _ := time.LoadLocation("Local") //重要:获取时区  rawValue.Interface().(time.Time).Format(dateFormat)
+						t, _ = time.ParseInLocation(dateFormat, t.Format(dateFormat), loc)
+						//						fieldValue.Set(reflect.ValueOf(t).Convert(core.StringType))
+						fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
+
+						// t = fieldValue.Interface().(time.Time)
+						// z, _ = t.Zone()
+						// session.Engine.LogDebug("fieldValue key[%v]: %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
+					} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
+						rawValueType == core.Int32Type {
+						hasAssigned = true
+						t := time.Unix(vv.Int(), 0).In(session.Engine.TZLocation)
+						vv = reflect.ValueOf(t)
+						fieldValue.Set(vv)
+					}
+				} else if session.Statement.UseCascade {
+					table := session.Engine.autoMapType(*fieldValue)
+					if table != nil {
+						if len(table.PrimaryKeys) > 1 {
+							panic("unsupported composited primary key cascade")
+						}
+						var pk = make(core.PK, len(table.PrimaryKeys))
+						switch rawValueType.Kind() {
+						case reflect.Int64:
+							pk[0] = vv.Int()
+						case reflect.Int:
+							pk[0] = int(vv.Int())
+						case reflect.Int32:
+							pk[0] = int32(vv.Int())
+						case reflect.Int16:
+							pk[0] = int16(vv.Int())
+						case reflect.Int8:
+							pk[0] = int8(vv.Int())
+						case reflect.Uint64:
+							pk[0] = vv.Uint()
+						case reflect.Uint:
+							pk[0] = uint(vv.Uint())
+						case reflect.Uint32:
+							pk[0] = uint32(vv.Uint())
+						case reflect.Uint16:
+							pk[0] = uint16(vv.Uint())
+						case reflect.Uint8:
+							pk[0] = uint8(vv.Uint())
+						case reflect.String:
+							pk[0] = vv.String()
+						default:
+							panic("unsupported primary key type cascade")
+						}
+
+						if !isPKZero(pk) {
+							// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
+							// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
+							// property to be fetched lazily
+							structInter := reflect.New(fieldValue.Type())
+							newsession := session.Engine.NewSession()
+							defer newsession.Close()
+							has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
+							if err != nil {
+								return err
+							}
+							if has {
+								v := structInter.Elem().Interface()
+								fieldValue.Set(reflect.ValueOf(v))
+							} else {
+								return errors.New("cascade obj is not exist!")
+							}
+						}
+					} else {
+						session.Engine.LogError("unsupported struct type in Scan: ", fieldValue.Type().String())
+					}
+				}
+			case reflect.Ptr:
+				// !nashtsai! TODO merge duplicated codes above
+				//typeStr := fieldType.String()
+				switch fieldType {
+				// following types case matching ptr's native type, therefore assign ptr directly
+				case core.PtrStringType:
+					if rawValueType.Kind() == reflect.String {
+						x := vv.String()
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrBoolType:
+					if rawValueType.Kind() == reflect.Bool {
+						x := vv.Bool()
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrTimeType:
+					if rawValueType == core.PtrTimeType {
+						hasAssigned = true
+						var x time.Time = rawValue.Interface().(time.Time)
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrFloat64Type:
+					if rawValueType.Kind() == reflect.Float64 {
+						x := vv.Float()
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrUint64Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint64 = uint64(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrInt64Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						x := vv.Int()
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrFloat32Type:
+					if rawValueType.Kind() == reflect.Float64 {
+						var x float32 = float32(vv.Float())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrIntType:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x int = int(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrInt32Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x int32 = int32(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrInt8Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x int8 = int8(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrInt16Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x int16 = int16(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrUintType:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint = uint(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.PtrUint32Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint32 = uint32(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.Uint8Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint8 = uint8(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.Uint16Type:
+					if rawValueType.Kind() == reflect.Int64 {
+						var x uint16 = uint16(vv.Int())
+						hasAssigned = true
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+				case core.Complex64Type:
+					var x complex64
+					err := json.Unmarshal([]byte(vv.String()), &x)
+					if err != nil {
+						session.Engine.LogError(err)
+					} else {
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+					hasAssigned = true
+				case core.Complex128Type:
+					var x complex128
+					err := json.Unmarshal([]byte(vv.String()), &x)
+					if err != nil {
+						session.Engine.LogError(err)
+					} else {
+						fieldValue.Set(reflect.ValueOf(&x))
+					}
+					hasAssigned = true
+				} // switch fieldType
+				// default:
+				// 	session.Engine.LogError("unsupported type in Scan: ", reflect.TypeOf(v).String())
+			} // switch fieldType.Kind()
+
+			// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
+			if !hasAssigned {
+				data, err := value2Bytes(&rawValue)
+				if err == nil {
+					session.bytes2Value(table.GetColumn(key), fieldValue, data)
+				} else {
+					session.Engine.LogError(err.Error())
+				}
+			}
+		}
+	}
+	return nil
+
+}
+
+func (session *Session) queryPreprocessByMap(sqlStr *string, paramMap interface{}) {
+	re := regexp.MustCompile(`[?](\w+)`)
+	query := *sqlStr
+	names := make(map[string]int)
+	var i int
+	query = re.ReplaceAllStringFunc(query, func(src string) string {
+		names[src[1:]] = i
+		i += 1
+		return "?"
+	})
+
+	for _, filter := range session.Engine.dialect.Filters() {
+		query = filter.Do(query, session.Engine.dialect, session.Statement.RefTable)
+	}
+
+	*sqlStr = query
+	session.Engine.logSQL(*sqlStr, paramMap)
+}

+ 7 - 0
sql/oracle/select.example.stpl

@@ -0,0 +1,7 @@
+select id,title,createdatetime,content 
+from article where  
+{% if count>1%}
+id=?id
+{% else%}
+userid=?userid
+{% endif %}

+ 429 - 0
sqlite3_dialect.go

@@ -0,0 +1,429 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"database/sql"
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	RegisterDialect("sqlite3", &sqlite3{})
+// }
+
+var (
+	sqlite3ReservedWords = map[string]bool{
+		"ABORT":             true,
+		"ACTION":            true,
+		"ADD":               true,
+		"AFTER":             true,
+		"ALL":               true,
+		"ALTER":             true,
+		"ANALYZE":           true,
+		"AND":               true,
+		"AS":                true,
+		"ASC":               true,
+		"ATTACH":            true,
+		"AUTOINCREMENT":     true,
+		"BEFORE":            true,
+		"BEGIN":             true,
+		"BETWEEN":           true,
+		"BY":                true,
+		"CASCADE":           true,
+		"CASE":              true,
+		"CAST":              true,
+		"CHECK":             true,
+		"COLLATE":           true,
+		"COLUMN":            true,
+		"COMMIT":            true,
+		"CONFLICT":          true,
+		"CONSTRAINT":        true,
+		"CREATE":            true,
+		"CROSS":             true,
+		"CURRENT_DATE":      true,
+		"CURRENT_TIME":      true,
+		"CURRENT_TIMESTAMP": true,
+		"DATABASE":          true,
+		"DEFAULT":           true,
+		"DEFERRABLE":        true,
+		"DEFERRED":          true,
+		"DELETE":            true,
+		"DESC":              true,
+		"DETACH":            true,
+		"DISTINCT":          true,
+		"DROP":              true,
+		"EACH":              true,
+		"ELSE":              true,
+		"END":               true,
+		"ESCAPE":            true,
+		"EXCEPT":            true,
+		"EXCLUSIVE":         true,
+		"EXISTS":            true,
+		"EXPLAIN":           true,
+		"FAIL":              true,
+		"FOR":               true,
+		"FOREIGN":           true,
+		"FROM":              true,
+		"FULL":              true,
+		"GLOB":              true,
+		"GROUP":             true,
+		"HAVING":            true,
+		"IF":                true,
+		"IGNORE":            true,
+		"IMMEDIATE":         true,
+		"IN":                true,
+		"INDEX":             true,
+		"INDEXED":           true,
+		"INITIALLY":         true,
+		"INNER":             true,
+		"INSERT":            true,
+		"INSTEAD":           true,
+		"INTERSECT":         true,
+		"INTO":              true,
+		"IS":                true,
+		"ISNULL":            true,
+		"JOIN":              true,
+		"KEY":               true,
+		"LEFT":              true,
+		"LIKE":              true,
+		"LIMIT":             true,
+		"MATCH":             true,
+		"NATURAL":           true,
+		"NO":                true,
+		"NOT":               true,
+		"NOTNULL":           true,
+		"NULL":              true,
+		"OF":                true,
+		"OFFSET":            true,
+		"ON":                true,
+		"OR":                true,
+		"ORDER":             true,
+		"OUTER":             true,
+		"PLAN":              true,
+		"PRAGMA":            true,
+		"PRIMARY":           true,
+		"QUERY":             true,
+		"RAISE":             true,
+		"RECURSIVE":         true,
+		"REFERENCES":        true,
+		"REGEXP":            true,
+		"REINDEX":           true,
+		"RELEASE":           true,
+		"RENAME":            true,
+		"REPLACE":           true,
+		"RESTRICT":          true,
+		"RIGHT":             true,
+		"ROLLBACK":          true,
+		"ROW":               true,
+		"SAVEPOINT":         true,
+		"SELECT":            true,
+		"SET":               true,
+		"TABLE":             true,
+		"TEMP":              true,
+		"TEMPORARY":         true,
+		"THEN":              true,
+		"TO":                true,
+		"TRANSACTI":         true,
+		"TRIGGER":           true,
+		"UNION":             true,
+		"UNIQUE":            true,
+		"UPDATE":            true,
+		"USING":             true,
+		"VACUUM":            true,
+		"VALUES":            true,
+		"VIEW":              true,
+		"VIRTUAL":           true,
+		"WHEN":              true,
+		"WHERE":             true,
+		"WITH":              true,
+		"WITHOUT":           true,
+	}
+)
+
+type sqlite3 struct {
+	core.Base
+}
+
+func (db *sqlite3) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
+	return db.Base.Init(d, db, uri, drivername, dataSourceName)
+}
+
+func (db *sqlite3) SqlType(c *core.Column) string {
+	switch t := c.SQLType.Name; t {
+	case core.Date, core.DateTime, core.TimeStamp, core.Time:
+		return core.DateTime
+	case core.TimeStampz:
+		return core.Text
+	case core.Char, core.Varchar, core.NVarchar, core.TinyText,
+		core.Text, core.MediumText, core.LongText, core.Json:
+		return core.Text
+	case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool:
+		return core.Integer
+	case core.Float, core.Double, core.Real:
+		return core.Real
+	case core.Decimal, core.Numeric:
+		return core.Numeric
+	case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary:
+		return core.Blob
+	case core.Serial, core.BigSerial:
+		c.IsPrimaryKey = true
+		c.IsAutoIncrement = true
+		c.Nullable = false
+		return core.Integer
+	default:
+		return t
+	}
+}
+
+func (db *sqlite3) FormatBytes(bs []byte) string {
+	return fmt.Sprintf("X'%x'", bs)
+}
+
+func (db *sqlite3) SupportInsertMany() bool {
+	return true
+}
+
+func (db *sqlite3) IsReserved(name string) bool {
+	_, ok := sqlite3ReservedWords[name]
+	return ok
+}
+
+func (db *sqlite3) Quote(name string) string {
+	return "`" + name + "`"
+}
+
+func (db *sqlite3) QuoteStr() string {
+	return "`"
+}
+
+func (db *sqlite3) AutoIncrStr() string {
+	return "AUTOINCREMENT"
+}
+
+func (db *sqlite3) SupportEngine() bool {
+	return false
+}
+
+func (db *sqlite3) SupportCharset() bool {
+	return false
+}
+
+func (db *sqlite3) IndexOnTable() bool {
+	return false
+}
+
+func (db *sqlite3) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
+	args := []interface{}{idxName}
+	return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args
+}
+
+func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
+}
+
+func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
+	quote := db.Quote
+	//var unique string
+	var idxName string = index.Name
+	if !strings.HasPrefix(idxName, "UQE_") &&
+		!strings.HasPrefix(idxName, "IDX_") {
+		if index.Type == core.UniqueType {
+			idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
+		} else {
+			idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
+		}
+	}
+	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
+}
+
+/*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
+	args := []interface{}{tableName}
+	sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
+	return sql, args
+}*/
+
+func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
+	args := []interface{}{tableName}
+	query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
+	rows, err := db.DB().Query(query, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", query, args)
+	}
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+
+	if rows.Next() {
+		return true, nil
+	}
+	return false, nil
+}
+
+func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
+	args := []interface{}{tableName}
+	s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, nil, err
+	}
+	defer rows.Close()
+
+	var name string
+	for rows.Next() {
+		err = rows.Scan(&name)
+		if err != nil {
+			return nil, nil, err
+		}
+		break
+	}
+
+	if name == "" {
+		return nil, nil, errors.New("no table named " + tableName)
+	}
+
+	nStart := strings.Index(name, "(")
+	nEnd := strings.LastIndex(name, ")")
+	colCreates := strings.Split(name[nStart+1:nEnd], ",")
+	cols := make(map[string]*core.Column)
+	colSeq := make([]string, 0)
+	for _, colStr := range colCreates {
+		fields := strings.Fields(strings.TrimSpace(colStr))
+		col := new(core.Column)
+		col.Indexes = make(map[string]bool)
+		col.Nullable = true
+		col.DefaultIsEmpty = true
+		for idx, field := range fields {
+			if idx == 0 {
+				col.Name = strings.Trim(field, "`[] ")
+				continue
+			} else if idx == 1 {
+				col.SQLType = core.SQLType{field, 0, 0}
+			}
+			switch field {
+			case "PRIMARY":
+				col.IsPrimaryKey = true
+			case "AUTOINCREMENT":
+				col.IsAutoIncrement = true
+			case "NULL":
+				if fields[idx-1] == "NOT" {
+					col.Nullable = false
+				} else {
+					col.Nullable = true
+				}
+			case "DEFAULT":
+				col.Default = fields[idx+1]
+				col.DefaultIsEmpty = false
+			}
+		}
+		if !col.SQLType.IsNumeric() && !col.DefaultIsEmpty {
+			col.Default = "'" + col.Default + "'"
+		}
+		cols[col.Name] = col
+		colSeq = append(colSeq, col.Name)
+	}
+	return colSeq, cols, nil
+}
+
+func (db *sqlite3) GetTables() ([]*core.Table, error) {
+	args := []interface{}{}
+	s := "SELECT name FROM sqlite_master WHERE type='table'"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	tables := make([]*core.Table, 0)
+	for rows.Next() {
+		table := core.NewEmptyTable()
+		err = rows.Scan(&table.Name)
+		if err != nil {
+			return nil, err
+		}
+		if table.Name == "sqlite_sequence" {
+			continue
+		}
+		tables = append(tables, table)
+	}
+	return tables, nil
+}
+
+func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
+	args := []interface{}{tableName}
+	s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
+
+	rows, err := db.DB().Query(s, args...)
+	if db.Logger != nil {
+		db.Logger.Info("[sql]", s, args)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	indexes := make(map[string]*core.Index, 0)
+	for rows.Next() {
+		var tmpSql sql.NullString
+		err = rows.Scan(&tmpSql)
+		if err != nil {
+			return nil, err
+		}
+
+		if !tmpSql.Valid {
+			continue
+		}
+		sql := tmpSql.String
+
+		index := new(core.Index)
+		nNStart := strings.Index(sql, "INDEX")
+		nNEnd := strings.Index(sql, "ON")
+		if nNStart == -1 || nNEnd == -1 {
+			continue
+		}
+
+		indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
+		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
+			index.Name = indexName[5+len(tableName) : len(indexName)]
+		} else {
+			index.Name = indexName
+		}
+
+		if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
+			index.Type = core.UniqueType
+		} else {
+			index.Type = core.IndexType
+		}
+
+		nStart := strings.Index(sql, "(")
+		nEnd := strings.Index(sql, ")")
+		colIndexes := strings.Split(sql[nStart+1:nEnd], ",")
+
+		index.Cols = make([]string, 0)
+		for _, col := range colIndexes {
+			index.Cols = append(index.Cols, strings.Trim(col, "` []"))
+		}
+		indexes[index.Name] = index
+	}
+
+	return indexes, nil
+}
+
+func (db *sqlite3) Filters() []core.Filter {
+	return []core.Filter{&core.IdFilter{}}
+}

+ 20 - 0
sqlite3_driver.go

@@ -0,0 +1,20 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"github.com/xormplus/core"
+)
+
+// func init() {
+// 	core.RegisterDriver("sqlite3", &sqlite3Driver{})
+// }
+
+type sqlite3Driver struct {
+}
+
+func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
+	return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
+}

+ 1336 - 0
statement.go

@@ -0,0 +1,1336 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+type inParam struct {
+	colName string
+	args    []interface{}
+}
+
+type incrParam struct {
+	colName string
+	arg     interface{}
+}
+
+type decrParam struct {
+	colName string
+	arg     interface{}
+}
+
+type exprParam struct {
+	colName string
+	expr    string
+}
+
+// statement save all the sql info for executing SQL
+type Statement struct {
+	RefTable      *core.Table
+	Engine        *Engine
+	Start         int
+	LimitN        int
+	WhereStr      string
+	IdParam       *core.PK
+	Params        []interface{}
+	OrderStr      string
+	JoinStr       string
+	GroupByStr    string
+	HavingStr     string
+	ColumnStr     string
+	columnMap     map[string]bool
+	useAllCols    bool
+	OmitStr       string
+	ConditionStr  string
+	AltTableName  string
+	RawSQL        string
+	RawParams     []interface{}
+	UseCascade    bool
+	UseAutoJoin   bool
+	StoreEngine   string
+	Charset       string
+	BeanArgs      []interface{}
+	UseCache      bool
+	UseAutoTime   bool
+	IsDistinct    bool
+	TableAlias    string
+	allUseBool    bool
+	checkVersion  bool
+	unscoped      bool
+	mustColumnMap map[string]bool
+	inColumns     map[string]*inParam
+	incrColumns   map[string]incrParam
+	decrColumns   map[string]decrParam
+	exprColumns   map[string]exprParam
+}
+
+// init
+func (statement *Statement) Init() {
+	statement.RefTable = nil
+	statement.Start = 0
+	statement.LimitN = 0
+	statement.WhereStr = ""
+	statement.Params = make([]interface{}, 0)
+	statement.OrderStr = ""
+	statement.UseCascade = true
+	statement.JoinStr = ""
+	statement.GroupByStr = ""
+	statement.HavingStr = ""
+	statement.ColumnStr = ""
+	statement.OmitStr = ""
+	statement.columnMap = make(map[string]bool)
+	statement.ConditionStr = ""
+	statement.AltTableName = ""
+	statement.IdParam = nil
+	statement.RawSQL = ""
+	statement.RawParams = make([]interface{}, 0)
+	statement.BeanArgs = make([]interface{}, 0)
+	statement.UseCache = true
+	statement.UseAutoTime = true
+	statement.IsDistinct = false
+	statement.TableAlias = ""
+	statement.allUseBool = false
+	statement.useAllCols = false
+	statement.mustColumnMap = make(map[string]bool)
+	statement.checkVersion = true
+	statement.unscoped = false
+	statement.inColumns = make(map[string]*inParam)
+	statement.incrColumns = make(map[string]incrParam)
+	statement.decrColumns = make(map[string]decrParam)
+	statement.exprColumns = make(map[string]exprParam)
+}
+
+// add the raw sql statement
+func (statement *Statement) Sql(querystring string, args ...interface{}) *Statement {
+	statement.RawSQL = querystring
+	statement.RawParams = args
+	return statement
+}
+
+// set the table alias
+func (statement *Statement) Alias(alias string) *Statement {
+	statement.TableAlias = alias
+	return statement
+}
+
+// add Where statment
+func (statement *Statement) Where(querystring string, args ...interface{}) *Statement {
+	if !strings.Contains(querystring, statement.Engine.dialect.EqStr()) {
+		querystring = strings.Replace(querystring, "=", statement.Engine.dialect.EqStr(), -1)
+	}
+	statement.WhereStr = querystring
+	statement.Params = args
+	return statement
+}
+
+// add Where & and statment
+func (statement *Statement) And(querystring string, args ...interface{}) *Statement {
+	if statement.WhereStr != "" {
+		statement.WhereStr = fmt.Sprintf("(%v) %s (%v)", statement.WhereStr,
+			statement.Engine.dialect.AndStr(), querystring)
+	} else {
+		statement.WhereStr = querystring
+	}
+	statement.Params = append(statement.Params, args...)
+	return statement
+}
+
+// add Where & Or statment
+func (statement *Statement) Or(querystring string, args ...interface{}) *Statement {
+	if statement.WhereStr != "" {
+		statement.WhereStr = fmt.Sprintf("(%v) %s (%v)", statement.WhereStr,
+			statement.Engine.dialect.OrStr(), querystring)
+	} else {
+		statement.WhereStr = querystring
+	}
+	statement.Params = append(statement.Params, args...)
+	return statement
+}
+
+// tempororily set table name
+func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
+	v := rValue(tableNameOrBean)
+	t := v.Type()
+	if t.Kind() == reflect.String {
+		statement.AltTableName = tableNameOrBean.(string)
+	} else if t.Kind() == reflect.Struct {
+		statement.RefTable = statement.Engine.autoMapType(v)
+	}
+	return statement
+}
+
+/*func (statement *Statement) genFields(bean interface{}) map[string]interface{} {
+    results := make(map[string]interface{})
+    table := statement.Engine.TableInfo(bean)
+    for _, col := range table.Columns {
+        fieldValue := col.ValueOf(bean)
+        fieldType := reflect.TypeOf(fieldValue.Interface())
+        var val interface{}
+        switch fieldType.Kind() {
+        case reflect.Bool:
+            if allUseBool {
+                val = fieldValue.Interface()
+            } else if _, ok := boolColumnMap[col.Name]; ok {
+                val = fieldValue.Interface()
+            } else {
+                // if a bool in a struct, it will not be as a condition because it default is false,
+                // please use Where() instead
+                continue
+            }
+        case reflect.String:
+            if fieldValue.String() == "" {
+                continue
+            }
+            // for MyString, should convert to string or panic
+            if fieldType.String() != reflect.String.String() {
+                val = fieldValue.String()
+            } else {
+                val = fieldValue.Interface()
+            }
+        case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
+            if fieldValue.Int() == 0 {
+                continue
+            }
+            val = fieldValue.Interface()
+        case reflect.Float32, reflect.Float64:
+            if fieldValue.Float() == 0.0 {
+                continue
+            }
+            val = fieldValue.Interface()
+        case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
+            if fieldValue.Uint() == 0 {
+                continue
+            }
+            val = fieldValue.Interface()
+        case reflect.Struct:
+            if fieldType == reflect.TypeOf(time.Now()) {
+                t := fieldValue.Interface().(time.Time)
+                if t.IsZero() || !fieldValue.IsValid() {
+                    continue
+                }
+                var str string
+                if col.SQLType.Name == Time {
+                    s := t.UTC().Format("2006-01-02 15:04:05")
+                    val = s[11:19]
+                } else if col.SQLType.Name == Date {
+                    str = t.Format("2006-01-02")
+                    val = str
+                } else {
+                    val = t
+                }
+            } else {
+                engine.autoMapType(fieldValue.Type())
+                if table, ok := engine.Tables[fieldValue.Type()]; ok {
+                    pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumn().FieldName)
+                    if pkField.Int() != 0 {
+                        val = pkField.Interface()
+                    } else {
+                        continue
+                    }
+                } else {
+                    val = fieldValue.Interface()
+                }
+            }
+        case reflect.Array, reflect.Slice, reflect.Map:
+            if fieldValue == reflect.Zero(fieldType) {
+                continue
+            }
+            if fieldValue.IsNil() || !fieldValue.IsValid() {
+                continue
+            }
+
+            if col.SQLType.IsText() {
+                bytes, err := json.Marshal(fieldValue.Interface())
+                if err != nil {
+                    engine.LogError(err)
+                    continue
+                }
+                val = string(bytes)
+            } else if col.SQLType.IsBlob() {
+                var bytes []byte
+                var err error
+                if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
+                    fieldType.Elem().Kind() == reflect.Uint8 {
+                    if fieldValue.Len() > 0 {
+                        val = fieldValue.Bytes()
+                    } else {
+                        continue
+                    }
+                } else {
+                    bytes, err = json.Marshal(fieldValue.Interface())
+                    if err != nil {
+                        engine.LogError(err)
+                        continue
+                    }
+                    val = bytes
+                }
+            } else {
+                continue
+            }
+        default:
+            val = fieldValue.Interface()
+        }
+        results[col.Name] = val
+    }
+    return results
+}*/
+
+// Auto generating conditions according a struct
+func buildUpdates(engine *Engine, table *core.Table, bean interface{},
+	includeVersion bool, includeUpdated bool, includeNil bool,
+	includeAutoIncr bool, allUseBool bool, useAllCols bool,
+	mustColumnMap map[string]bool, columnMap map[string]bool, update bool) ([]string, []interface{}) {
+
+	colNames := make([]string, 0)
+	var args = make([]interface{}, 0)
+	for _, col := range table.Columns() {
+		if !includeVersion && col.IsVersion {
+			continue
+		}
+		if col.IsCreated {
+			continue
+		}
+		if !includeUpdated && col.IsUpdated {
+			continue
+		}
+		if !includeAutoIncr && col.IsAutoIncrement {
+			continue
+		}
+		if col.IsDeleted {
+			continue
+		}
+		if use, ok := columnMap[col.Name]; ok && !use {
+			continue
+		}
+
+		if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
+			continue
+		}
+
+		fieldValuePtr, err := col.ValueOf(bean)
+		if err != nil {
+			engine.LogError(err)
+			continue
+		}
+
+		fieldValue := *fieldValuePtr
+		fieldType := reflect.TypeOf(fieldValue.Interface())
+
+		requiredField := useAllCols
+		includeNil := useAllCols
+		if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok {
+			if b {
+				requiredField = true
+			} else {
+				continue
+			}
+		}
+
+		var val interface{}
+
+		if fieldValue.CanAddr() {
+			if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
+				data, err := structConvert.ToDB()
+				if err != nil {
+					engine.LogError(err)
+				} else {
+					val = data
+				}
+				goto APPEND
+			}
+		}
+
+		if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
+			data, err := structConvert.ToDB()
+			if err != nil {
+				engine.LogError(err)
+			} else {
+				val = data
+			}
+			goto APPEND
+		}
+
+		if fieldType.Kind() == reflect.Ptr {
+			if fieldValue.IsNil() {
+				if includeNil {
+					args = append(args, nil)
+					colNames = append(colNames, fmt.Sprintf("%v=?", engine.Quote(col.Name)))
+				}
+				continue
+			} else if !fieldValue.IsValid() {
+				continue
+			} else {
+				// dereference ptr type to instance type
+				fieldValue = fieldValue.Elem()
+				fieldType = reflect.TypeOf(fieldValue.Interface())
+				requiredField = true
+			}
+		}
+
+		switch fieldType.Kind() {
+		case reflect.Bool:
+			if allUseBool || requiredField {
+				val = fieldValue.Interface()
+			} else {
+				// if a bool in a struct, it will not be as a condition because it default is false,
+				// please use Where() instead
+				continue
+			}
+		case reflect.String:
+			if !requiredField && fieldValue.String() == "" {
+				continue
+			}
+			// for MyString, should convert to string or panic
+			if fieldType.String() != reflect.String.String() {
+				val = fieldValue.String()
+			} else {
+				val = fieldValue.Interface()
+			}
+		case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
+			if !requiredField && fieldValue.Int() == 0 {
+				continue
+			}
+			val = fieldValue.Interface()
+		case reflect.Float32, reflect.Float64:
+			if !requiredField && fieldValue.Float() == 0.0 {
+				continue
+			}
+			val = fieldValue.Interface()
+		case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
+			if !requiredField && fieldValue.Uint() == 0 {
+				continue
+			}
+			t := int64(fieldValue.Uint())
+			val = reflect.ValueOf(&t).Interface()
+		case reflect.Struct:
+			if fieldType == reflect.TypeOf(time.Now()) {
+				t := fieldValue.Interface().(time.Time)
+				if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
+					continue
+				}
+				val = engine.FormatTime(col.SQLType.Name, t)
+			} else {
+				engine.autoMapType(fieldValue)
+				if table, ok := engine.Tables[fieldValue.Type()]; ok {
+					if len(table.PrimaryKeys) == 1 {
+						pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
+						// fix non-int pk issues
+						//if pkField.Int() != 0 {
+						if pkField.IsValid() && !isZero(pkField.Interface()) {
+							val = pkField.Interface()
+						} else {
+							continue
+						}
+					} else {
+						//TODO: how to handler?
+						panic("not supported")
+					}
+				} else {
+					val = fieldValue.Interface()
+				}
+			}
+		case reflect.Array, reflect.Slice, reflect.Map:
+			if fieldValue == reflect.Zero(fieldType) {
+				continue
+			}
+			if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
+				continue
+			}
+
+			if col.SQLType.IsText() {
+				bytes, err := json.Marshal(fieldValue.Interface())
+				if err != nil {
+					engine.LogError(err)
+					continue
+				}
+				val = string(bytes)
+			} else if col.SQLType.IsBlob() {
+				var bytes []byte
+				var err error
+				if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
+					fieldType.Elem().Kind() == reflect.Uint8 {
+					if fieldValue.Len() > 0 {
+						val = fieldValue.Bytes()
+					} else {
+						continue
+					}
+				} else {
+					bytes, err = json.Marshal(fieldValue.Interface())
+					if err != nil {
+						engine.LogError(err)
+						continue
+					}
+					val = bytes
+				}
+			} else {
+				continue
+			}
+		default:
+			val = fieldValue.Interface()
+		}
+
+	APPEND:
+		//fmt.Println("==", col.Name, "==", fmt.Sprintf("%v", val))
+		args = append(args, val)
+		if col.IsPrimaryKey && engine.dialect.DBType() == "ql" {
+			continue
+		}
+		colNames = append(colNames, fmt.Sprintf("%v = ?", engine.Quote(col.Name)))
+	}
+
+	return colNames, args
+}
+
+// Auto generating conditions according a struct
+func buildConditions(engine *Engine, table *core.Table, bean interface{},
+	includeVersion bool, includeUpdated bool, includeNil bool,
+	includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
+	mustColumnMap map[string]bool) ([]string, []interface{}) {
+
+	colNames := make([]string, 0)
+	var args = make([]interface{}, 0)
+	for _, col := range table.Columns() {
+		if !includeVersion && col.IsVersion {
+			continue
+		}
+		if !includeUpdated && col.IsUpdated {
+			continue
+		}
+		if !includeAutoIncr && col.IsAutoIncrement {
+			continue
+		}
+
+		if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text {
+			continue
+		}
+		fieldValuePtr, err := col.ValueOf(bean)
+		if err != nil {
+			engine.LogError(err)
+			continue
+		}
+
+		if col.IsDeleted && !unscoped { // tag "deleted" is enabled
+			colNames = append(colNames, fmt.Sprintf("(%v IS NULL or %v = '0001-01-01 00:00:00')", engine.Quote(col.Name), engine.Quote(col.Name)))
+		}
+
+		fieldValue := *fieldValuePtr
+		if fieldValue.Interface() == nil {
+			continue
+		}
+
+		fieldType := reflect.TypeOf(fieldValue.Interface())
+		requiredField := useAllCols
+		if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok {
+			if b {
+				requiredField = true
+			} else {
+				continue
+			}
+		}
+
+		if fieldType.Kind() == reflect.Ptr {
+			if fieldValue.IsNil() {
+				if includeNil {
+					args = append(args, nil)
+					colNames = append(colNames, fmt.Sprintf("%v %s ?", engine.Quote(col.Name), engine.dialect.EqStr()))
+				}
+				continue
+			} else if !fieldValue.IsValid() {
+				continue
+			} else {
+				// dereference ptr type to instance type
+				fieldValue = fieldValue.Elem()
+				fieldType = reflect.TypeOf(fieldValue.Interface())
+				requiredField = true
+			}
+		}
+
+		var val interface{}
+		switch fieldType.Kind() {
+		case reflect.Bool:
+			if allUseBool || requiredField {
+				val = fieldValue.Interface()
+			} else {
+				// if a bool in a struct, it will not be as a condition because it default is false,
+				// please use Where() instead
+				continue
+			}
+		case reflect.String:
+			if !requiredField && fieldValue.String() == "" {
+				continue
+			}
+			// for MyString, should convert to string or panic
+			if fieldType.String() != reflect.String.String() {
+				val = fieldValue.String()
+			} else {
+				val = fieldValue.Interface()
+			}
+		case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
+			if !requiredField && fieldValue.Int() == 0 {
+				continue
+			}
+			val = fieldValue.Interface()
+		case reflect.Float32, reflect.Float64:
+			if !requiredField && fieldValue.Float() == 0.0 {
+				continue
+			}
+			val = fieldValue.Interface()
+		case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
+			if !requiredField && fieldValue.Uint() == 0 {
+				continue
+			}
+			t := int64(fieldValue.Uint())
+			val = reflect.ValueOf(&t).Interface()
+		case reflect.Struct:
+			if fieldType.ConvertibleTo(core.TimeType) {
+				t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
+				if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
+					continue
+				}
+				val = engine.FormatTime(col.SQLType.Name, t)
+			} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
+				continue
+			} else {
+				engine.autoMapType(fieldValue)
+				if table, ok := engine.Tables[fieldValue.Type()]; ok {
+					if len(table.PrimaryKeys) == 1 {
+						pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
+						// fix non-int pk issues
+						//if pkField.Int() != 0 {
+						if pkField.IsValid() && !isZero(pkField.Interface()) {
+							val = pkField.Interface()
+						} else {
+							continue
+						}
+					} else {
+						//TODO: how to handler?
+						panic(fmt.Sprintln("not supported", fieldValue.Interface(), "as", table.PrimaryKeys))
+					}
+				} else {
+					val = fieldValue.Interface()
+				}
+			}
+		case reflect.Array, reflect.Slice, reflect.Map:
+			if fieldValue == reflect.Zero(fieldType) {
+				continue
+			}
+			if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
+				continue
+			}
+
+			if col.SQLType.IsText() {
+				bytes, err := json.Marshal(fieldValue.Interface())
+				if err != nil {
+					engine.LogError(err)
+					continue
+				}
+				val = string(bytes)
+			} else if col.SQLType.IsBlob() {
+				var bytes []byte
+				var err error
+				if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
+					fieldType.Elem().Kind() == reflect.Uint8 {
+					if fieldValue.Len() > 0 {
+						val = fieldValue.Bytes()
+					} else {
+						continue
+					}
+				} else {
+					bytes, err = json.Marshal(fieldValue.Interface())
+					if err != nil {
+						engine.LogError(err)
+						continue
+					}
+					val = bytes
+				}
+			} else {
+				continue
+			}
+		default:
+			val = fieldValue.Interface()
+		}
+
+		args = append(args, val)
+		var condi string
+		if col.IsPrimaryKey && engine.dialect.DBType() == "ql" {
+			condi = "id() == ?"
+		} else {
+			condi = fmt.Sprintf("%v %s ?", engine.Quote(col.Name), engine.dialect.EqStr())
+		}
+		colNames = append(colNames, condi)
+	}
+
+	return colNames, args
+}
+
+// return current tableName
+func (statement *Statement) TableName() string {
+	if statement.AltTableName != "" {
+		return statement.AltTableName
+	}
+
+	if statement.RefTable != nil {
+		return statement.RefTable.Name
+	}
+	return ""
+}
+
+var (
+	ptrPkType = reflect.TypeOf(&core.PK{})
+	pkType    = reflect.TypeOf(core.PK{})
+)
+
+// Generate "where id = ? " statment or for composite key "where key1 = ? and key2 = ?"
+func (statement *Statement) Id(id interface{}) *Statement {
+	idValue := reflect.ValueOf(id)
+	idType := reflect.TypeOf(idValue.Interface())
+
+	switch idType {
+	case ptrPkType:
+		if pkPtr, ok := (id).(*core.PK); ok {
+			statement.IdParam = pkPtr
+		}
+	case pkType:
+		if pk, ok := (id).(core.PK); ok {
+			statement.IdParam = &pk
+		}
+	default:
+		// TODO: treat as int primitve for now, need to handle type check?
+		statement.IdParam = &core.PK{id}
+	}
+
+	return statement
+}
+
+// Generate  "Update ... Set column = column + arg" statment
+func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
+	k := strings.ToLower(column)
+	if len(arg) > 0 {
+		statement.incrColumns[k] = incrParam{column, arg[0]}
+	} else {
+		statement.incrColumns[k] = incrParam{column, 1}
+	}
+	return statement
+}
+
+// Generate  "Update ... Set column = column - arg" statment
+func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
+	k := strings.ToLower(column)
+	if len(arg) > 0 {
+		statement.decrColumns[k] = decrParam{column, arg[0]}
+	} else {
+		statement.decrColumns[k] = decrParam{column, 1}
+	}
+	return statement
+}
+
+// Generate  "Update ... Set column = {expression}" statment
+func (statement *Statement) SetExpr(column string, expression string) *Statement {
+	k := strings.ToLower(column)
+	statement.exprColumns[k] = exprParam{column, expression}
+	return statement
+}
+
+// Generate  "Update ... Set column = column + arg" statment
+func (statement *Statement) getInc() map[string]incrParam {
+	return statement.incrColumns
+}
+
+// Generate  "Update ... Set column = column - arg" statment
+func (statement *Statement) getDec() map[string]decrParam {
+	return statement.decrColumns
+}
+
+// Generate  "Update ... Set column = {expression}" statment
+func (statement *Statement) getExpr() map[string]exprParam {
+	return statement.exprColumns
+}
+
+// Generate "Where column IN (?) " statment
+func (statement *Statement) In(column string, args ...interface{}) *Statement {
+	k := strings.ToLower(column)
+	var newargs []interface{}
+	if len(args) == 1 &&
+		reflect.TypeOf(args[0]).Kind() == reflect.Slice {
+		newargs = make([]interface{}, 0)
+		v := reflect.ValueOf(args[0])
+		for i := 0; i < v.Len(); i++ {
+			newargs = append(newargs, v.Index(i).Interface())
+		}
+	} else {
+		newargs = args
+	}
+
+	if _, ok := statement.inColumns[k]; ok {
+		statement.inColumns[k].args = append(statement.inColumns[k].args, newargs...)
+	} else {
+		statement.inColumns[k] = &inParam{column, newargs}
+	}
+	return statement
+}
+
+func (statement *Statement) genInSql() (string, []interface{}) {
+	if len(statement.inColumns) == 0 {
+		return "", []interface{}{}
+	}
+
+	inStrs := make([]string, 0, len(statement.inColumns))
+	args := make([]interface{}, 0)
+	for _, params := range statement.inColumns {
+		inStrs = append(inStrs, fmt.Sprintf("(%v IN (%v))",
+			statement.Engine.autoQuote(params.colName),
+			strings.Join(makeArray("?", len(params.args)), ",")))
+		args = append(args, params.args...)
+	}
+
+	if len(statement.inColumns) == 1 {
+		return inStrs[0], args
+	}
+	return fmt.Sprintf("(%v)", strings.Join(inStrs, " "+statement.Engine.dialect.AndStr()+" ")), args
+}
+
+func (statement *Statement) attachInSql() {
+	inSql, inArgs := statement.genInSql()
+	if len(inSql) > 0 {
+		if statement.ConditionStr != "" {
+			statement.ConditionStr += " " + statement.Engine.dialect.AndStr() + " "
+		}
+		statement.ConditionStr += inSql
+		statement.Params = append(statement.Params, inArgs...)
+	}
+}
+
+func col2NewCols(columns ...string) []string {
+	newColumns := make([]string, 0)
+	for _, col := range columns {
+		col = strings.Replace(col, "`", "", -1)
+		col = strings.Replace(col, `"`, "", -1)
+		ccols := strings.Split(col, ",")
+		for _, c := range ccols {
+			newColumns = append(newColumns, strings.TrimSpace(c))
+		}
+	}
+	return newColumns
+}
+
+func (engine *Engine) autoQuote(col string) string {
+	col = strings.Replace(col, "`", "", -1)
+	col = strings.Replace(col, engine.QuoteStr(), "", -1)
+	fields := strings.Split(strings.TrimSpace(col), ".")
+	for i, field := range fields {
+		fields[i] = engine.Quote(field)
+	}
+	return strings.Join(fields, ".")
+}
+
+func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
+	newColumns := make([]string, 0)
+	for _, col := range columns {
+		col = strings.Replace(col, "`", "", -1)
+		col = strings.Replace(col, statement.Engine.QuoteStr(), "", -1)
+		ccols := strings.Split(col, ",")
+		for _, c := range ccols {
+			fields := strings.Split(strings.TrimSpace(c), ".")
+			if len(fields) == 1 {
+				newColumns = append(newColumns, statement.Engine.Quote(fields[0]))
+			} else if len(fields) == 2 {
+				newColumns = append(newColumns, statement.Engine.Quote(fields[0])+"."+
+					statement.Engine.Quote(fields[1]))
+			} else {
+				panic(errors.New("unwanted colnames"))
+			}
+		}
+	}
+	return newColumns
+}
+
+// Generate "Distince col1, col2 " statment
+func (statement *Statement) Distinct(columns ...string) *Statement {
+	statement.IsDistinct = true
+	statement.Cols(columns...)
+	return statement
+}
+
+// Generate "col1, col2" statement
+func (statement *Statement) Cols(columns ...string) *Statement {
+	newColumns := col2NewCols(columns...)
+	for _, nc := range newColumns {
+		statement.columnMap[strings.ToLower(nc)] = true
+	}
+	statement.ColumnStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
+	if strings.Contains(statement.ColumnStr, ".") {
+		statement.ColumnStr = strings.Replace(statement.ColumnStr, ".", statement.Engine.Quote("."), -1)
+	}
+	return statement
+}
+
+// Update use only: update all columns
+func (statement *Statement) AllCols() *Statement {
+	statement.useAllCols = true
+	return statement
+}
+
+// Update use only: must update columns
+func (statement *Statement) MustCols(columns ...string) *Statement {
+	newColumns := col2NewCols(columns...)
+	for _, nc := range newColumns {
+		statement.mustColumnMap[strings.ToLower(nc)] = true
+	}
+	return statement
+}
+
+// Update use only: not update columns
+/*func (statement *Statement) NotCols(columns ...string) *Statement {
+	newColumns := col2NewCols(columns...)
+	for _, nc := range newColumns {
+		statement.mustColumnMap[strings.ToLower(nc)] = false
+	}
+	return statement
+}*/
+
+// indicates that use bool fields as update contents and query contiditions
+func (statement *Statement) UseBool(columns ...string) *Statement {
+	if len(columns) > 0 {
+		statement.MustCols(columns...)
+	} else {
+		statement.allUseBool = true
+	}
+	return statement
+}
+
+// do not use the columns
+func (statement *Statement) Omit(columns ...string) {
+	newColumns := col2NewCols(columns...)
+	for _, nc := range newColumns {
+		statement.columnMap[strings.ToLower(nc)] = false
+	}
+	statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
+}
+
+// Generate LIMIT limit statement
+func (statement *Statement) Top(limit int) *Statement {
+	statement.Limit(limit)
+	return statement
+}
+
+// Generate LIMIT start, limit statement
+func (statement *Statement) Limit(limit int, start ...int) *Statement {
+	statement.LimitN = limit
+	if len(start) > 0 {
+		statement.Start = start[0]
+	}
+	return statement
+}
+
+// Generate "Order By order" statement
+func (statement *Statement) OrderBy(order string) *Statement {
+	if statement.OrderStr != "" {
+		statement.OrderStr += ", "
+	}
+	statement.OrderStr += order
+	return statement
+}
+
+func (statement *Statement) Desc(colNames ...string) *Statement {
+	if statement.OrderStr != "" {
+		statement.OrderStr += ", "
+	}
+	newColNames := statement.col2NewColsWithQuote(colNames...)
+	sqlStr := strings.Join(newColNames, " DESC, ")
+	statement.OrderStr += sqlStr + " DESC"
+	return statement
+}
+
+// Method Asc provide asc order by query condition, the input parameters are columns.
+func (statement *Statement) Asc(colNames ...string) *Statement {
+	if statement.OrderStr != "" {
+		statement.OrderStr += ", "
+	}
+	newColNames := statement.col2NewColsWithQuote(colNames...)
+	sqlStr := strings.Join(newColNames, " ASC, ")
+	statement.OrderStr += sqlStr + " ASC"
+	return statement
+}
+
+//The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
+func (statement *Statement) Join(join_operator string, tablename interface{}, condition string) *Statement {
+	var joinTable string
+	switch tablename.(type) {
+	case []string:
+		t := tablename.([]string)
+		l := len(t)
+		if l > 1 {
+			table := t[0]
+			joinTable = statement.Engine.Quote(table) + " AS " + statement.Engine.Quote(t[1])
+		} else if l == 1 {
+			table := t[0]
+			joinTable = statement.Engine.Quote(table)
+		}
+	case []interface{}:
+		t := tablename.([]interface{})
+		l := len(t)
+		table := ""
+		if l > 0 {
+			f := t[0]
+			v := rValue(f)
+			t := v.Type()
+			if t.Kind() == reflect.String {
+				table = f.(string)
+			} else if t.Kind() == reflect.Struct {
+				r := statement.Engine.autoMapType(v)
+				table = r.Name
+			}
+		}
+		if l > 1 {
+			joinTable = statement.Engine.Quote(table) + " AS " + statement.Engine.Quote(fmt.Sprintf("%v", t[1]))
+		} else if l == 1 {
+			joinTable = statement.Engine.Quote(table)
+		}
+	default:
+		t := fmt.Sprintf("%v", tablename)
+		joinTable = statement.Engine.Quote(t)
+	}
+	if statement.JoinStr != "" {
+		statement.JoinStr = statement.JoinStr + fmt.Sprintf(" %v JOIN %v ON %v", join_operator,
+			joinTable, condition)
+	} else {
+		statement.JoinStr = fmt.Sprintf("%v JOIN %v ON %v", join_operator,
+			joinTable, condition)
+	}
+	return statement
+}
+
+// Generate "Group By keys" statement
+func (statement *Statement) GroupBy(keys string) *Statement {
+	statement.GroupByStr = keys
+	return statement
+}
+
+// Generate "Having conditions" statement
+func (statement *Statement) Having(conditions string) *Statement {
+	statement.HavingStr = fmt.Sprintf("HAVING %v", conditions)
+	return statement
+}
+
+// Always disable struct tag "deleted"
+func (statement *Statement) Unscoped() *Statement {
+	statement.unscoped = true
+	return statement
+}
+
+func (statement *Statement) genColumnStr() string {
+	table := statement.RefTable
+	colNames := make([]string, 0)
+	for _, col := range table.Columns() {
+		if statement.OmitStr != "" {
+			if _, ok := statement.columnMap[strings.ToLower(col.Name)]; ok {
+				continue
+			}
+		}
+		if col.MapType == core.ONLYTODB {
+			continue
+		}
+
+		if statement.JoinStr != "" {
+			var name string
+			if statement.TableAlias != "" {
+				name = statement.Engine.Quote(statement.TableAlias)
+			} else {
+				name = statement.Engine.Quote(statement.TableName())
+			}
+			name += "." + statement.Engine.Quote(col.Name)
+			if col.IsPrimaryKey && statement.Engine.Dialect().DBType() == "ql" {
+				colNames = append(colNames, "id() AS "+name)
+			} else {
+				colNames = append(colNames, name)
+			}
+		} else {
+			name := statement.Engine.Quote(col.Name)
+			if col.IsPrimaryKey && statement.Engine.Dialect().DBType() == "ql" {
+				colNames = append(colNames, "id() AS "+name)
+			} else {
+				colNames = append(colNames, name)
+			}
+		}
+	}
+	return strings.Join(colNames, ", ")
+}
+
+func (statement *Statement) genCreateTableSQL() string {
+	return statement.Engine.dialect.CreateTableSql(statement.RefTable, statement.AltTableName,
+		statement.StoreEngine, statement.Charset)
+}
+
+func indexName(tableName, idxName string) string {
+	return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
+}
+
+func (s *Statement) genIndexSQL() []string {
+	var sqls []string = make([]string, 0)
+	tbName := s.TableName()
+	quote := s.Engine.Quote
+	for idxName, index := range s.RefTable.Indexes {
+		if index.Type == core.IndexType {
+			sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(tbName, idxName)),
+				quote(tbName), quote(strings.Join(index.Cols, quote(","))))
+			sqls = append(sqls, sql)
+		}
+	}
+	return sqls
+}
+
+func uniqueName(tableName, uqeName string) string {
+	return fmt.Sprintf("UQE_%v_%v", tableName, uqeName)
+}
+
+func (s *Statement) genUniqueSQL() []string {
+	var sqls []string = make([]string, 0)
+	tbName := s.TableName()
+	for _, index := range s.RefTable.Indexes {
+		if index.Type == core.UniqueType {
+			sql := s.Engine.dialect.CreateIndexSql(tbName, index)
+			sqls = append(sqls, sql)
+		}
+	}
+	return sqls
+}
+
+func (s *Statement) genDelIndexSQL() []string {
+	var sqls []string = make([]string, 0)
+	for idxName, index := range s.RefTable.Indexes {
+		var rIdxName string
+		if index.Type == core.UniqueType {
+			rIdxName = uniqueName(s.TableName(), idxName)
+		} else if index.Type == core.IndexType {
+			rIdxName = indexName(s.TableName(), idxName)
+		}
+		sql := fmt.Sprintf("DROP INDEX %v", s.Engine.Quote(rIdxName))
+		if s.Engine.dialect.IndexOnTable() {
+			sql += fmt.Sprintf(" ON %v", s.Engine.Quote(s.TableName()))
+		}
+		sqls = append(sqls, sql)
+	}
+	return sqls
+}
+
+/*
+func (s *Statement) genDropSQL() string {
+	return s.Engine.dialect.MustDropTa(s.TableName()) + ";"
+}*/
+
+func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) {
+	var table *core.Table
+	if statement.RefTable == nil {
+		table = statement.Engine.TableInfo(bean)
+		statement.RefTable = table
+	} else {
+		table = statement.RefTable
+	}
+
+	colNames, args := buildConditions(statement.Engine, table, bean, true, true,
+		false, true, statement.allUseBool, statement.useAllCols,
+		statement.unscoped, statement.mustColumnMap)
+
+	statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.dialect.AndStr()+" ")
+	statement.BeanArgs = args
+
+	var columnStr string = statement.ColumnStr
+	if len(statement.JoinStr) == 0 {
+		if len(columnStr) == 0 {
+			if statement.GroupByStr != "" {
+				columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
+			} else {
+				columnStr = statement.genColumnStr()
+			}
+		}
+	} else {
+		if len(columnStr) == 0 {
+			if statement.GroupByStr != "" {
+				columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
+			} else {
+				columnStr = "*"
+			}
+		}
+	}
+
+	statement.attachInSql() // !admpub!  fix bug:Iterate func missing "... IN (...)"
+	return statement.genSelectSql(columnStr), append(statement.Params, statement.BeanArgs...)
+}
+
+func (s *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) {
+	quote := s.Engine.Quote
+	sql := fmt.Sprintf("ALTER TABLE %v ADD %v;", quote(s.TableName()),
+		col.String(s.Engine.dialect))
+	return sql, []interface{}{}
+}
+
+/*func (s *Statement) genAddIndexStr(idxName string, cols []string) (string, []interface{}) {
+	quote := s.Engine.Quote
+	colstr := quote(strings.Join(cols, quote(", ")))
+	sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(idxName), quote(s.TableName()), colstr)
+	return sql, []interface{}{}
+}
+
+func (s *Statement) genAddUniqueStr(uqeName string, cols []string) (string, []interface{}) {
+	quote := s.Engine.Quote
+	colstr := quote(strings.Join(cols, quote(", ")))
+	sql := fmt.Sprintf("CREATE UNIQUE INDEX %v ON %v (%v);", quote(uqeName), quote(s.TableName()), colstr)
+	return sql, []interface{}{}
+}*/
+
+func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}) {
+	table := statement.Engine.TableInfo(bean)
+	statement.RefTable = table
+
+	colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
+		true, statement.allUseBool, statement.useAllCols,
+		statement.unscoped, statement.mustColumnMap)
+
+	statement.ConditionStr = strings.Join(colNames, " "+statement.Engine.Dialect().AndStr()+" ")
+	statement.BeanArgs = args
+
+	// count(index fieldname) > count(0) > count(*)
+	var id string = "*"
+	if statement.Engine.Dialect().DBType() == "ql" {
+		id = ""
+	}
+	statement.attachInSql()
+	return statement.genSelectSql(fmt.Sprintf("count(%v)", id)), append(statement.Params, statement.BeanArgs...)
+}
+
+func (statement *Statement) genSelectSql(columnStr string) (a string) {
+	/*if statement.GroupByStr != "" {
+		if columnStr == "" {
+			columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
+		}
+		//statement.GroupByStr = columnStr
+	}*/
+	var distinct string
+	if statement.IsDistinct {
+		distinct = "DISTINCT "
+	}
+
+	var top string
+	var mssqlCondi string
+	/*var orderBy string
+	if statement.OrderStr != "" {
+		orderBy = fmt.Sprintf(" ORDER BY %v", statement.OrderStr)
+	}*/
+	statement.processIdParam()
+	var whereStr string
+	if statement.WhereStr != "" {
+		whereStr = fmt.Sprintf(" WHERE %v", statement.WhereStr)
+		if statement.ConditionStr != "" {
+			whereStr = fmt.Sprintf("%v %s %v", whereStr, statement.Engine.Dialect().AndStr(),
+				statement.ConditionStr)
+		}
+	} else if statement.ConditionStr != "" {
+		whereStr = fmt.Sprintf(" WHERE %v", statement.ConditionStr)
+	}
+	var fromStr string = " FROM " + statement.Engine.Quote(statement.TableName())
+	if statement.TableAlias != "" {
+		if statement.Engine.dialect.DBType() == core.ORACLE {
+			fromStr += " " + statement.Engine.Quote(statement.TableAlias)
+		} else {
+			fromStr += " AS " + statement.Engine.Quote(statement.TableAlias)
+		}
+	}
+	if statement.JoinStr != "" {
+		fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr)
+	}
+
+	if statement.Engine.dialect.DBType() == core.MSSQL {
+		if statement.LimitN > 0 {
+			top = fmt.Sprintf(" TOP %d ", statement.LimitN)
+		}
+		if statement.Start > 0 {
+			var column string = "(id)"
+			if len(statement.RefTable.PKColumns()) == 0 {
+				for _, index := range statement.RefTable.Indexes {
+					if len(index.Cols) == 1 {
+						column = index.Cols[0]
+						break
+					}
+				}
+				if len(column) == 0 {
+					column = statement.RefTable.ColumnsSeq()[0]
+				}
+			}
+			var orderStr string
+			if len(statement.OrderStr) > 0 {
+				orderStr = " ORDER BY " + statement.OrderStr
+			}
+			var groupStr string
+			if len(statement.GroupByStr) > 0 {
+				groupStr = " GROUP BY " + statement.GroupByStr
+			}
+			mssqlCondi = fmt.Sprintf("(%s NOT IN (SELECT TOP %d %s%s%s%s%s))",
+				column, statement.Start, column, fromStr, whereStr, orderStr, groupStr)
+		}
+	}
+
+	// !nashtsai! REVIEW Sprintf is considered slowest mean of string concatnation, better to work with builder pattern
+	a = fmt.Sprintf("SELECT %v%v%v%v%v", top, distinct, columnStr,
+		fromStr, whereStr)
+	if mssqlCondi != "" {
+		if whereStr != "" {
+			a += " AND " + mssqlCondi
+		} else {
+			a += " WHERE " + mssqlCondi
+		}
+	}
+
+	if statement.GroupByStr != "" {
+		a = fmt.Sprintf("%v GROUP BY %v", a, statement.GroupByStr)
+	}
+	if statement.HavingStr != "" {
+		a = fmt.Sprintf("%v %v", a, statement.HavingStr)
+	}
+	if statement.OrderStr != "" {
+		a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
+	}
+	if statement.Engine.dialect.DBType() != core.MSSQL && statement.Engine.dialect.DBType() != core.ORACLE {
+		if statement.Start > 0 {
+			a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start)
+		} else if statement.LimitN > 0 {
+			a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN)
+		}
+	} else if statement.Engine.dialect.DBType() == core.ORACLE {
+		if statement.Start != 0 || statement.LimitN != 0 {
+			a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start)
+		}
+	}
+
+	return
+}
+
+func (statement *Statement) processIdParam() {
+	if statement.IdParam != nil {
+		if statement.Engine.dialect.DBType() != "ql" {
+			for i, col := range statement.RefTable.PKColumns() {
+				if i < len(*(statement.IdParam)) {
+					statement.And(fmt.Sprintf("%v %s ?", statement.Engine.Quote(col.Name),
+						statement.Engine.dialect.EqStr()), (*(statement.IdParam))[i])
+				} else {
+					statement.And(fmt.Sprintf("%v %s ?", statement.Engine.Quote(col.Name),
+						statement.Engine.dialect.EqStr()), "")
+				}
+			}
+		} else {
+			if len(*(statement.IdParam)) <= 1 {
+				statement.And("id() == ?", (*(statement.IdParam))[0])
+			}
+		}
+	}
+}

+ 63 - 0
syslogger.go

@@ -0,0 +1,63 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows,!nacl,!plan9
+
+package xorm
+
+import (
+	"fmt"
+	"log/syslog"
+
+	"github.com/xormplus/core"
+)
+
+type SyslogLogger struct {
+	w *syslog.Writer
+}
+
+func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
+	return &SyslogLogger{w: w}
+}
+
+func (s *SyslogLogger) Debug(v ...interface{}) (err error) {
+	return s.w.Debug(fmt.Sprint(v...))
+}
+
+func (s *SyslogLogger) Debugf(format string, v ...interface{}) (err error) {
+	return s.w.Debug(fmt.Sprintf(format, v...))
+}
+
+func (s *SyslogLogger) Err(v ...interface{}) (err error) {
+	return s.w.Err(fmt.Sprint(v...))
+}
+
+func (s *SyslogLogger) Errf(format string, v ...interface{}) (err error) {
+	return s.w.Err(fmt.Sprintf(format, v...))
+}
+
+func (s *SyslogLogger) Info(v ...interface{}) (err error) {
+	return s.w.Info(fmt.Sprint(v...))
+}
+
+func (s *SyslogLogger) Infof(format string, v ...interface{}) (err error) {
+	return s.w.Info(fmt.Sprintf(format, v...))
+}
+
+func (s *SyslogLogger) Warning(v ...interface{}) (err error) {
+	return s.w.Warning(fmt.Sprint(v...))
+}
+
+func (s *SyslogLogger) Warningf(format string, v ...interface{}) (err error) {
+	return s.w.Warning(fmt.Sprintf(format, v...))
+}
+
+func (s *SyslogLogger) Level() core.LogLevel {
+	return core.LOG_UNKNOWN
+}
+
+// SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
+func (s *SyslogLogger) SetLevel(l core.LogLevel) (err error) {
+	return fmt.Errorf("unable to set syslog level")
+}

+ 7 - 0
test/sql/oracle/select.example.stpl

@@ -0,0 +1,7 @@
+select id,userid,title,createdatetime,content 
+from article where  
+{% if count>1%}
+id=?id
+{% else%}
+userid=?userid
+{% endif %}

+ 9 - 0
test/sql/oracle/studygolang.xml

@@ -0,0 +1,9 @@
+<sqlMap>
+<sql id="selectAllArticle">
+select id,title,createdatetime,content 
+from article where id in (?1,?2)
+</sql>
+<sql id="selectStudentById1">
+select * from article where id=?id
+</sql>
+</sqlMap>

+ 1 - 0
test/sql/xormcfg.ini

@@ -0,0 +1 @@
+sqlMapRootDir = ./sql/oracle

+ 273 - 0
test/xorm_test.go

@@ -0,0 +1,273 @@
+package xorm
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/xormplus/xorm"
+
+	_ "github.com/lib/pq"
+)
+
+type Article struct {
+	Id             int       `xorm:"not null pk autoincr unique INTEGER"`
+	Content        string    `xorm:"not null TEXT"`
+	Title          string    `xorm:"not null VARCHAR(255)"`
+	Categorysubid  int       `xorm:"not null INTEGER"`
+	Remark         string    `xorm:"not null VARCHAR(2555)"`
+	Userid         int       `xorm:"not null INTEGER"`
+	Viewcount      int       `xorm:"not null default 0 INTEGER"`
+	Replycount     int       `xorm:"not null default 0 INTEGER"`
+	Tags           string    `xorm:"not null VARCHAR(300)"`
+	Createdatetime JSONTime  `xorm:"not null default 'now()' DATETIME"`
+	Isdraft        int       `xorm:"SMALLINT"`
+	Lastupdatetime time.Time `xorm:"not null default 'now()' DATETIME"`
+}
+
+type JSONTime time.Time
+
+func (t JSONTime) MarshalJSON() ([]byte, error) {
+	//do your serializing here
+	stamp := fmt.Sprintf("\"%s\"", time.Time(t).Format("2006/01/08 15:04:05"))
+	return []byte(stamp), nil
+}
+
+var db *xorm.Engine
+
+func Test_InitDB(t *testing.T) {
+	var err error
+	db, err = xorm.NewPostgreSQL("postgres://postgres:root@localhost:5432/mblog?sslmode=disable")
+
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func Test_GetFirst_Json(t *testing.T) {
+	var article Article
+	has,rows, err := db.Id(2).GetFirst(&article).Json()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !has{
+		t.Log("[Test_GetFirst_Json]->rows: not exist\n")
+	}
+	t.Log("[Test_GetFirst_Json]->rows:\n" + rows)
+}
+
+func Test_GetFirst_Xml(t *testing.T) {
+	var article Article
+	has,rows, err := db.Where("userid =?",3).GetFirst(&article).Xml()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !has{
+		t.Log("[Test_GetFirst_Xml]->rows: not exist\n")
+	}
+	t.Log("[Test_GetFirst_Xml]->rows:\n" + rows)
+}
+
+func Test_GetFirst_XmlIndent(t *testing.T) {
+	var article Article
+	has,rows, err := db.Where("userid =?",3).GetFirst(&article).XmlIndent("","  ","article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !has{
+		t.Log("[Test_GetFirst_XmlIndent]->rows: not exist\n")
+	}
+	t.Log("[Test_GetFirst_XmlIndent]->rows:\n" + rows)
+}
+
+func Test_FindAll_Json(t *testing.T) {
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?", 2).FindAll().Json()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAll_Json]->rows:\n" + rows)
+}
+
+func Test_FindAll_Xml(t *testing.T) {
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?", 2).FindAll().Xml()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAll_Xml]->rows:\n" + rows)
+}
+
+func Test_FindAll_XmlIndent(t *testing.T) {
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?", 2).FindAll().XmlIndent("", "  ", "article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAll_XmlIndent]->rows:\n" + rows)
+}
+
+func Test_FindAllWithDateFormat_Json(t *testing.T) {
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?", 2).FindAllWithDateFormat("20060102").Json()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAllWithDateFormat_Json]->rows:\n" + rows)
+}
+
+func Test_FindAllWithDateFormat_Xml(t *testing.T) {
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?", 2).FindAllWithDateFormat("20060102").Xml()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAllWithDateFormat_Xml]->rows:\n" + rows)
+}
+
+func Test_FindAllWithDateFormat_XmlIndent(t *testing.T) {
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id in (?,?)", 2, 5).FindAllWithDateFormat("20060102").XmlIndent("", "  ", "article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAllWithDateFormat_XmlIndent]->rows:\n" + rows)
+}
+
+func Test_FindAllByParamMap_Json(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 4, "userid": 1}
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?id and userid=?userid", &paramMap).FindAllByParamMap().Json()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAllByParamMap_Json]->rows:\n" + rows)
+}
+
+func Test_FindAllByParamMap_Xml(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 6, "userid": 1}
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?id and userid=?userid", &paramMap).FindAllByParamMap().Xml()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAllByParamMap_Xml]->rows:\n" + rows)
+}
+
+func Test_FindAllByParamMap_XmlIndent(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 6, "userid": 1}
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?id and userid=?userid", &paramMap).FindAllByParamMap().XmlIndent("", "  ", "article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAllByParamMap_XmlIndent]->rows:\n" + rows)
+}
+
+func Test_FindAllByParamMapWithDateFormat_XmlIndent(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 5, "userid": 1}
+	rows, err := db.Sql("select id,title,createdatetime,content from article where id = ?id and userid=?userid", &paramMap).FindAllByParamMapWithDateFormat("2006/01/02").XmlIndent("", "  ", "article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_FindAllByParamMapWithDateFormat_XmlIndent]->rows:\n" + rows)
+}
+
+func Test_SqlMapClient_FindAllByParamMap_Json(t *testing.T) {
+	paramMap := map[string]interface{}{"1": 2, "2": 5}
+	rows, err := db.SqlMapClient("selectAllArticle", &paramMap).FindAllByParamMap().Json()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlMapClient_FindAllByParamMap_Json]->rows:\n" + rows)
+}
+
+func Test_SqlMapClient_FindAllByParamMapWithDateFormat_Json(t *testing.T) {
+	paramMap := map[string]interface{}{"1": 2, "2": 5}
+	rows, err := db.SqlMapClient("selectAllArticle", &paramMap).FindAllByParamMapWithDateFormat("2006-01-02 15:04").Json()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlMapClient_FindAllByParamMapWithDateFormat_Json]->rows:\n" + rows)
+}
+
+func Test_SqlMapClient_FindAllByParamMap_Xml(t *testing.T) {
+	paramMap := map[string]interface{}{"1": 2, "2": 5}
+	rows, err := db.SqlMapClient("selectAllArticle", &paramMap).FindAllByParamMap().Xml()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlMapClient_FindAllByParamMap_Xml]->rows:\n" + rows)
+}
+
+func Test_SqlMapClient_FindAllByParamMapWithDateFormat_Xml(t *testing.T) {
+	paramMap := map[string]interface{}{"1": 2, "2": 5}
+	rows, err := db.SqlMapClient("selectAllArticle", &paramMap).FindAllByParamMapWithDateFormat("2006-01-02 15:04").Xml()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlMapClient_FindAllByParamMapWithDateFormat_Xml]->rows:\n" + rows)
+}
+
+func Test_SqlMapClient_FindAllByParamMap_XmlIndent(t *testing.T) {
+	paramMap := map[string]interface{}{"1": 2, "2": 5}
+	rows, err := db.SqlMapClient("selectAllArticle", &paramMap).FindAllByParamMap().XmlIndent("", "  ", "article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlMapClient_FindAllByParamMap_XmlIndent]->rows:\n" + rows)
+}
+
+func Test_SqlMapClient_FindAllByParamMapWithDateFormat_XmlIndent(t *testing.T) {
+	paramMap := map[string]interface{}{"1": 2, "2": 5}
+	rows, err := db.SqlMapClient("selectAllArticle", &paramMap).FindAllByParamMapWithDateFormat("2006-01-02 15:04").XmlIndent("", "  ", "article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlMapClient_FindAllByParamMapWithDateFormat_XmlIndent]->rows:\n" + rows)
+}
+
+func Test_SqlTemplateClient_FindAllByParamMap_Json(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 2, "userid": 3, "count": 1}
+	rows, err := db.SqlTemplateClient("select.example.stpl", paramMap).FindAllByParamMap().Json()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlTemplateClient_FindAllByParamMap_Json]->rows:\n" + rows)
+}
+
+func Test_SqlTemplateClient_FindAllByParamMapWithDateFormat_Json(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 2, "userid": 3, "count": 1}
+	rows, err := db.SqlTemplateClient("select.example.stpl", paramMap).FindAllByParamMapWithDateFormat("01/02/2006").Json()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlTemplateClient_FindAllByParamMapWithDateFormat_Json]->rows:\n" + rows)
+}
+
+func Test_SqlTemplateClient_FindAllByParamMap_Xml(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 2, "userid": 3, "count": 2}
+	rows, err := db.SqlTemplateClient("select.example.stpl", paramMap).FindAllByParamMap().Xml()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlTemplateClient_FindAllByParamMap_Xml]->rows:\n" + rows)
+}
+
+func Test_SqlTemplateClient_FindAllByParamMapWithDateFormat_Xml(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 2, "userid": 3, "count": 2}
+	rows, err := db.SqlTemplateClient("select.example.stpl", paramMap).FindAllByParamMapWithDateFormat("01/02/2006").Xml()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlTemplateClient_FindAllByParamMapWithDateFormat_Xml]->rows:\n" + rows)
+}
+
+func Test_SqlTemplateClient_FindAllByParamMap_XmlIndent(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 2, "userid": 3, "count": 2}
+	rows, err := db.SqlTemplateClient("select.example.stpl", paramMap).FindAllByParamMap().XmlIndent("", "  ", "article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlTemplateClient_FindAllByParamMap_XmlIndent]->rows:\n" + rows)
+}
+
+func Test_SqlTemplateClient_FindAllByParamMapWithDateFormat_XmlIndent(t *testing.T) {
+	paramMap := map[string]interface{}{"id": 2, "userid": 3, "count": 2}
+	rows, err := db.SqlTemplateClient("select.example.stpl", paramMap).FindAllByParamMapWithDateFormat("01/02/2006").XmlIndent("", "  ", "article")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("[Test_SqlTemplateClient_FindAllByParamMapWithDateFormat_XmlIndent]->rows:\n" + rows)
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 87 - 0
test/测试结果.txt


+ 111 - 0
xorm.go

@@ -0,0 +1,111 @@
+// Copyright 2015 The Xorm Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xorm
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"reflect"
+	"runtime"
+	"sync"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+const (
+	Version string = "1.0.0"
+)
+
+// new a db manager according to the parameter. Currently support four
+// drivers
+func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
+	regDrvsNDialects()
+	driver := core.QueryDriver(driverName)
+	if driver == nil {
+		return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
+	}
+
+	uri, err := driver.Parse(driverName, dataSourceName)
+	if err != nil {
+		return nil, err
+	}
+
+	dialect := core.QueryDialect(uri.DbType)
+	if dialect == nil {
+		return nil, errors.New(fmt.Sprintf("Unsupported dialect type: %v", uri.DbType))
+	}
+
+	db, err := core.Open(driverName, dataSourceName)
+	if err != nil {
+		return nil, err
+	}
+
+	err = dialect.Init(db, uri, driverName, dataSourceName)
+	if err != nil {
+		return nil, err
+	}
+
+	sqlMap := SqlMap{}
+	err = sqlMap.Init()
+
+	engine := &Engine{
+		db:            db,
+		dialect:       dialect,
+		Tables:        make(map[reflect.Type]*core.Table),
+		mutex:         &sync.RWMutex{},
+		TagIdentifier: "xorm",
+		Logger:        NewSimpleLogger(os.Stdout),
+		TZLocation:    time.Local,
+		SqlMap:        sqlMap,
+	}
+
+	if err != nil {
+		engine.Logger.Warning(err)
+	}
+
+	engine.dialect.SetLogger(engine.Logger)
+
+	engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
+
+	runtime.SetFinalizer(engine, close)
+
+	return engine, nil
+}
+
+func regDrvsNDialects() bool {
+	providedDrvsNDialects := map[string]struct {
+		dbType     core.DbType
+		getDriver  func() core.Driver
+		getDialect func() core.Dialect
+	}{
+		"mssql":    {"mssql", func() core.Driver { return &odbcDriver{} }, func() core.Dialect { return &mssql{} }},
+		"odbc":     {"mssql", func() core.Driver { return &odbcDriver{} }, func() core.Dialect { return &mssql{} }}, // !nashtsai! TODO change this when supporting MS Access
+		"mysql":    {"mysql", func() core.Driver { return &mysqlDriver{} }, func() core.Dialect { return &mysql{} }},
+		"mymysql":  {"mysql", func() core.Driver { return &mymysqlDriver{} }, func() core.Dialect { return &mysql{} }},
+		"postgres": {"postgres", func() core.Driver { return &pqDriver{} }, func() core.Dialect { return &postgres{} }},
+		"sqlite3":  {"sqlite3", func() core.Driver { return &sqlite3Driver{} }, func() core.Dialect { return &sqlite3{} }},
+		"oci8":     {"oracle", func() core.Driver { return &oci8Driver{} }, func() core.Dialect { return &oracle{} }},
+		"goracle":  {"oracle", func() core.Driver { return &goracleDriver{} }, func() core.Dialect { return &oracle{} }},
+	}
+
+	for driverName, v := range providedDrvsNDialects {
+		if driver := core.QueryDriver(driverName); driver == nil {
+			core.RegisterDriver(driverName, v.getDriver())
+			core.RegisterDialect(v.dbType, v.getDialect())
+		}
+	}
+	return true
+}
+
+func close(engine *Engine) {
+	engine.Close()
+}
+
+// clone an engine
+func (engine *Engine) Clone() (*Engine, error) {
+	return NewEngine(engine.DriverName(), engine.DataSourceName())
+}

+ 141 - 0
xormplus.go

@@ -0,0 +1,141 @@
+package xorm
+
+import (
+	"encoding/xml"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+//	"fmt"
+
+	"github.com/Unknwon/goconfig"
+	"gopkg.in/flosch/pongo2.v3"
+)
+
+const (
+	MSSQL_DRIVER      string = "mssql"
+	MSSQL_ODBC_DRIVER string = "odbc"
+	MYSQL_DRIVER      string = "mysql"
+	MYMYSQL_DRIVER    string = "mymysql"
+	POSTGRESQL_DRIVER string = "postgres"
+	OCI8_DRIVER       string = "oci8"
+	GORACLE_DRIVER    string = "goracle"
+	SQLITE3_DRIVER    string = "sqlite3"
+)
+
+type SqlMap struct {
+	Sql         map[string]string
+	SqlTemplate map[string]*pongo2.Template
+	Cfg goconfig.ConfigFile
+}
+
+type Result struct {
+	Sql []Sql `xml:"sql"`
+}
+
+type Sql struct {
+	Value string `xml:",chardata"`
+	Id    string `xml:"id,attr"`
+}
+
+func (sqlMap *SqlMap) Init() error {
+	var err error
+	cfg, err := goconfig.LoadConfigFile("./sql/xormcfg.ini")
+	if err != nil {
+		return err
+	}
+	var sqlMapRootDir string
+	sqlMapRootDir, err = cfg.GetValue("", "sqlMapRootDir")
+	if err != nil {
+		return err
+	}
+
+	sqlMap.Sql = make(map[string]string)
+	sqlMap.SqlTemplate = make(map[string]*pongo2.Template)
+	err=filepath.Walk(sqlMapRootDir, sqlMap.walkFunc)
+	if err!=nil{
+		return err
+	}
+
+	return nil
+}
+
+func (sqlMap *SqlMap) walkFunc(path string, info os.FileInfo, err error) error {
+	if err!=nil{
+		return err
+	}
+
+	if info.IsDir() {
+		return nil
+	}
+
+	if strings.HasSuffix(path, ".xml") {
+		err = sqlMap.paresSql(path)
+		if err != nil {
+			return err
+		}
+	}
+
+	if strings.HasSuffix(path, ".stpl") {
+		err = sqlMap.paresSqlTemplate(info.Name(), path)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (sqlMap *SqlMap) paresSqlTemplate(filename string, filepath string) error {
+	template, err := pongo2.FromFile(filepath)
+	if err != nil {
+		return err
+	}
+
+	sqlMap.SqlTemplate[filename] = template
+	return nil
+}
+
+func (sqlMap *SqlMap) paresSql(filepath string) error {
+
+	content, err := ioutil.ReadFile(filepath)
+
+	if err != nil {
+		return err
+	}
+
+	var result Result
+	err = xml.Unmarshal(content, &result)
+	if err != nil {
+		return err
+	}
+
+	for _, sql := range result.Sql {
+		sqlMap.Sql[sql.Id] = sql.Value
+	}
+
+	return nil
+}
+
+func NewOracle(driverName string, dataSourceName string) (*Engine, error) {
+	return NewEngine(driverName, dataSourceName)
+}
+
+func NewMSSQL(driverName string, dataSourceName string) (*Engine, error) {
+	return NewEngine(driverName, dataSourceName)
+}
+
+func NewMySQL(driverName string, dataSourceName string) (*Engine, error) {
+	return NewEngine(driverName, dataSourceName)
+}
+
+func NewPostgreSQL(dataSourceName string) (*Engine, error) {
+	return NewEngine(POSTGRESQL_DRIVER, dataSourceName)
+}
+
+func NewSqlite3(dataSourceName string) (*Engine, error) {
+	return NewEngine(SQLITE3_DRIVER, dataSourceName)
+}
+
+func NewDB(driverName string, dataSourceName string) (*Engine, error) {
+	return NewEngine(driverName, dataSourceName)
+}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác