diff --git a/doc.go b/doc.go index b183e8d2..4980a372 100644 --- a/doc.go +++ b/doc.go @@ -19,17 +19,17 @@ Firstly, we should new an engine for a database Method NewEngine's parameters is the same as sql.Open. It depends drivers' implementation. -Generally, one engine is enough. You can set it as package variable. +Generally, one engine for an application is enough. You can set it as package variable. Raw Methods Xorm also support raw sql execution: -1. query sql, the returned results is []map[string][]byte +1. query a SQL string, the returned results is []map[string][]byte results, err := engine.Query("select * from user") -2. exec sql, the returned results +2. execute a SQL string, the returned results affected, err := engine.Exec("update user set .... where ...") @@ -57,29 +57,31 @@ There are 7 major ORM methods and many helpful methods to use to operate databas 3. Query multiple records from database - err := engine.Find(...) + sliceOfStructs := new(Struct) + err := engine.Find(sliceOfStructs) // SELECT * FROM user 4. Query multiple records and record by record handle, there two methods, one is Iterate, another is Raws - raws, err := engine.Raws(...) - // SELECT * FROM user - for raws.Next() { - raws.Scan(bean) - } - err := engine.Iterate(...) // SELECT * FROM user + raws, err := engine.Raws(...) + // SELECT * FROM user + bean := new(Struct) + for raws.Next() { + err = raws.Scan(bean) + } + 5. Update one or more records affected, err := engine.Update(&user) - // UPDATE user SET + // UPDATE user SET ... -6. Delete one or more records +6. Delete one or more records, Delete MUST has conditon - affected, err := engine.Delete(&user) + affected, err := engine.Where(...).Delete(&user) // DELETE FROM user Where ... 7. Count records @@ -89,14 +91,19 @@ another is Raws Conditions -The above 7 methods could use with condition methods. +The above 7 methods could use with condition methods chainable. +Attention: the above 7 methods should be the last chainable method. 1. Id, In - engine.Id(1).Get(&user) + engine.Id(1).Get(&user) // for single primary key // SELECT * FROM user WHERE id = 1 + engine.Id(core.PK{1, 2}).Get(&user) // for composite primary keys + // SELECT * FROM user WHERE id1 = 1 AND id2 = 2 engine.In("id", 1, 2, 3).Find(&users) // SELECT * FROM user WHERE id IN (1, 2, 3) + engine.In("id", []int{1, 2, 3}) + // SELECT * FROM user WHERE id IN (1, 2, 3) 2. Where, And, Or @@ -114,10 +121,11 @@ The above 7 methods could use with condition methods. engine.Limit().Find() // SELECT * FROM user LIMIT .. OFFSET .. - engine.Top().Find() - // SELECT * FROM user LIMIT .. + engine.Top(5).Find() + // SELECT TOP 5 * FROM user // for mssql + // SELECT * FROM user LIMIT .. OFFSET 0 //for other databases -5. Sql +5. Sql, let you custom SQL engine.Sql("select * from user").Find() @@ -125,8 +133,12 @@ The above 7 methods could use with condition methods. engine.Cols("col1, col2").Find() // SELECT col1, col2 FROM user + engine.Cols("col1", "col2").Where().Update(user) + // UPDATE user set col1 = ?, col2 = ? Where ... engine.Omit("col1").Find() // SELECT col2, col3 FROM user + engine.Omit("col1").Insert() + // INSERT INTO table (non-col1) VALUES () engine.Distinct("col1").Find() // SELECT DISTINCT col1 FROM user diff --git a/docs/QuickStart.md b/docs/QuickStart.md index 3b9f0aab..a363fdf2 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -346,7 +346,6 @@ Notice: If you want to use transaction on inserting, you should use session.Begi ### 5.1. Chainable APIs for Queries, Execusions and Aggregations Queries and Aggregations is basically formed by using `Get`, `Find`, `Count` methods, with conjunction of following chainable APIs to form conditions, grouping and ordering: -查询和统计主要使用`Get`, `Find`, `Count`三个方法。在进行查询时可以使用多个方法来形成查询条件,条件函数如下: * Id([]interface{}) Primary Key lookup @@ -535,16 +534,16 @@ affected, err := engine.Table(new(User)).Id(id).Update(map[string]interface{}{"a ``` -### 6.1.乐观锁 +### 6.1.Optimistic Lock -要使用乐观锁,需要使用version标记 +To enable object optimistic lock, add 'version' tag value: type User struct { Id int64 Name string Version int `xorm:"version"` } -在Insert时,version标记的字段将会被设置为1,在Update时,Update的内容必须包含version原来的值。 +The version starts with 1 when inserted to DB. For updating make sure originated version value is used for optimistic lock check. ```Go var user User diff --git a/engine.go b/engine.go index dfe146d4..08b17872 100644 --- a/engine.go +++ b/engine.go @@ -42,6 +42,14 @@ type Engine struct { Logger core.ILogger TZLocation *time.Location + + disableGlobalCache bool +} + +func (engine *Engine) SetDisableGlobalCache(disable bool) { + if engine.disableGlobalCache != disable { + engine.disableGlobalCache = disable + } } func (engine *Engine) DriverName() string { @@ -186,6 +194,30 @@ func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) { } } +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("sql [%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("sql [%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() @@ -380,7 +412,12 @@ func (engine *Engine) DumpAll(w io.Writer) error { temp += fmt.Sprintf(", '%s'", d.(string)) } } else if col.SQLType.IsNumeric() { - temp += fmt.Sprintf(", %s", string(d.([]byte))) + 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, "-") { @@ -591,7 +628,7 @@ func (engine *Engine) autoMapType(v reflect.Value) *core.Table { return table } -func (engine *Engine) autoMap(bean interface{}) *core.Table { +func (engine *Engine) TableInfo(bean interface{}) *core.Table { v := rValue(bean) return engine.autoMapType(v) } @@ -610,7 +647,10 @@ func addIndex(indexName string, table *core.Table, col *core.Column, indexType i func (engine *Engine) newTable() *core.Table { table := core.NewEmptyTable() - table.Cacher = engine.Cacher + + if !engine.disableGlobalCache { + table.Cacher = engine.Cacher + } return table } @@ -639,6 +679,9 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { var idFieldColName string var err error + hasCacheTag := false + hasNoCacheTag := false + for i := 0; i < t.NumField(); i++ { tag := t.Field(i).Tag @@ -733,6 +776,14 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { 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, "'") { @@ -841,7 +892,7 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { if fieldType.Kind() == reflect.Int64 && (col.FieldName == "Id" || strings.HasSuffix(col.FieldName, ".Id")) { idFieldColName = col.Name } - } + } // end for if idFieldColName != "" && len(table.PrimaryKeys) == 0 { col := table.GetColumn(idFieldColName) @@ -852,6 +903,20 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { 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 } @@ -900,7 +965,7 @@ func (engine *Engine) IsTableExist(bean interface{}) (bool, error) { } func (engine *Engine) IdOf(bean interface{}) core.PK { - table := engine.autoMap(bean) + table := engine.TableInfo(bean) v := reflect.Indirect(reflect.ValueOf(bean)) pk := make([]interface{}, len(table.PrimaryKeys)) for i, col := range table.PKColumns() { @@ -948,7 +1013,7 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id string) error { if t.Kind() != reflect.Struct { return errors.New("error params") } - table := engine.autoMap(bean) + table := engine.TableInfo(bean) cacher := table.Cacher if cacher == nil { cacher = engine.Cacher @@ -967,7 +1032,7 @@ func (engine *Engine) ClearCache(beans ...interface{}) error { if t.Kind() != reflect.Struct { return errors.New("error params") } - table := engine.autoMap(bean) + table := engine.TableInfo(bean) cacher := table.Cacher if cacher == nil { cacher = engine.Cacher @@ -985,7 +1050,7 @@ func (engine *Engine) ClearCache(beans ...interface{}) error { // If you change some field, you should change the database manually. func (engine *Engine) Sync(beans ...interface{}) error { for _, bean := range beans { - table := engine.autoMap(bean) + table := engine.TableInfo(bean) s := engine.NewSession() defer s.Close() @@ -1084,7 +1149,7 @@ func (engine *Engine) Sync2(beans ...interface{}) error { structTables := make([]*core.Table, 0) for _, bean := range beans { - table := engine.autoMap(bean) + table := engine.TableInfo(bean) structTables = append(structTables, table) var oriTable *core.Table @@ -1126,16 +1191,19 @@ func (engine *Engine) Sync2(beans ...interface{}) error { curType := engine.dialect.SqlType(oriCol) if expectedType != curType { if expectedType == core.Text && - curType == core.Varchar { + strings.HasPrefix(curType, core.Varchar) { // currently only support mysql - if engine.dialect.DBType() == core.MYSQL { + 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", + 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", + engine.LogWarnf("Table %s column %s db type is %s, struct type is %s", table.Name, col.Name, curType, expectedType) } } diff --git a/mssql_dialect.go b/mssql_dialect.go index eee50795..49e4c0ab 100644 --- a/mssql_dialect.go +++ b/mssql_dialect.go @@ -13,6 +13,196 @@ import ( // 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 } @@ -74,6 +264,15 @@ 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 "\"" } diff --git a/mysql_dialect.go b/mysql_dialect.go index 40d699ce..d39c4154 100644 --- a/mysql_dialect.go +++ b/mysql_dialect.go @@ -15,6 +15,151 @@ import ( // 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 @@ -95,6 +240,15 @@ 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 "`" } diff --git a/oracle_dialect.go b/oracle_dialect.go index 57da2c50..fc603686 100644 --- a/oracle_dialect.go +++ b/oracle_dialect.go @@ -13,6 +13,490 @@ import ( // 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 } @@ -56,6 +540,15 @@ 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 "\"" } diff --git a/postgres_dialect.go b/postgres_dialect.go index fcdd1fd1..4f2d193a 100644 --- a/postgres_dialect.go +++ b/postgres_dialect.go @@ -12,6 +12,325 @@ import ( // func init() { // RegisterDialect("postgres", &postgres{}) // } +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, + } +) type postgres struct { core.Base @@ -73,6 +392,15 @@ 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 "\"" } diff --git a/rows.go b/rows.go index 99f724dd..c566b125 100644 --- a/rows.go +++ b/rows.go @@ -34,7 +34,7 @@ func newRows(session *Session, bean interface{}) (*Rows, error) { var sqlStr string var args []interface{} - rows.session.Statement.RefTable = rows.session.Engine.autoMap(bean) + rows.session.Statement.RefTable = rows.session.Engine.TableInfo(bean) if rows.session.Statement.RawSQL == "" { sqlStr, args = rows.session.Statement.genGetSql(bean) } else { diff --git a/session.go b/session.go index 63bbc103..d3fc859f 100644 --- a/session.go +++ b/session.go @@ -447,10 +447,12 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er session.Engine.logSQL(sqlStr, args...) - if session.IsAutoCommit { - return session.innerExec(sqlStr, args...) - } - return session.Tx.Exec(sqlStr, args...) + return session.Engine.LogSQLExecutionTime(sqlStr, args, func() (sql.Result, error) { + if session.IsAutoCommit { + return session.innerExec(sqlStr, args...) + } + return session.Tx.Exec(sqlStr, args...) + }) } // Exec raw sql @@ -469,7 +471,7 @@ func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, er // this function create a table according a bean func (session *Session) CreateTable(bean interface{}) error { - session.Statement.RefTable = session.Engine.autoMap(bean) + session.Statement.RefTable = session.Engine.TableInfo(bean) err := session.newDb() if err != nil { @@ -485,7 +487,7 @@ func (session *Session) CreateTable(bean interface{}) error { // create indexes func (session *Session) CreateIndexes(bean interface{}) error { - session.Statement.RefTable = session.Engine.autoMap(bean) + session.Statement.RefTable = session.Engine.TableInfo(bean) err := session.newDb() if err != nil { @@ -508,7 +510,7 @@ func (session *Session) CreateIndexes(bean interface{}) error { // create uniques func (session *Session) CreateUniques(bean interface{}) error { - session.Statement.RefTable = session.Engine.autoMap(bean) + session.Statement.RefTable = session.Engine.TableInfo(bean) err := session.newDb() if err != nil { @@ -595,7 +597,7 @@ func (session *Session) DropTable(bean interface{}) error { if t.Kind() == reflect.String { session.Statement.AltTableName = bean.(string) } else if t.Kind() == reflect.Struct { - session.Statement.RefTable = session.Engine.autoMap(bean) + session.Statement.RefTable = session.Engine.TableInfo(bean) } else { return errors.New("Unsupported type") } @@ -952,7 +954,7 @@ func (session *Session) Get(bean interface{}) (bool, error) { var args []interface{} if session.Statement.RefTable == nil { - session.Statement.RefTable = session.Engine.autoMap(bean) + session.Statement.RefTable = session.Engine.TableInfo(bean) } if session.Statement.RawSQL == "" { @@ -1814,15 +1816,16 @@ func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) } func (session *Session) query(sqlStr string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { + session.queryPreprocess(&sqlStr, paramStr...) if session.IsAutoCommit { - return query(session.Db, sqlStr, paramStr...) + return session.innerQuery(session.Db, sqlStr, paramStr...) } - return txQuery(session.Tx, sqlStr, paramStr...) + return session.txQuery(session.Tx, sqlStr, paramStr...) } -func txQuery(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) { +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 @@ -1832,17 +1835,26 @@ func txQuery(tx *core.Tx, sqlStr string, params ...interface{}) (resultsSlice [] return rows2maps(rows) } -func query(db *core.DB, sqlStr string, params ...interface{}) (resultsSlice []map[string][]byte, err error) { - s, err := db.Prepare(sqlStr) +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 } - defer s.Close() - rows, err := s.Query(params...) - if err != nil { - return nil, err - } - defer rows.Close() return rows2maps(rows) } @@ -2064,6 +2076,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error strings.Join(colMultiPlaces, "),(")) res, err := session.exec(statement, args...) + if err != nil { return 0, err } @@ -2720,7 +2733,7 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val } func (session *Session) innerInsert(bean interface{}) (int64, error) { - table := session.Engine.autoMap(bean) + table := session.Engine.TableInfo(bean) session.Statement.RefTable = table // handle BeforeInsertProcessor @@ -3117,7 +3130,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 // -- if t.Kind() == reflect.Struct { - table = session.Engine.autoMap(bean) + table = session.Engine.TableInfo(bean) session.Statement.RefTable = table if session.Statement.ColumnStr == "" { @@ -3371,7 +3384,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) { } // -- - table := session.Engine.autoMap(bean) + 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, diff --git a/sqlite3_dialect.go b/sqlite3_dialect.go index e8d6cf2c..0b9c4298 100644 --- a/sqlite3_dialect.go +++ b/sqlite3_dialect.go @@ -12,6 +12,135 @@ import ( // 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 } @@ -54,6 +183,15 @@ 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 "`" } diff --git a/statement.go b/statement.go index e7a253d6..9094492e 100644 --- a/statement.go +++ b/statement.go @@ -151,7 +151,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { /*func (statement *Statement) genFields(bean interface{}) map[string]interface{} { results := make(map[string]interface{}) - table := statement.Engine.autoMap(bean) + table := statement.Engine.TableInfo(bean) for _, col := range table.Columns { fieldValue := col.ValueOf(bean) fieldType := reflect.TypeOf(fieldValue.Interface()) @@ -905,9 +905,11 @@ func (statement *Statement) Asc(colNames ...string) *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, tablename, condition string) *Statement { if statement.JoinStr != "" { - statement.JoinStr = statement.JoinStr + fmt.Sprintf(" %v JOIN %v ON %v", join_operator, tablename, condition) + statement.JoinStr = statement.JoinStr + fmt.Sprintf(" %v JOIN %v ON %v", join_operator, + statement.Engine.Quote(tablename), condition) } else { - statement.JoinStr = fmt.Sprintf("%v JOIN %v ON %v", join_operator, tablename, condition) + statement.JoinStr = fmt.Sprintf("%v JOIN %v ON %v", join_operator, + statement.Engine.Quote(tablename), condition) } return statement } @@ -1020,7 +1022,7 @@ func (s *Statement) genDropSQL() string { func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) { var table *core.Table if statement.RefTable == nil { - table = statement.Engine.autoMap(bean) + table = statement.Engine.TableInfo(bean) statement.RefTable = table } else { table = statement.RefTable @@ -1070,7 +1072,7 @@ func (s *Statement) genAddUniqueStr(uqeName string, cols []string) (string, []in }*/ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}) { - table := statement.Engine.autoMap(bean) + table := statement.Engine.TableInfo(bean) statement.RefTable = table colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,