2019-02-02 16:18:25 +08:00
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
2018-10-26 22:08:52 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
2019-02-02 16:18:25 +08:00
// You can obtain one at https://github.com/gogf/gf.
2018-10-26 22:08:52 +08:00
/ *
@ author wenzi1 < liyz23 @ qq . com >
@ date 20181026
说明 :
1. 需要导入oracle驱动 : github . com / mattn / go - oci8
2. 不支持save / replace方法 , 可以调用这2个方法估计会报错 , 还没测试过 , ( 应该是可以通过oracle的merge来实现这2个功能的 , 还没仔细研究 )
3. 不支持LastInsertId方法
* /
2019-03-05 17:52:34 +08:00
2018-10-26 22:08:52 +08:00
package gdb
import (
"database/sql"
"fmt"
2019-02-02 16:18:25 +08:00
"github.com/gogf/gf/g/text/gregex"
2018-10-26 22:08:52 +08:00
"strconv"
"strings"
)
// 数据库链接对象
2018-12-14 18:35:51 +08:00
type dbOracle struct {
* dbBase
2018-10-26 22:08:52 +08:00
}
// 创建SQL操作对象
2018-12-15 15:50:39 +08:00
func ( db * dbOracle ) Open ( config * ConfigNode ) ( * sql . DB , error ) {
2018-10-26 22:08:52 +08:00
var source string
2019-04-02 14:37:46 +08:00
if config . LinkInfo != "" {
source = config . LinkInfo
2018-10-26 22:08:52 +08:00
} else {
2018-12-15 15:50:39 +08:00
source = fmt . Sprintf ( "%s/%s@%s" , config . User , config . Pass , config . Name )
2018-10-26 22:08:52 +08:00
}
if db , err := sql . Open ( "oci8" , source ) ; err == nil {
return db , nil
} else {
return nil , err
}
}
2018-12-14 18:35:51 +08:00
// 获得关键字操作符
2019-01-02 18:17:01 +08:00
func ( db * dbOracle ) getChars ( ) ( charLeft string , charRight string ) {
2018-12-14 18:35:51 +08:00
return "\"" , "\""
2018-10-26 22:08:52 +08:00
}
// 在执行sql之前对sql进行进一步处理
2018-12-14 18:35:51 +08:00
func ( db * dbOracle ) handleSqlBeforeExec ( query string ) string {
2018-10-26 22:08:52 +08:00
index := 0
2018-12-14 18:35:51 +08:00
str , _ := gregex . ReplaceStringFunc ( "\\?" , query , func ( s string ) string {
2018-10-26 22:08:52 +08:00
index ++
return fmt . Sprintf ( ":%d" , index )
} )
str , _ = gregex . ReplaceString ( "\"" , "" , str )
2018-12-14 18:35:51 +08:00
return db . parseSql ( str )
2018-10-26 22:08:52 +08:00
}
//由于ORACLE中对LIMIT和批量插入的语法与MYSQL不一致, 所以这里需要对LIMIT和批量插入做语法上的转换
2018-12-14 18:35:51 +08:00
func ( db * dbOracle ) parseSql ( sql string ) string {
2018-10-26 22:08:52 +08:00
//下面的正则表达式匹配出SELECT和INSERT的关键字后分别做不同的处理, 如有LIMIT则将LIMIT的关键字也匹配出
patten := ` ^\s*(?i)(SELECT)|(INSERT)|(LIMIT\s*(\d+)\s*,\s*(\d+)) `
2018-12-14 18:35:51 +08:00
if gregex . IsMatchString ( patten , sql ) == false {
2019-05-29 11:53:10 +08:00
//fmt.Println("not matched..")
2018-10-26 22:08:52 +08:00
return sql
}
2018-12-14 18:35:51 +08:00
res , err := gregex . MatchAllString ( patten , sql )
2018-10-26 22:08:52 +08:00
if err != nil {
2019-05-29 11:53:10 +08:00
//fmt.Println("MatchString error.", err)
2018-12-14 18:35:51 +08:00
return ""
2018-10-26 22:08:52 +08:00
}
2019-06-19 09:06:52 +08:00
index := 0
2018-10-26 22:08:52 +08:00
keyword := strings . TrimSpace ( res [ index ] [ 0 ] )
2019-06-19 09:06:52 +08:00
keyword = strings . ToUpper ( keyword )
2018-10-26 22:08:52 +08:00
index ++
switch keyword {
2019-06-19 09:06:52 +08:00
case "SELECT" :
//不含LIMIT关键字则不处理
if len ( res ) < 2 || ( strings . HasPrefix ( res [ index ] [ 0 ] , "LIMIT" ) == false && strings . HasPrefix ( res [ index ] [ 0 ] , "limit" ) == false ) {
break
}
//取limit前面的字符串
if gregex . IsMatchString ( "((?i)SELECT)(.+)((?i)LIMIT)" , sql ) == false {
break
}
queryExpr , _ := gregex . MatchString ( "((?i)SELECT)(.+)((?i)LIMIT)" , sql )
if len ( queryExpr ) != 4 || strings . EqualFold ( queryExpr [ 1 ] , "SELECT" ) == false || strings . EqualFold ( queryExpr [ 3 ] , "LIMIT" ) == false {
break
}
//取limit后面的取值范围
first , limit := 0 , 0
for i := 1 ; i < len ( res [ index ] ) ; i ++ {
if len ( strings . TrimSpace ( res [ index ] [ i ] ) ) == 0 {
continue
2018-10-26 22:08:52 +08:00
}
2019-06-19 09:06:52 +08:00
if strings . HasPrefix ( res [ index ] [ i ] , "LIMIT" ) || strings . HasPrefix ( res [ index ] [ i ] , "limit" ) {
first , _ = strconv . Atoi ( res [ index ] [ i + 1 ] )
limit , _ = strconv . Atoi ( res [ index ] [ i + 2 ] )
2018-10-26 22:08:52 +08:00
break
}
2019-06-19 09:06:52 +08:00
}
//也可以使用between,据说这种写法的性能会比between好点,里层SQL中的ROWNUM_ >= limit可以缩小查询后的数据集规模
sql = fmt . Sprintf ( "SELECT * FROM (SELECT GFORM.*, ROWNUM ROWNUM_ FROM (%s %s) GFORM WHERE ROWNUM <= %d) WHERE ROWNUM_ >= %d" , queryExpr [ 1 ] , queryExpr [ 2 ] , limit , first )
case "INSERT" :
//获取VALUE的值, 匹配所有带括号的值,会将INSERT INTO后的值匹配到, 所以下面的判断语句会判断数组长度是否小于3
valueExpr , err := gregex . MatchAllString ( ` (\s*\(([^\(\)]*)\)) ` , sql )
if err != nil {
return sql
}
//判断VALUE后的值是否有多个, 只有在批量插入的时候才需要做转换, 如只有1个VALUE则不需要做转换
if len ( valueExpr ) < 3 {
break
}
//获取INTO后面的值
tableExpr , err := gregex . MatchString ( ` (?i)\s*(INTO\s+\w+\(([^\(\)]*)\)) ` , sql )
if err != nil {
return sql
}
tableExpr [ 0 ] = strings . TrimSpace ( tableExpr [ 0 ] )
sql = "INSERT ALL"
for i := 1 ; i < len ( valueExpr ) ; i ++ {
sql += fmt . Sprintf ( " %s VALUES%s" , tableExpr [ 0 ] , strings . TrimSpace ( valueExpr [ i ] [ 0 ] ) )
}
sql += " SELECT 1 FROM DUAL"
default :
2018-10-26 22:08:52 +08:00
}
return sql
}
2019-01-02 18:17:01 +08:00
// 获得指定表表的数据结构, 构造成map哈希表返回, 其中键名为表字段名称, 键值暂无用途(默认为字段数据类型).
func ( db * dbOracle ) getTableFields ( table string ) ( fields map [ string ] string , err error ) {
// 缓存不存在时会查询数据表结构,缓存后不过期,直至程序重启(重新部署)
v := db . cache . GetOrSetFunc ( "table_fields_" + table , func ( ) interface { } {
result := ( Result ) ( nil )
result , err = db . GetAll ( fmt . Sprintf ( `
SELECT COLUMN_NAME AS FIELD , CASE DATA_TYPE
WHEN ' NUMBER ' THEN DATA_TYPE || '(' || DATA_PRECISION || ',' || DATA_SCALE || ')'
WHEN ' FLOAT ' THEN DATA_TYPE || '(' || DATA_PRECISION || ',' || DATA_SCALE || ')'
ELSE DATA_TYPE || '(' || DATA_LENGTH || ')' END AS TYPE
FROM USER_TAB_COLUMNS WHERE TABLE_NAME = ' % s ' ORDER BY COLUMN_ID ` , strings . ToUpper ( table ) ) )
if err != nil {
return nil
}
fields = make ( map [ string ] string )
for _ , m := range result {
fields [ strings . ToLower ( m [ "FIELD" ] . String ( ) ) ] = strings . ToLower ( m [ "TYPE" ] . String ( ) ) //ORACLE返回的值默认都是大写的, 需要转为小写
}
return fields
} , 0 )
if err == nil {
fields = v . ( map [ string ] string )
}
return
}