1 Star 2 Fork 2

winie/gobatis

forked from wenj91/gobatis 
加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
sql_source.go 4.82 KB
一键复制 编辑 原始数据 按行查看 历史
xiongshibo 提交于 2022-07-09 09:58 +08:00 . 合并原作者代码
package gobatis
import (
"reflect"
"strings"
"unicode"
)
// gobatis的核心, 从配置到sql, 参数映射......
type boundSql struct {
sqlStr string
paramMappings []string
params map[string]interface{}
extParams map[string]interface{}
originalSql string //原始sql
actualParam []interface{} // 变量
}
// func (bs *boundSql) paramArr() (paramArr []interface{}, err error) {
// for i := 0; i < len(bs.paramMappings); i++ {
// paramName := bs.paramMappings[i]
// param, ok := bs.extParams[paramName]
// if !ok {
// err = errors.New("param:" + paramName + " not exists")
// return
// }
// paramArr = append(paramArr, param)
// }
// return
// }
type iSqlSource interface {
getBoundSql(isRaw bool, params map[string]interface{}) *boundSql
}
type dynamicSqlSource struct {
sqlNode iSqlNode
}
func (d *dynamicSqlSource) getBoundSql(isRaw bool, params map[string]interface{}) *boundSql {
ctx := newDynamicContext(params)
d.sqlNode.build(ctx)
sss := staticSqlSource{
sqlStr: ctx.toSql(),
isRaw: isRaw,
}
bs := sss.getBoundSql(isRaw, params)
bs.extParams = ctx.params
return bs
}
type staticSqlSource struct {
sqlStr string //替换后的sql
isRaw bool //是否原始sql
paramMappings []string
originalSql string //原始sql
actualParam []interface{} // 变量
}
func (ss *staticSqlSource) getBoundSql(isRaw bool, params map[string]interface{}) *boundSql {
ss.originalSql = ss.sqlStr
ss.isRaw = isRaw
// ss.dollarTokenHandler(params)
ss.tokenHandler(params)
// ss.colonTokenHandler(params)
return &boundSql{
sqlStr: ss.sqlStr,
paramMappings: ss.paramMappings,
params: params,
originalSql: ss.originalSql,
actualParam: ss.actualParam,
}
}
// 静态token处理, 将#{xx} ${xx} :xx 预处理为数据库预编译语句
func (ss *staticSqlSource) tokenHandler(params map[string]interface{}) {
sqlStr := ss.sqlStr
// if !strings.Contains(sqlStr, "#") || !strings.Contains(sqlStr, "$") || !strings.Contains(sqlStr, ":") {
// return
// }
finalSqlStr := ""
itemStr := ""
start := 0
tokenstart := "" //token开始时间
tokenend := false
for i := 0; i < len(sqlStr); i++ {
if start > 0 {
itemStr += string(sqlStr[i])
}
if i != 0 && i < len(sqlStr) {
if string([]byte{sqlStr[i-1], sqlStr[i]}) == "#{" {
tokenstart = "#{"
start = i
} else if string([]byte{sqlStr[i-1], sqlStr[i]}) == "${" {
tokenstart = "${"
start = i
} else if string([]byte{sqlStr[i-1], sqlStr[i]}) == ":" {
tokenstart = ":"
start = i
}
}
if tokenstart == "#{" || tokenstart == "${" {
tokenend = start != 0 && i < len(sqlStr)-1 && sqlStr[i+1] == '}'
} else if tokenstart == ":" {
tokenend = start != 0 && (i+1 == len(sqlStr) || (i < len(sqlStr)-1 && isSeparatorsChar(sqlStr[i+1])))
}
if start != 0 && tokenend {
finalSqlStr += sqlStr[:start-1]
// sqlStr = sqlStr[i+2:]
if i+1 < len(sqlStr) {
sqlStr = sqlStr[i+2:]
} else {
sqlStr = ""
}
itemStr = strings.Trim(itemStr, " ")
itemStr = strings.TrimSpace(itemStr)
param, ok := params[itemStr]
if !ok {
LOG.Error("param:" + itemStr + " not exists")
continue
}
if tokenstart == "${" {
finalSqlStr += param.(string)
} else {
ss.paramMappings = append(ss.paramMappings, itemStr)
if ss.isRaw {
psql, rparam := SqlInParam(param)
finalSqlStr += psql
ss.actualParam = append(ss.actualParam, rparam...)
} else {
finalSqlStr += " ? "
}
}
i = 0
start = 0
itemStr = ""
tokenstart = ""
tokenend = false
}
}
if start != 0 {
LOG.Warn("token not close")
}
finalSqlStr += sqlStr
finalSqlStr = strings.TrimSpace(finalSqlStr)
ss.sqlStr = finalSqlStr
}
var PARAMETER_SEPARATORS = [19]string{`"`, `\'`, `:`, `&`, `,`, `;`, `(`, `)`, `|`, `=`, `+`, `-`, `*`, `%`, `/`, `\\`, `<`, `>`, `^`}
// If Char Is Whitespace
func isSeparatorsChar(statement byte) bool {
if unicode.IsSpace(rune(statement)) {
return true
}
for _, p := range PARAMETER_SEPARATORS {
if p == string(statement) {
return true
}
}
return false
}
// isEmpty gets whether the specified object is considered empty or not.
func SqlInParam(object interface{}) (string, []interface{}) {
param := make([]interface{}, 0)
var sql string
// get nil case out of the way
if object == nil {
return sql, param
}
listKind := reflect.TypeOf(object).Kind()
listValue := reflect.ValueOf(object)
if listKind == reflect.String || listKind == reflect.Int64 || listKind == reflect.Int || listKind == reflect.Int8 || listKind == reflect.Int16 || listKind == reflect.Int32 {
sql = sql + ` ? `
param = append(param, object)
return sql, param
}
for i := 0; i < listValue.Len(); i++ {
sql = sql + ` ? `
if i+1 <= listValue.Len()-1 {
sql = sql + `,`
}
param = append(param, listValue.Index(i).Interface())
}
return sql, param
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/winie/gobatis.git
git@gitee.com:winie/gobatis.git
winie
gobatis
gobatis
v0.1.25

搜索帮助