xorm/dialects/oracle.go

962 lines
30 KiB
Go
Raw Normal View History

2015-04-28 08:25:04 +00:00
// 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 dialects
2014-01-07 09:19:33 +00:00
import (
"context"
"database/sql"
2017-03-23 06:05:32 +00:00
"errors"
2014-01-07 09:19:33 +00:00
"fmt"
2017-03-23 06:05:32 +00:00
"regexp"
2014-01-07 09:19:33 +00:00
"strconv"
"strings"
"xorm.io/xorm/core"
"xorm.io/xorm/schemas"
2014-01-07 09:33:27 +00:00
)
2014-01-07 09:19:33 +00:00
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,
}
oracleQuoter = schemas.Quoter{
Prefix: '"',
Suffix: '"',
IsReserved: schemas.AlwaysReserve,
}
)
2014-01-07 09:33:27 +00:00
type oracle struct {
Base
useLegacy bool
2014-01-07 09:19:33 +00:00
}
func (db *oracle) Init(uri *URI) error {
db.quoter = oracleQuoter
return db.Base.Init(db, uri)
2014-01-07 09:19:33 +00:00
}
func (db *oracle) UseLegacyLimitOffset() bool { return db.useLegacy }
func (db *oracle) SetParams(params map[string]string) {
useLegacy, ok := params["USE_LEGACY_LIMIT_OFFSET"]
if ok {
if b, _ := strconv.ParseBool(useLegacy); b {
db.useLegacy = true
}
}
}
func (db *oracle) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) {
rows, err := queryer.QueryContext(ctx, "select * from v$version where banner like 'Oracle%'")
if err != nil {
return nil, err
}
defer rows.Close()
var version string
if !rows.Next() {
if rows.Err() != nil {
return nil, rows.Err()
}
return nil, errors.New("unknow version")
}
if err := rows.Scan(&version); err != nil {
return nil, err
}
return &schemas.Version{
Number: version,
}, nil
}
func (db *oracle) Features() *DialectFeatures {
return &DialectFeatures{
AutoincrMode: SequenceAutoincrMode,
}
}
func (db *oracle) SQLType(c *schemas.Column) string {
2014-01-07 09:19:33 +00:00
var res string
switch t := c.SQLType.Name; t {
case schemas.Bool:
if c.Default == "true" {
c.Default = "1"
} else if c.Default == "false" {
c.Default = "0"
}
res = "NUMBER(1,0)"
case schemas.Bit, schemas.TinyInt, schemas.SmallInt, schemas.MediumInt, schemas.Int, schemas.Integer, schemas.BigInt, schemas.Serial, schemas.BigSerial:
2015-03-03 06:58:01 +00:00
res = "NUMBER"
case schemas.Binary, schemas.VarBinary, schemas.Blob, schemas.TinyBlob, schemas.MediumBlob, schemas.LongBlob, schemas.Bytea:
return schemas.Blob
case schemas.Time, schemas.DateTime, schemas.TimeStamp:
res = schemas.TimeStamp
case schemas.TimeStampz:
2014-01-07 09:19:33 +00:00
res = "TIMESTAMP WITH TIME ZONE"
case schemas.Float, schemas.Double, schemas.Numeric, schemas.Decimal:
2014-01-07 09:19:33 +00:00
res = "NUMBER"
case schemas.Text, schemas.MediumText, schemas.LongText, schemas.Json:
2014-01-07 09:19:33 +00:00
res = "CLOB"
case schemas.Char, schemas.Varchar, schemas.TinyText:
2015-03-03 06:58:01 +00:00
res = "VARCHAR2"
2014-01-07 09:19:33 +00:00
default:
res = t
}
2023-10-30 01:23:20 +00:00
hasLen1 := c.Length > 0
hasLen2 := c.Length2 > 0
2014-05-29 08:53:23 +00:00
if hasLen2 {
res += "(" + strconv.FormatInt(c.Length, 10) + "," + strconv.FormatInt(c.Length2, 10) + ")"
2014-05-29 08:53:23 +00:00
} else if hasLen1 {
res += "(" + strconv.FormatInt(c.Length, 10) + ")"
2014-01-07 09:19:33 +00:00
}
return res
}
func (db *oracle) ColumnTypeKind(t string) int {
switch strings.ToUpper(t) {
case "DATE":
return schemas.TIME_TYPE
case "CHAR", "NCHAR", "VARCHAR", "VARCHAR2", "NVARCHAR2", "LONG", "CLOB", "NCLOB":
return schemas.TEXT_TYPE
case "NUMBER":
return schemas.NUMERIC_TYPE
case "BLOB":
return schemas.BLOB_TYPE
default:
return schemas.UNKNOW_TYPE
}
}
2015-03-03 06:58:01 +00:00
func (db *oracle) AutoIncrStr() string {
return "AUTO_INCREMENT"
}
func (db *oracle) IsReserved(name string) bool {
_, ok := oracleReservedWords[strings.ToUpper(name)]
return ok
}
func (db *oracle) DropTableSQL(tableName string) (string, bool) {
return fmt.Sprintf("DROP TABLE \"%s\"", tableName), false
2015-03-13 07:20:24 +00:00
}
func (db *oracle) CreateTableSQL(ctx context.Context, queryer core.Queryer, table *schemas.Table, tableName string) (string, bool, error) {
sql := "CREATE TABLE "
2015-03-03 06:58:01 +00:00
if tableName == "" {
tableName = table.Name
}
Fix join table name quote bug (#1534) Fix test Fix test Add new Quoter object to handle quote Fix join table name quote bug Move reserve words related files into dialects sub package (#1544) Move reserve words related files into dialects sub package Reviewed-on: https://gitea.com/xorm/xorm/pulls/1544 Fix mssql quote (#1535) Fix some quotes Fix mssql quote Merge core package back into the main repository and split into serval sub packages. (#1543) Fix test Improve fmt update go.mod Move core as a sub package Reviewed-on: https://gitea.com/xorm/xorm/pulls/1543 Fix int time deleted bug (#1539) Fix panic Fix test Fix test for mssql time Add sql type check on deleted cond Fix int time deleted bug Reviewed-on: https://gitea.com/xorm/xorm/pulls/1539 Add test for mysql8.0 (#1538) Fix pk order on test Add test for mysql8.0 Reviewed-on: https://gitea.com/xorm/xorm/pulls/1538 Add test for join limit (#1536) Add test for join limit Reviewed-on: https://gitea.com/xorm/xorm/pulls/1536 Improve drone (#1537) Fix drone Improve drone * use traditional positional parameters on inser... Reviewed-on: https://gitea.com/xorm/xorm/pulls/1537 Fix slice of struct not cache bug (#895) Fix failure caused by nil bean Judge both type of struct and pointer in case of out-of-range Fix issue #894 Add test for join subquery (#1528) Fix test Fix subquery with schema Add test for join subquery Add makefile (#1531) Fix drone Fix ci Add deps Improve drone Fix envs Add makefile Reviewed-on: https://gitea.com/xorm/xorm/pulls/1531 Add password for postgres drone image (#1530) Add password for postgres drone image Reviewed-on: https://gitea.com/xorm/xorm/pulls/1530 format time when sqlTypeName is core.Varchar (#1026) fix time test add test for time format sign codes according to contributing rules. format time when sqlTypeName is core.Varchar. Same with core.DateTime or core.TimeStamp Add test for second insert error (#1527) Add test for second insert error Reviewed-on: https://gitea.com/xorm/xorm/pulls/1527 Add tests for table name (#1517) add tests for table name Fix test (#1526) Fix test Reviewed-on: https://gitea.com/xorm/xorm/pulls/1526 Fix test (#1526) Fix test Reviewed-on: https://gitea.com/xorm/xorm/pulls/1526 Fix wrong warning log on autoincrement column when sync table (#1525) improve doc Fix wrong warning log on autoincrement column when sync table Reviewed-on: https://gitea.com/xorm/xorm/pulls/1525 Fixed Join strings on func Exist (#1520) fix test fixed Join strings on func Exist Co-authored-by: Tomofumi Kusana <tkusana@morisawa.co.jp> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1520 For nullable columns, store nil values as NULL (#531) Merge branch 'master' into jcsalem/fix/nil_ptr_is_nullable fix bug when buffersize with iterate (#941) Merge branch 'master' into lunny/fix_buffer_iterate Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 fix test fix bug fix bug when buffersize with iterate SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Co-authored-by: Guillermo Prandi <guillep2k@noreply.gitea.io> Reviewed-on: https://gitea.com/xorm/xorm/pulls/941 fix update map with version (#1448) fix test fix update map with version SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Reviewed-on: https://gitea.com/xorm/xorm/pulls/1448 Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 For nullable columns, store nil values as NULL fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Improve c... Reviewed-on: https://gitea.com/xorm/xorm/pulls/1534
2020-02-25 00:01:36 +00:00
quoter := db.Quoter()
sql += quoter.Quote(tableName) + " ("
2015-03-03 06:58:01 +00:00
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
/*if col.IsPrimaryKey && len(pkList) == 1 {
sql += col.String(b.dialect)
} else {*/
s, _ := ColumnString(db, col, false, false)
sql += s
// }
2015-03-03 06:58:01 +00:00
sql = strings.TrimSpace(sql)
sql += ", "
}
if len(pkList) > 0 {
sql += "PRIMARY KEY ( "
sql += quoter.Join(pkList, ",")
2015-03-03 06:58:01 +00:00
sql += " ), "
}
sql = sql[:len(sql)-2] + ")"
return sql, false, nil
2015-03-03 06:58:01 +00:00
}
func (db *oracle) IsSequenceExist(ctx context.Context, queryer core.Queryer, seqName string) (bool, error) {
return db.HasRecords(queryer, ctx, `SELECT sequence_name FROM user_sequences WHERE sequence_name = :1`, seqName)
}
func (db *oracle) SetQuotePolicy(quotePolicy QuotePolicy) {
switch quotePolicy {
case QuotePolicyNone:
q := oracleQuoter
q.IsReserved = schemas.AlwaysNoReserve
db.quoter = q
case QuotePolicyReserved:
q := oracleQuoter
q.IsReserved = db.IsReserved
db.quoter = q
case QuotePolicyAlways:
fallthrough
default:
db.quoter = oracleQuoter
}
}
func (db *oracle) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
2015-03-12 09:21:02 +00:00
args := []interface{}{tableName, idxName}
2014-01-07 09:19:33 +00:00
return `SELECT INDEX_NAME FROM USER_INDEXES ` +
2015-03-12 09:21:02 +00:00
`WHERE TABLE_NAME = :1 AND INDEX_NAME = :2`, args
2014-01-07 09:19:33 +00:00
}
func (db *oracle) IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error) {
return db.HasRecords(queryer, ctx, `SELECT table_name FROM user_tables WHERE table_name = :1`, tableName)
2015-03-03 06:58:01 +00:00
}
func (db *oracle) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName, colName string) (bool, error) {
2015-05-19 14:39:50 +00:00
args := []interface{}{tableName, colName}
2015-03-12 09:21:02 +00:00
query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
" AND column_name = :2"
return db.HasRecords(queryer, ctx, query, args...)
2014-01-07 09:19:33 +00:00
}
func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
2015-03-12 09:21:02 +00:00
args := []interface{}{tableName}
2014-01-07 09:19:33 +00:00
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 := queryer.QueryContext(ctx, s, args...)
2014-01-07 09:19:33 +00:00
if err != nil {
return nil, nil, err
}
2014-01-07 09:33:27 +00:00
defer rows.Close()
cols := make(map[string]*schemas.Column)
2014-01-07 09:19:33 +00:00
colSeq := make([]string, 0)
2014-01-07 09:33:27 +00:00
for rows.Next() {
col := new(schemas.Column)
2016-06-30 08:35:04 +00:00
col.Indexes = make(map[string]int)
2014-01-07 09:33:27 +00:00
2015-02-28 07:45:24 +00:00
var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string
var dataLen int64
2014-01-07 09:33:27 +00:00
err = rows.Scan(&colName, &colDefault, &dataType, &dataLen, &dataPrecision,
&dataScale, &nullable)
if err != nil {
return nil, nil, err
}
2015-02-28 07:45:24 +00:00
col.Name = strings.Trim(*colName, `" `)
if colDefault != nil {
col.Default = *colDefault
col.DefaultIsEmpty = false
}
2014-01-07 09:33:27 +00:00
2015-02-28 07:45:24 +00:00
if *nullable == "Y" {
2014-01-07 09:33:27 +00:00
col.Nullable = true
} else {
col.Nullable = false
}
2015-02-28 07:45:24 +00:00
var ignore bool
2015-03-12 09:21:02 +00:00
var dt string
var len1, len2 int64
2015-03-12 09:21:02 +00:00
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.ParseInt(lens[0], 10, 64)
len2, _ = strconv.ParseInt(lens[1], 10, 64)
2015-03-12 09:21:02 +00:00
} else {
len1, _ = strconv.ParseInt(lens[0], 10, 64)
2015-03-12 09:21:02 +00:00
}
}
switch dt {
2014-01-07 09:33:27 +00:00
case "VARCHAR2":
col.SQLType = schemas.SQLType{Name: schemas.Varchar, DefaultLength: len1, DefaultLength2: len2}
2015-04-03 14:37:37 +00:00
case "NVARCHAR2":
col.SQLType = schemas.SQLType{Name: schemas.NVarchar, DefaultLength: len1, DefaultLength2: len2}
2014-01-07 09:33:27 +00:00
case "TIMESTAMP WITH TIME ZONE":
col.SQLType = schemas.SQLType{Name: schemas.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
2015-02-28 07:45:24 +00:00
case "NUMBER":
col.SQLType = schemas.SQLType{Name: schemas.Double, DefaultLength: len1, DefaultLength2: len2}
2015-02-28 07:45:24 +00:00
case "LONG", "LONG RAW":
col.SQLType = schemas.SQLType{Name: schemas.Text, DefaultLength: 0, DefaultLength2: 0}
2015-02-28 07:45:24 +00:00
case "RAW":
col.SQLType = schemas.SQLType{Name: schemas.Binary, DefaultLength: 0, DefaultLength2: 0}
2015-02-28 07:45:24 +00:00
case "ROWID":
col.SQLType = schemas.SQLType{Name: schemas.Varchar, DefaultLength: 18, DefaultLength2: 0}
2015-02-28 07:45:24 +00:00
case "AQ$_SUBSCRIBERS":
ignore = true
2014-01-07 09:33:27 +00:00
default:
col.SQLType = schemas.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2}
2014-01-07 09:19:33 +00:00
}
2015-03-12 09:21:02 +00:00
2015-02-28 07:45:24 +00:00
if ignore {
continue
}
if _, ok := schemas.SqlTypes[col.SQLType.Name]; !ok {
return nil, nil, fmt.Errorf("Unknown colType %v %v", *dataType, col.SQLType)
2014-01-07 09:33:27 +00:00
}
col.Length = dataLen
if col.SQLType.IsText() || col.SQLType.IsTime() {
2015-02-28 07:45:24 +00:00
if !col.DefaultIsEmpty {
2014-01-07 09:19:33 +00:00
col.Default = "'" + col.Default + "'"
}
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}
if rows.Err() != nil {
return nil, nil, rows.Err()
}
2014-01-07 09:19:33 +00:00
return colSeq, cols, nil
}
func (db *oracle) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) {
2014-01-07 09:19:33 +00:00
args := []interface{}{}
s := "SELECT table_name FROM user_tables"
2014-04-18 10:39:07 +00:00
rows, err := queryer.QueryContext(ctx, s, args...)
2014-01-07 09:19:33 +00:00
if err != nil {
return nil, err
}
2014-04-18 10:39:07 +00:00
defer rows.Close()
2014-01-07 09:19:33 +00:00
tables := make([]*schemas.Table, 0)
2014-01-07 09:33:27 +00:00
for rows.Next() {
table := schemas.NewEmptyTable()
2014-01-07 09:33:27 +00:00
err = rows.Scan(&table.Name)
if err != nil {
return nil, err
2014-01-07 09:19:33 +00:00
}
2014-01-07 09:33:27 +00:00
2014-01-07 09:19:33 +00:00
tables = append(tables, table)
}
if rows.Err() != nil {
return nil, rows.Err()
}
2014-01-07 09:19:33 +00:00
return tables, nil
}
func (db *oracle) GetIndexes(queryer core.Queryer, ctx context.Context, tableName string) (map[string]*schemas.Index, error) {
2014-01-07 09:19:33 +00:00
args := []interface{}{tableName}
2014-01-07 09:33:27 +00:00
s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
2014-01-07 09:19:33 +00:00
"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
rows, err := queryer.QueryContext(ctx, s, args...)
2014-01-07 09:19:33 +00:00
if err != nil {
return nil, err
}
2014-01-07 09:33:27 +00:00
defer rows.Close()
2014-01-07 09:19:33 +00:00
indexes := make(map[string]*schemas.Index)
2014-01-07 09:33:27 +00:00
for rows.Next() {
2014-01-07 09:19:33 +00:00
var indexType int
2014-01-07 09:33:27 +00:00
var indexName, colName, uniqueness string
err = rows.Scan(&colName, &uniqueness, &indexName)
if err != nil {
return nil, err
}
indexName = strings.Trim(indexName, `" `)
2017-04-05 10:17:41 +00:00
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
indexName = indexName[5+len(tableName):]
isRegular = true
}
2014-01-07 09:33:27 +00:00
if uniqueness == "UNIQUE" {
indexType = schemas.UniqueType
2014-01-07 09:33:27 +00:00
} else {
indexType = schemas.IndexType
2014-01-07 09:19:33 +00:00
}
var index *schemas.Index
2014-01-07 09:19:33 +00:00
var ok bool
if index, ok = indexes[indexName]; !ok {
index = new(schemas.Index)
2014-01-07 09:19:33 +00:00
index.Type = indexType
index.Name = indexName
2017-04-05 10:17:41 +00:00
index.IsRegular = isRegular
2014-01-07 09:19:33 +00:00
indexes[indexName] = index
}
index.AddColumn(colName)
}
if rows.Err() != nil {
return nil, rows.Err()
}
2014-01-07 09:19:33 +00:00
return indexes, nil
}
2014-01-07 09:33:27 +00:00
func (db *oracle) Filters() []Filter {
return []Filter{
&oracleSeqFilter{Prefix: ":", Start: 1},
}
2014-01-07 09:33:27 +00:00
}
2017-03-23 06:05:32 +00:00
type godrorDriver struct {
baseDriver
2017-03-23 06:05:32 +00:00
}
func (g *godrorDriver) Features() *DriverFeatures {
return &DriverFeatures{
SupportReturnInsertedID: false,
}
}
func (g *godrorDriver) Parse(driverName, dataSourceName string) (*URI, error) {
db := &URI{DBType: schemas.ORACLE}
2017-03-23 06:05:32 +00:00
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)
2017-03-23 06:05:32 +00:00
names := dsnPattern.SubexpNames()
for i, match := range matches {
if names[i] == "dbname" {
db.DBName = match
2017-03-23 06:05:32 +00:00
}
}
if db.DBName == "" {
2017-03-23 06:05:32 +00:00
return nil, errors.New("dbname is empty")
}
return db, nil
}
func (g *godrorDriver) GenScanResult(colType string) (interface{}, error) {
switch colType {
case "CHAR", "NCHAR", "VARCHAR", "VARCHAR2", "NVARCHAR2", "LONG", "CLOB", "NCLOB":
var s sql.NullString
return &s, nil
case "NUMBER":
var s sql.NullString
return &s, nil
case "DATE":
var s sql.NullTime
return &s, nil
case "BLOB":
var r sql.RawBytes
return &r, nil
default:
var r sql.RawBytes
return &r, nil
}
}
2017-03-23 06:05:32 +00:00
type oci8Driver struct {
godrorDriver
2017-03-23 06:05:32 +00:00
}
// dataSourceName=user/password@ipv4:port/dbname
// dataSourceName=user/password@[ipv6]:port/dbname
func (o *oci8Driver) Parse(driverName, dataSourceName string) (*URI, error) {
db := &URI{DBType: schemas.ORACLE}
2017-03-23 06:05:32 +00:00
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 {
if names[i] == "dbname" {
db.DBName = match
2017-03-23 06:05:32 +00:00
}
}
if db.DBName == "" && len(matches) != 0 {
2017-03-23 06:05:32 +00:00
return nil, errors.New("dbname is empty")
}
return db, nil
}
type oracleDriver struct {
godrorDriver
}