Ai
1 Star 0 Fork 0

go-genie/sqlx-pg

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
interpolate_params.go 4.04 KB
一键复制 编辑 原始数据 按行查看 历史
文兄 提交于 2025-06-17 16:12 +08:00 . init
package pgutils
import (
"context"
"database/sql/driver"
"fmt"
"strconv"
"strings"
"time"
"gitee.com/go-genie/sqlx/builder"
)
func InterpolateParams(sqlExpr builder.SqlExpr) (string, error) {
return InterpolateParamsContext(context.Background(), sqlExpr)
}
func InterpolateParamsContext(ctx context.Context, sqlExpr builder.SqlExpr) (string, error) {
if builder.IsNilExpr(sqlExpr) {
return "", nil
}
e := sqlExpr.Ex(ctx)
b, err := interpolateParams(e.Query(), e.Args(), time.UTC)
if err != nil {
return "", err
}
return string(b), nil
}
func interpolateParams(query string, args []interface{}, loc *time.Location) ([]byte, error) {
if strings.Count(query, "?") != len(args) {
return nil, driver.ErrSkip
}
buf := make([]byte, 0)
buf = buf[:0]
argPos := 0
for i := 0; i < len(query); i++ {
q := strings.IndexByte(query[i:], '?')
if q == -1 {
buf = append(buf, query[i:]...)
break
}
buf = append(buf, query[i:i+q]...)
i += q
arg, err := driver.DefaultParameterConverter.ConvertValue(args[argPos])
if err != nil {
return nil, err
}
argPos++
if arg == nil {
buf = append(buf, "NULL"...)
continue
}
switch v := arg.(type) {
case int64:
buf = strconv.AppendInt(buf, v, 10)
case float64:
buf = strconv.AppendFloat(buf, v, 'g', -1, 64)
case bool:
if v {
buf = append(buf, '1')
} else {
buf = append(buf, '0')
}
case time.Time:
if v.IsZero() {
buf = append(buf, "'0000-00-00'"...)
} else {
v := v.In(loc)
v = v.Add(time.Nanosecond * 500) // Write round under microsecond
year := v.Year()
year100 := year / 100
year1 := year % 100
month := v.Month()
day := v.Day()
hour := v.Hour()
minute := v.Minute()
second := v.Second()
micro := v.Nanosecond() / 1000
buf = append(buf, []byte{
'\'',
digits10[year100], digits01[year100],
digits10[year1], digits01[year1],
'-',
digits10[month], digits01[month],
'-',
digits10[day], digits01[day],
' ',
digits10[hour], digits01[hour],
':',
digits10[minute], digits01[minute],
':',
digits10[second], digits01[second],
}...)
if micro != 0 {
micro10000 := micro / 10000
micro100 := micro / 100 % 100
micro1 := micro % 100
buf = append(buf, []byte{
'.',
digits10[micro10000], digits01[micro10000],
digits10[micro100], digits01[micro100],
digits10[micro1], digits01[micro1],
}...)
}
buf = append(buf, '\'')
}
case []byte:
if v == nil {
buf = append(buf, "NULL"...)
} else {
buf = append(buf, "E'"...)
buf = escapeBytesBackslash(buf, v)
buf = append(buf, '\'')
}
case string:
buf = append(buf, '\'')
buf = escapeBytesBackslash(buf, []byte(v))
buf = append(buf, '\'')
default:
return nil, fmt.Errorf("unsupported type %T: %v", v, v)
}
}
if argPos != len(args) {
return nil, driver.ErrSkip
}
return buf, nil
}
const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
func escapeBytesBackslash(buf, v []byte) []byte {
pos := len(buf)
buf = reserveBuffer(buf, len(v)*2)
for _, c := range v {
switch c {
case '\x00':
buf[pos] = '\\'
buf[pos+1] = '0'
pos += 2
case '\n':
buf[pos] = '\\'
buf[pos+1] = 'n'
pos += 2
case '\r':
buf[pos] = '\\'
buf[pos+1] = 'r'
pos += 2
case '\x1a':
buf[pos] = '\\'
buf[pos+1] = 'Z'
pos += 2
case '\'':
buf[pos] = '\\'
buf[pos+1] = '\''
pos += 2
case '"':
buf[pos] = '\\'
buf[pos+1] = '"'
pos += 2
case '\\':
buf[pos] = '\\'
buf[pos+1] = '\\'
pos += 2
default:
buf[pos] = c
pos++
}
}
return buf[:pos]
}
func reserveBuffer(buf []byte, appendSize int) []byte {
newSize := len(buf) + appendSize
if cap(buf) < newSize {
// Grow buffer exponentially
newBuf := make([]byte, len(buf)*2+appendSize)
copy(newBuf, buf)
buf = newBuf
}
return buf[:newSize]
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/go-genie/sqlx-pg.git
git@gitee.com:go-genie/sqlx-pg.git
go-genie
sqlx-pg
sqlx-pg
v1.0.9

搜索帮助