Skip to content

Commit 27444cb

Browse files
committed
refactor(gdb): use driver dispatch for bool literal and shared-lock clause
Replace two anti-patterns from earlier commits in this PR with the canonical driver-dispatch pattern already used by OrderRandomFunction: - gdb_model_soft_time.go: delete boolFalseLiteral() method that branched on driver name via switch m.db.GetConfig().Type. Call m.db.GetBoolLiteral(false) directly at the two WHERE-builder sites. - pgsql/gaussdb DoFilter: delete the gstr.Replace that rewrote "LOCK IN SHARE MODE" to "FOR SHARE" on every query. Instead, make Model.LockShared() call m.db.GetLockSharedClause() so each driver emits its own dialect directly — no string munging, no risk of corrupting SQL string literals that happen to contain the phrase. New DB interface methods: - GetBoolLiteral(v bool) string - GetLockSharedClause() string Core provides MySQL-legacy defaults ("0"/"1" and "LOCK IN SHARE MODE"), so mysql/mariadb/mssql/oracle/dm/sqlite/oceanbase/tidb inherit without change. pgsql/gaussdb/clickhouse override bool literal to "true"/"false"; pgsql/gaussdb override lock clause to "FOR SHARE". No behavior change vs. the prior commits — all 560 pgsql tests still pass.
1 parent c1d0c89 commit 27444cb

9 files changed

Lines changed: 105 additions & 27 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2+
//
3+
// This Source Code Form is subject to the terms of the MIT License.
4+
// If a copy of the MIT was not distributed with this file,
5+
// You can obtain one at https://github.com/gogf/gf.
6+
7+
package clickhouse
8+
9+
// GetBoolLiteral returns the SQL literal for the given boolean value.
10+
// ClickHouse has a strict Bool type that requires 'true'/'false' literals.
11+
// GetLockSharedClause is not overridden because ClickHouse does not support
12+
// row-level locking — queries with lock clauses would fail at the server
13+
// regardless of which syntax is emitted.
14+
func (d *Driver) GetBoolLiteral(v bool) string {
15+
if v {
16+
return "true"
17+
}
18+
return "false"
19+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2+
//
3+
// This Source Code Form is subject to the terms of the MIT License.
4+
// If a copy of the MIT was not distributed with this file,
5+
// You can obtain one at https://github.com/gogf/gf.
6+
7+
package gaussdb
8+
9+
import (
10+
"github.com/gogf/gf/v2/database/gdb"
11+
)
12+
13+
// GetBoolLiteral returns the SQL literal for the given boolean value.
14+
// GaussDB is PostgreSQL-compatible and uses strict boolean literals.
15+
func (d *Driver) GetBoolLiteral(v bool) string {
16+
if v {
17+
return "true"
18+
}
19+
return "false"
20+
}
21+
22+
// GetLockSharedClause returns the SQL clause for shared row locks.
23+
// GaussDB uses "FOR SHARE" instead of MySQL's legacy "LOCK IN SHARE MODE".
24+
func (d *Driver) GetLockSharedClause() string {
25+
return gdb.LockForShare
26+
}

contrib/drivers/gaussdb/gaussdb_do_filter.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@ func (d *Driver) DoFilter(
5656
newSql = "INSERT" + newSql[len(gdb.InsertOperationIgnore):]
5757
}
5858

59-
// Translate MySQL shared lock syntax to GaussDB (PostgreSQL-compatible) syntax.
60-
// LockShared() generates "LOCK IN SHARE MODE" which is MySQL-only;
61-
// GaussDB uses "FOR SHARE" for the same semantics.
62-
newSql = gstr.Replace(newSql, "LOCK IN SHARE MODE", "FOR SHARE")
63-
6459
newArgs = args
6560

6661
return d.Core.DoFilter(ctx, link, newSql, newArgs)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2+
//
3+
// This Source Code Form is subject to the terms of the MIT License.
4+
// If a copy of the MIT was not distributed with this file,
5+
// You can obtain one at https://github.com/gogf/gf.
6+
7+
package pgsql
8+
9+
import (
10+
"github.com/gogf/gf/v2/database/gdb"
11+
)
12+
13+
// GetBoolLiteral returns the SQL literal for the given boolean value.
14+
// PostgreSQL uses a strict boolean type that requires 'true'/'false' literals,
15+
// not MySQL's numeric 1/0.
16+
func (d *Driver) GetBoolLiteral(v bool) string {
17+
if v {
18+
return "true"
19+
}
20+
return "false"
21+
}
22+
23+
// GetLockSharedClause returns the SQL clause for shared row locks.
24+
// PostgreSQL uses "FOR SHARE" instead of MySQL's legacy "LOCK IN SHARE MODE".
25+
func (d *Driver) GetLockSharedClause() string {
26+
return gdb.LockForShare
27+
}

contrib/drivers/pgsql/pgsql_do_filter.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ func (d *Driver) DoFilter(
5252
newSql = "INSERT" + newSql[len(gdb.InsertOperationIgnore):] + " ON CONFLICT DO NOTHING"
5353
}
5454

55-
// Translate MySQL shared lock syntax to PostgreSQL syntax.
56-
// LockShared() generates "LOCK IN SHARE MODE" which is MySQL-only;
57-
// PostgreSQL uses "FOR SHARE" for the same semantics.
58-
newSql = gstr.Replace(newSql, "LOCK IN SHARE MODE", "FOR SHARE")
59-
6055
newArgs = args
6156

6257
return d.Core.DoFilter(ctx, link, newSql, newArgs)

database/gdb/gdb.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,17 @@ type DB interface {
345345
// OrderRandomFunction returns the SQL function for random ordering.
346346
// The implementation is database-specific (e.g., RAND() for MySQL).
347347
OrderRandomFunction() string
348+
349+
// GetBoolLiteral returns the SQL literal for the given boolean value.
350+
// Drivers with strict boolean types (e.g. pgsql, gaussdb, clickhouse)
351+
// return "true"/"false"; others return "1"/"0" for bit/int-based
352+
// boolean columns.
353+
GetBoolLiteral(v bool) string
354+
355+
// GetLockSharedClause returns the SQL clause emitted by Model.LockShared().
356+
// Drivers that don't support MySQL's legacy "LOCK IN SHARE MODE" override
357+
// to return their dialect equivalent (e.g. "FOR SHARE" on PostgreSQL).
358+
GetLockSharedClause() string
348359
}
349360

350361
// TX defines the interfaces for ORM transaction operations.

database/gdb/gdb_core_underlying.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,22 @@ func (c *Core) OrderRandomFunction() string {
514514
return "RAND()"
515515
}
516516

517+
// GetBoolLiteral returns the SQL literal for the given boolean value.
518+
// Default is "1"/"0" (MySQL bit/int convention); strict-bool drivers override.
519+
func (c *Core) GetBoolLiteral(v bool) string {
520+
if v {
521+
return "1"
522+
}
523+
return "0"
524+
}
525+
526+
// GetLockSharedClause returns the SQL clause for Model.LockShared().
527+
// Default is MySQL's legacy "LOCK IN SHARE MODE"; drivers with other
528+
// dialect syntax (e.g. PostgreSQL's "FOR SHARE") override.
529+
func (c *Core) GetLockSharedClause() string {
530+
return LockInShareMode
531+
}
532+
517533
func (c *Core) columnValueToLocalValue(ctx context.Context, value any, columnType *sql.ColumnType) (any, error) {
518534
var scanType = columnType.ScanType()
519535
if scanType != nil {

database/gdb/gdb_model_lock.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,11 @@ func (m *Model) LockUpdateSkipLocked() *Model {
120120
}
121121

122122
// LockShared sets the lock in share mode for current operation.
123-
// This is equivalent to Lock("LOCK IN SHARE MODE") for MySQL or Lock("FOR SHARE") for PostgreSQL.
124-
// Note: For maximum compatibility, this uses MySQL's legacy syntax.
123+
// The actual clause is dialect-specific and supplied by the driver via
124+
// GetLockSharedClause() — MySQL emits "LOCK IN SHARE MODE", PostgreSQL/GaussDB
125+
// emit "FOR SHARE", etc.
125126
func (m *Model) LockShared() *Model {
126127
model := m.getModel()
127-
model.lockInfo = LockInShareMode
128+
model.lockInfo = m.db.GetLockSharedClause()
128129
return model
129130
}

database/gdb/gdb_model_soft_time.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ func (m *softTimeMaintainer) buildDeleteCondition(
302302
case LocalTypeInt, LocalTypeUint, LocalTypeInt64, LocalTypeUint64:
303303
return fmt.Sprintf(`%s=0`, quotedName)
304304
case LocalTypeBool:
305-
return fmt.Sprintf(`%s=%s`, quotedName, m.boolFalseLiteral())
305+
return fmt.Sprintf(`%s=%s`, quotedName, m.db.GetBoolLiteral(false))
306306
default:
307307
intlog.Errorf(ctx, `invalid field type "%s" for soft delete condition: prefix=%s, field=%s`, fieldType, prefix, fieldName)
308308
return ""
@@ -313,24 +313,12 @@ func (m *softTimeMaintainer) buildDeleteCondition(
313313

314314
default:
315315
if fieldType == LocalTypeBool {
316-
return fmt.Sprintf(`%s=%s`, quotedName, m.boolFalseLiteral())
316+
return fmt.Sprintf(`%s=%s`, quotedName, m.db.GetBoolLiteral(false))
317317
}
318318
return fmt.Sprintf(`%s=0`, quotedName)
319319
}
320320
}
321321

322-
// boolFalseLiteral returns the SQL literal for boolean false appropriate for the current driver.
323-
// Drivers with strict boolean types (pgsql, gaussdb, clickhouse) require 'false',
324-
// while others (mysql, mssql, oracle, dm, etc.) use '0' for bit/int-based boolean columns.
325-
func (m *softTimeMaintainer) boolFalseLiteral() string {
326-
switch m.db.GetConfig().Type {
327-
case "pgsql", "gaussdb", "clickhouse":
328-
return "false"
329-
default:
330-
return "0"
331-
}
332-
}
333-
334322
// GetFieldValue generates value for create/update/delete operations.
335323
func (m *softTimeMaintainer) GetFieldValue(
336324
ctx context.Context, fieldType LocalType, isDeleted bool,

0 commit comments

Comments
 (0)