diff --git a/g/database/gdb/gdb.go b/g/database/gdb/gdb.go index adb1a6735..f3afee6c9 100644 --- a/g/database/gdb/gdb.go +++ b/g/database/gdb/gdb.go @@ -95,6 +95,7 @@ type DB interface { getCache() *gcache.Cache getChars() (charLeft string, charRight string) getDebug() bool + setSchema(sqlDb *sql.DB, schema string) error filterFields(table string, data map[string]interface{}) map[string]interface{} convertValue(fieldValue interface{}, fieldType string) interface{} getTableFields(table string) (map[string]string, error) @@ -339,10 +340,12 @@ func (bs *dbBase) getSqlDb(master bool) (sqlDb *sql.DB, err error) { sqlDb = v.(*sql.DB) } // 是否开启调试模式 - bs.SetDebug(node.Debug) + bs.db.SetDebug(node.Debug) // 是否手动选择数据库 if v := bs.schema.Val(); v != "" { - sqlDb.Exec("USE " + v) + if e := bs.db.setSchema(sqlDb, v); e != nil { + err = e + } } return } diff --git a/g/database/gdb/gdb_base.go b/g/database/gdb/gdb_base.go index 8d1e82db8..0d33a3449 100644 --- a/g/database/gdb/gdb_base.go +++ b/g/database/gdb/gdb_base.go @@ -615,3 +615,9 @@ func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) { } return records, nil } + +// 动态切换数据库 +func (bs *dbBase) setSchema(sqlDb *sql.DB, schema string) error { + _, err := sqlDb.Exec("USE " + schema) + return err +} diff --git a/g/database/gdb/gdb_model.go b/g/database/gdb/gdb_model.go index ef61c8041..f2ab4d437 100644 --- a/g/database/gdb/gdb_model.go +++ b/g/database/gdb/gdb_model.go @@ -30,6 +30,7 @@ type Model struct { orderBy string // 排序语句 start int // 分页开始 limit int // 分页条数 + offset int // 查询偏移量(OFFSET语法) data interface{} // 操作数据(注意仅支持Map/List/string类型) batch int // 批量操作条数 filter bool // 是否按照表字段过滤data参数 @@ -47,6 +48,7 @@ func (bs *dbBase) Table(tables string) *Model { tables: tables, fields: "*", start: -1, + offset: -1, safe: false, } } @@ -214,6 +216,14 @@ func (md *Model) Limit(limit ...int) *Model { return model } +// 链式操作,OFFSET语法(部分数据库支持)。 +// 注意:可以使用Limit方法调用替换该方法特性,底层不同数据库将会自动替换LIMIT语法为OFFSET语法。 +func (md *Model) Offset(offset int) *Model { + model := md.getModel() + model.offset = offset + return model +} + // 链式操作,翻页,注意分页页码从1开始,而Limit方法从0开始。 func (md *Model) ForPage(page, limit int) *Model { model := md.getModel() @@ -605,11 +615,13 @@ func (md *Model) getConditionSql() string { } if md.limit != 0 { if md.start >= 0 { - s += fmt.Sprintf(" LIMIT %d, %d", md.start, md.limit) + s += fmt.Sprintf(" LIMIT %d,%d", md.start, md.limit) } else { s += fmt.Sprintf(" LIMIT %d", md.limit) } - + } + if md.offset >= 0 { + s += fmt.Sprintf(" OFFSET %d", md.offset) } return s } diff --git a/g/database/gdb/gdb_pgsql.go b/g/database/gdb/gdb_pgsql.go index 60d921b1a..44a1c72e2 100644 --- a/g/database/gdb/gdb_pgsql.go +++ b/g/database/gdb/gdb_pgsql.go @@ -9,12 +9,16 @@ package gdb import ( "database/sql" "fmt" - "regexp" + + "github.com/gogf/gf/g/text/gregex" ) // PostgreSQL的适配. +// // 使用时需要import: +// // _ "github.com/gogf/gf/third/github.com/lib/pq" +// // @todo 需要完善replace和save的操作覆盖 // 数据库链接对象 @@ -37,6 +41,12 @@ func (db *dbPgsql) Open(config *ConfigNode) (*sql.DB, error) { } } +// 动态切换数据库 +func (db *dbPgsql) setSchema(sqlDb *sql.DB, schema string) error { + _, err := sqlDb.Exec("SET search_path TO " + schema) + return err +} + // 获得关键字操作符 func (db *dbPgsql) getChars() (charLeft string, charRight string) { return "\"", "\"" @@ -44,11 +54,12 @@ func (db *dbPgsql) getChars() (charLeft string, charRight string) { // 在执行sql之前对sql进行进一步处理 func (db *dbPgsql) handleSqlBeforeExec(query string) string { - reg := regexp.MustCompile("\\?") index := 0 - str := reg.ReplaceAllStringFunc(query, func(s string) string { + query, _ = gregex.ReplaceStringFunc("\\?", query, func(s string) string { index++ return fmt.Sprintf("$%d", index) }) - return str + // 分页语法替换 + query, _ = gregex.ReplaceString(` LIMIT (\d+),\s*(\d+)`, ` LIMIT $1 OFFSET $2`, query) + return query } diff --git a/g/database/gdb/gdb_sqlite.go b/g/database/gdb/gdb_sqlite.go index f368cd548..708243231 100644 --- a/g/database/gdb/gdb_sqlite.go +++ b/g/database/gdb/gdb_sqlite.go @@ -41,7 +41,7 @@ func (db *dbSqlite) getChars() (charLeft string, charRight string) { return "`", "`" } -// 在执行sql之前对sql进行进一步处理 +// 在执行sql之前对sql进行进一步处理。 // @todo 需要增加对Save方法的支持,可使用正则来实现替换, // @todo 将ON DUPLICATE KEY UPDATE触发器修改为两条SQL语句(INSERT OR IGNORE & UPDATE) func (db *dbSqlite) handleSqlBeforeExec(query string) string { diff --git a/geg/other/test.go b/geg/other/test.go index 381a581b9..5bd1eae9c 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -1,19 +1,13 @@ package main import ( - "encoding/base64" "fmt" - "github.com/gogf/gf/g/encoding/gbase64" + + "github.com/gogf/gf/g/text/gregex" ) func main() { - data := "HwHsGhXMaGc===" - datab, err := gbase64.Decode([]byte(data)) - fmt.Println(err) - fmt.Println(datab) - fmt.Println(string(datab)) - - s, e := base64.StdEncoding.DecodeString(data) - fmt.Println(e) - fmt.Println(string(s)) + query := "SELECT * FROM user where status=1 LIMIT 10, 100" + query, _ = gregex.ReplaceString(` LIMIT (\d+),\s*(\d+)`, ` LIMIT $1 OFFSET $2`, query) + fmt.Println(query) }