mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
improve table prefix and quote feature for gdb
This commit is contained in:
@ -97,6 +97,7 @@ type DB interface {
|
||||
getDebug() bool
|
||||
getPrefix() string
|
||||
quoteWord(s string) string
|
||||
quoteString(s string) string
|
||||
doSetSchema(sqlDb *sql.DB, schema string) error
|
||||
filterFields(table string, data map[string]interface{}) map[string]interface{}
|
||||
convertValue(fieldValue []byte, fieldType string) interface{}
|
||||
|
||||
@ -15,8 +15,6 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
@ -29,8 +27,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
wordReg = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`) // Regular expression object for a word.
|
||||
lastOperatorReg = regexp.MustCompile(`[<>=]+\s*$`) // Regular expression object for a string which has operator at its tail.
|
||||
// lastOperatorReg is the regular expression object for a string which has operator at its tail.
|
||||
lastOperatorReg = regexp.MustCompile(`[<>=]+\s*$`)
|
||||
)
|
||||
|
||||
// 打印SQL对象(仅在debug=true时有效)
|
||||
@ -607,14 +605,18 @@ func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// 使用关键字操作符转义给定字符串。
|
||||
// 如果给定的字符串不为单词,那么不转义,直接返回该字符串。
|
||||
// quoteWord checks given string <s> a word, if true quotes it with security chars of the database
|
||||
// and returns the quoted string; or else return <s> without any change.
|
||||
func (bs *dbBase) quoteWord(s string) string {
|
||||
charLeft, charRight := bs.db.getChars()
|
||||
if wordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {
|
||||
return charLeft + s + charRight
|
||||
}
|
||||
return s
|
||||
return doQuoteWord(s, charLeft, charRight)
|
||||
}
|
||||
|
||||
// quoteString quotes string with quote chars. Strings like:
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
|
||||
func (bs *dbBase) quoteString(s string) string {
|
||||
charLeft, charRight := bs.db.getChars()
|
||||
return doQuoteString(s, charLeft, charRight)
|
||||
}
|
||||
|
||||
// 动态切换数据库
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -45,6 +46,55 @@ const (
|
||||
ORM_TAG_FOR_PRIMARY = "primary"
|
||||
)
|
||||
|
||||
var (
|
||||
// quoteWordReg is the regular expression object for a word check.
|
||||
quoteWordReg = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`)
|
||||
)
|
||||
|
||||
// doQuoteWord checks given string <s> a word, if true quotes it with <charLeft> and <charRight>
|
||||
// and returns the quoted string; or else return <s> without any change.
|
||||
func doQuoteWord(s, charLeft, charRight string) string {
|
||||
if quoteWordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {
|
||||
return charLeft + s + charRight
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// doQuoteString quotes string with quote chars. It handles strings like:
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
|
||||
func doQuoteString(s, charLeft, charRight string) string {
|
||||
array1 := gstr.SplitAndTrim(s, ",")
|
||||
for k1, v1 := range array1 {
|
||||
array2 := gstr.SplitAndTrim(v1, " ")
|
||||
array3 := gstr.SplitAndTrim(array2[0], ".")
|
||||
if len(array3) == 1 {
|
||||
array3[0] = doQuoteWord(array3[0], charLeft, charRight)
|
||||
} else if len(array3) == 2 {
|
||||
array3[1] = doQuoteWord(array3[1], charLeft, charRight)
|
||||
}
|
||||
array2[0] = gstr.Join(array3, ".")
|
||||
array1[k1] = gstr.Join(array2, " ")
|
||||
}
|
||||
return gstr.Join(array1, ",")
|
||||
}
|
||||
|
||||
// addTablePrefix adds prefix string to the table. It handles strings like:
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "user as u, user_detail as ut".
|
||||
//
|
||||
// Note that, this should be used before any quoting function calls.
|
||||
func addTablePrefix(table, prefix string) string {
|
||||
if prefix == "" {
|
||||
return table
|
||||
}
|
||||
array1 := gstr.SplitAndTrim(table, ",")
|
||||
for k1, v1 := range array1 {
|
||||
array2 := gstr.SplitAndTrim(v1, " ")
|
||||
array2[0] = prefix + array2[0]
|
||||
array1[k1] = gstr.Join(array2, " ")
|
||||
}
|
||||
return gstr.Join(array1, ",")
|
||||
}
|
||||
|
||||
// 获得struct对象对应的where查询条件
|
||||
func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interface{}) {
|
||||
array := ([]string)(nil)
|
||||
@ -135,7 +185,7 @@ func formatWhere(db DB, where interface{}, args []interface{}, omitEmpty bool) (
|
||||
if gstr.Pos(newWhere, "?") == -1 {
|
||||
if lastOperatorReg.MatchString(newWhere) {
|
||||
newWhere += "?"
|
||||
} else if wordReg.MatchString(newWhere) {
|
||||
} else if quoteWordReg.MatchString(newWhere) {
|
||||
newWhere += "=?"
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/container/gset"
|
||||
@ -69,11 +68,8 @@ const (
|
||||
// The parameter <tables> can be more than one table names, like :
|
||||
// "user", "user u", "user, user_detail", "user u, user_detail ud"
|
||||
func (bs *dbBase) Table(table string) *Model {
|
||||
if !gstr.Contains(table, ",") {
|
||||
array := gstr.SplitAndTrim(table, " ")
|
||||
array[0] = bs.db.quoteWord(bs.db.getPrefix() + array[0])
|
||||
table = gstr.Join(array, " ")
|
||||
}
|
||||
table = addTablePrefix(table, bs.db.getPrefix())
|
||||
table = bs.db.quoteString(table)
|
||||
return &Model{
|
||||
db: bs.db,
|
||||
tablesInit: table,
|
||||
@ -95,11 +91,8 @@ func (bs *dbBase) From(tables string) *Model {
|
||||
// Table acts like dbBase.Table except it operates on transaction.
|
||||
// See dbBase.Table.
|
||||
func (tx *TX) Table(table string) *Model {
|
||||
if !gstr.Contains(table, ",") {
|
||||
array := gstr.SplitAndTrim(table, " ")
|
||||
array[0] = tx.db.quoteWord(tx.db.getPrefix() + array[0])
|
||||
table = gstr.Join(array, " ")
|
||||
}
|
||||
table = addTablePrefix(table, tx.db.getPrefix())
|
||||
table = tx.db.quoteString(table)
|
||||
return &Model{
|
||||
db: tx.db,
|
||||
tx: tx,
|
||||
@ -187,9 +180,8 @@ func (m *Model) getModel() *Model {
|
||||
// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
|
||||
func (m *Model) LeftJoin(table string, on string) *Model {
|
||||
model := m.getModel()
|
||||
array := gstr.SplitAndTrim(table, " ")
|
||||
array[0] = m.db.quoteWord(m.db.getPrefix() + array[0])
|
||||
table = gstr.Join(array, " ")
|
||||
table = addTablePrefix(table, m.db.getPrefix())
|
||||
table = m.db.quoteString(table)
|
||||
model.tables += fmt.Sprintf(" LEFT JOIN %s ON (%s)", table, on)
|
||||
return model
|
||||
}
|
||||
@ -197,9 +189,8 @@ func (m *Model) LeftJoin(table string, on string) *Model {
|
||||
// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
|
||||
func (m *Model) RightJoin(table string, on string) *Model {
|
||||
model := m.getModel()
|
||||
array := gstr.SplitAndTrim(table, " ")
|
||||
array[0] = m.db.quoteWord(m.db.getPrefix() + array[0])
|
||||
table = gstr.Join(array, " ")
|
||||
table = addTablePrefix(table, m.db.getPrefix())
|
||||
table = m.db.quoteString(table)
|
||||
model.tables += fmt.Sprintf(" RIGHT JOIN %s ON (%s)", table, on)
|
||||
return model
|
||||
}
|
||||
@ -207,9 +198,8 @@ func (m *Model) RightJoin(table string, on string) *Model {
|
||||
// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
|
||||
func (m *Model) InnerJoin(table string, on string) *Model {
|
||||
model := m.getModel()
|
||||
array := gstr.SplitAndTrim(table, " ")
|
||||
array[0] = m.db.quoteWord(m.db.getPrefix() + array[0])
|
||||
table = gstr.Join(array, " ")
|
||||
table = addTablePrefix(table, m.db.getPrefix())
|
||||
table = m.db.quoteString(table)
|
||||
model.tables += fmt.Sprintf(" INNER JOIN %s ON (%s)", table, on)
|
||||
return model
|
||||
}
|
||||
@ -323,24 +313,14 @@ func (m *Model) Or(where interface{}, args ...interface{}) *Model {
|
||||
// GroupBy sets the "GROUP BY" statement for the model.
|
||||
func (m *Model) GroupBy(groupBy string) *Model {
|
||||
model := m.getModel()
|
||||
if !gstr.Contains(groupBy, ",") {
|
||||
array := strings.Split(groupBy, " ")
|
||||
array[0] = m.db.quoteWord(array[0])
|
||||
groupBy = strings.Join(array, " ")
|
||||
}
|
||||
model.groupBy = groupBy
|
||||
model.groupBy = m.db.quoteString(groupBy)
|
||||
return model
|
||||
}
|
||||
|
||||
// OrderBy sets the "ORDER BY" statement for the model.
|
||||
func (m *Model) OrderBy(orderBy string) *Model {
|
||||
model := m.getModel()
|
||||
if !gstr.Contains(orderBy, ",") {
|
||||
array := strings.Split(orderBy, " ")
|
||||
array[0] = m.db.quoteWord(array[0])
|
||||
orderBy = strings.Join(array, " ")
|
||||
}
|
||||
model.orderBy = orderBy
|
||||
model.orderBy = m.db.quoteString(orderBy)
|
||||
return model
|
||||
}
|
||||
|
||||
|
||||
77
database/gdb/gdb_unit_z_func_test.go
Normal file
77
database/gdb/gdb_unit_z_func_test.go
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// 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,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Func_doQuoteWord(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
array := map[string]string{
|
||||
"user": "`user`",
|
||||
"user u": "user u",
|
||||
"user_detail": "`user_detail`",
|
||||
"user,user_detail": "user,user_detail",
|
||||
"user u, user_detail ut": "user u, user_detail ut",
|
||||
"u.id asc": "u.id asc",
|
||||
"u.id asc, ut.uid desc": "u.id asc, ut.uid desc",
|
||||
}
|
||||
for k, v := range array {
|
||||
gtest.Assert(doQuoteWord(k, "`", "`"), v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Func_doQuoteString(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
|
||||
array := map[string]string{
|
||||
"user": "`user`",
|
||||
"user u": "`user` u",
|
||||
"user,user_detail": "`user`,`user_detail`",
|
||||
"user u, user_detail ut": "`user` u,`user_detail` ut",
|
||||
"u.id asc": "u.`id` asc",
|
||||
"u.id asc, ut.uid desc": "u.`id` asc,ut.`uid` desc",
|
||||
}
|
||||
for k, v := range array {
|
||||
gtest.Assert(doQuoteString(k, "`", "`"), v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Func_addTablePrefix(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
prefix := ""
|
||||
array := map[string]string{
|
||||
"user": "user",
|
||||
"user u": "user u",
|
||||
"user as u": "user as u",
|
||||
"user,user_detail": "user,user_detail",
|
||||
"user u, user_detail ut": "user u, user_detail ut",
|
||||
"user as u, user_detail as ut": "user as u, user_detail as ut",
|
||||
}
|
||||
for k, v := range array {
|
||||
gtest.Assert(addTablePrefix(k, prefix), v)
|
||||
}
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
prefix := "gf_"
|
||||
array := map[string]string{
|
||||
"user": "gf_user",
|
||||
"user u": "gf_user u",
|
||||
"user as u": "gf_user as u",
|
||||
"user,user_detail": "gf_user,gf_user_detail",
|
||||
"user u, user_detail ut": "gf_user u,gf_user_detail ut",
|
||||
"user as u, user_detail as ut": "gf_user as u,gf_user_detail as ut",
|
||||
}
|
||||
for k, v := range array {
|
||||
gtest.Assert(addTablePrefix(k, prefix), v)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user