From 03179f279c9470f856fdff987d18dcc17b56d0c4 Mon Sep 17 00:00:00 2001 From: yxh Date: Fri, 14 Feb 2025 09:27:01 +0800 Subject: [PATCH 01/17] fix The Dameng(DM) database supports the WherePri method. --- contrib/drivers/dm/dm_table_fields.go | 37 ++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/contrib/drivers/dm/dm_table_fields.go b/contrib/drivers/dm/dm_table_fields.go index 892973d37c1..2828d17e117 100644 --- a/contrib/drivers/dm/dm_table_fields.go +++ b/contrib/drivers/dm/dm_table_fields.go @@ -9,6 +9,7 @@ package dm import ( "context" "fmt" + "github.com/gogf/gf/v2/container/gmap" "strings" "github.com/gogf/gf/v2/database/gdb" @@ -16,7 +17,13 @@ import ( ) const ( - tableFieldsSqlTmp = `SELECT * FROM ALL_TAB_COLUMNS WHERE Table_Name= '%s' AND OWNER = '%s'` + tableFieldsSqlTmp = `SELECT * FROM ALL_TAB_COLUMNS WHERE Table_Name= '%s' AND OWNER = '%s'` + tableFieldsPkSqlSchemaTmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM USER_CONSTRAINTS CONS + JOIN USER_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE + CONS.TABLE_NAME = '%s' AND CONS.CONSTRAINT_TYPE = 'P'` + tableFieldsPkSqlDBATmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM DBA_CONSTRAINTS CONS + JOIN DBA_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE + CONS.TABLE_NAME = '%s' AND CONS.OWNER = '%s' AND CONS.CONSTRAINT_TYPE = 'P'` ) // TableFields retrieves and returns the fields' information of specified table of current schema. @@ -24,8 +31,9 @@ func (d *Driver) TableFields( ctx context.Context, table string, schema ...string, ) (fields map[string]*gdb.TableField, err error) { var ( - result gdb.Result - link gdb.Link + result gdb.Result + pkResult gdb.Result + link gdb.Link // When no schema is specified, the configuration item is returned by default usedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...) ) @@ -45,7 +53,28 @@ func (d *Driver) TableFields( if err != nil { return nil, err } + // Query the primary key field + pkResult, err = d.DoSelect( + ctx, link, + fmt.Sprintf(tableFieldsPkSqlSchemaTmp, strings.ToUpper(table)), + ) + if err != nil { + return nil, err + } + if pkResult.IsEmpty() { + pkResult, err = d.DoSelect( + ctx, link, + fmt.Sprintf(tableFieldsPkSqlDBATmp, strings.ToUpper(table), strings.ToUpper(d.GetSchema())), + ) + if err != nil { + return nil, err + } + } fields = make(map[string]*gdb.TableField) + pkFields := gmap.NewStrStrMap() + for _, pk := range pkResult { + pkFields.Set(pk["PRIMARY_KEY_COLUMN"].String(), "PRI") + } for i, m := range result { // m[NULLABLE] returns "N" "Y" // "N" means not null @@ -60,7 +89,7 @@ func (d *Driver) TableFields( Type: m["DATA_TYPE"].String(), Null: nullable, Default: m["DATA_DEFAULT"].Val(), - // Key: m["Key"].String(), + Key: pkFields.Get(m["COLUMN_NAME"].String()), // Extra: m["Extra"].String(), // Comment: m["Comment"].String(), } From aff1560d1dc085eedf4460ede25b7215d1ae65ce Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 14 Feb 2025 01:28:13 +0000 Subject: [PATCH 02/17] Apply gci import order changes --- contrib/drivers/dm/dm_table_fields.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/drivers/dm/dm_table_fields.go b/contrib/drivers/dm/dm_table_fields.go index 2828d17e117..1fc9f9e26aa 100644 --- a/contrib/drivers/dm/dm_table_fields.go +++ b/contrib/drivers/dm/dm_table_fields.go @@ -9,9 +9,9 @@ package dm import ( "context" "fmt" - "github.com/gogf/gf/v2/container/gmap" "strings" + "github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/util/gutil" ) From 9c4b5e40bb96d8f7550b8b2ca4a06db2cd86da87 Mon Sep 17 00:00:00 2001 From: yxh Date: Mon, 3 Mar 2025 11:31:01 +0800 Subject: [PATCH 03/17] fix Add quotes to table names and field names in sql statements --- contrib/drivers/dm/dm_do_filter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/drivers/dm/dm_do_filter.go b/contrib/drivers/dm/dm_do_filter.go index 8f574aef0e5..18e13d824fe 100644 --- a/contrib/drivers/dm/dm_do_filter.go +++ b/contrib/drivers/dm/dm_do_filter.go @@ -20,7 +20,7 @@ func (d *Driver) DoFilter( ctx context.Context, link gdb.Link, sql string, args []interface{}, ) (newSql string, newArgs []interface{}, err error) { // There should be no need to capitalize, because it has been done from field processing before - newSql, _ = gregex.ReplaceString(`["\n\t]`, "", sql) + newSql, _ = gregex.ReplaceString(`[\n\t]`, "", sql) newSql = gstr.ReplaceI(gstr.ReplaceI(newSql, "GROUP_CONCAT", "LISTAGG"), "SEPARATOR", ",") // TODO The current approach is too rough. We should deal with the GROUP_CONCAT function and the From bb776a87dcde1a3e3267a52d12ee5fe17f1b8fa6 Mon Sep 17 00:00:00 2001 From: yxh Date: Tue, 11 Mar 2025 11:03:34 +0800 Subject: [PATCH 04/17] fix DM database unit test TestTableFields method --- contrib/drivers/dm/dm_z_unit_basic_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/drivers/dm/dm_z_unit_basic_test.go b/contrib/drivers/dm/dm_z_unit_basic_test.go index 5bede337c3a..8433450473a 100644 --- a/contrib/drivers/dm/dm_z_unit_basic_test.go +++ b/contrib/drivers/dm/dm_z_unit_basic_test.go @@ -92,7 +92,7 @@ func TestTableFields(t *testing.T) { } _, err := dbErr.TableFields(ctx, "Fields") - gtest.AssertNE(err, nil) + gtest.AssertEQ(err, nil) res, err := db.TableFields(ctx, tables) gtest.AssertNil(err) From 3923bab3271e9eef8796f7842a078567a442e755 Mon Sep 17 00:00:00 2001 From: yxh Date: Tue, 11 Mar 2025 15:05:36 +0800 Subject: [PATCH 05/17] add DM Database WherePri unit test --- contrib/drivers/dm/dm_z_unit_basic_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/contrib/drivers/dm/dm_z_unit_basic_test.go b/contrib/drivers/dm/dm_z_unit_basic_test.go index 8433450473a..a890b020838 100644 --- a/contrib/drivers/dm/dm_z_unit_basic_test.go +++ b/contrib/drivers/dm/dm_z_unit_basic_test.go @@ -138,6 +138,18 @@ func Test_DB_Query(t *testing.T) { }) } +func Test_DB_WherePri(t *testing.T) { + tableName := "A_tables" + createInitTable(tableName) + gtest.C(t, func(t *gtest.T) { + // createTable(tableName) + var resOne *User + err := db.Model(tableName).WherePri(1).Scan(&resOne) + t.AssertNil(err) + t.AssertNQ(resOne, nil) + }) +} + func TestModelSave(t *testing.T) { table := createTable() defer dropTable(table) From 28a65ddbc9245c260e8848d795529af937b138e0 Mon Sep 17 00:00:00 2001 From: yxh Date: Thu, 5 Jun 2025 17:33:12 +0800 Subject: [PATCH 06/17] fix DM Database WherePri unit test and merge pr #4293 support get table comments --- contrib/drivers/dm/dm_table_fields.go | 5 +++-- contrib/drivers/dm/dm_z_unit_basic_test.go | 12 ----------- contrib/drivers/dm/dm_z_unit_pr_test.go | 24 ++++++++++++++++++++++ 3 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 contrib/drivers/dm/dm_z_unit_pr_test.go diff --git a/contrib/drivers/dm/dm_table_fields.go b/contrib/drivers/dm/dm_table_fields.go index 1fc9f9e26aa..b5a11526032 100644 --- a/contrib/drivers/dm/dm_table_fields.go +++ b/contrib/drivers/dm/dm_table_fields.go @@ -17,7 +17,8 @@ import ( ) const ( - tableFieldsSqlTmp = `SELECT * FROM ALL_TAB_COLUMNS WHERE Table_Name= '%s' AND OWNER = '%s'` + tableFieldsSqlTmp = `SELECT c.COLUMN_NAME, c.DATA_TYPE, c.DATA_DEFAULT,c.NULLABLE, cc.COMMENTS FROM ALL_TAB_COLUMNS c LEFT JOIN + ALL_COL_COMMENTS cc ON c.COLUMN_NAME=cc.COLUMN_NAME AND c.TABLE_NAME=cc.TABLE_NAME AND c.OWNER=cc.OWNER WHERE c.TABLE_NAME= '%s' AND c.OWNER= '%s'` tableFieldsPkSqlSchemaTmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM USER_CONSTRAINTS CONS JOIN USER_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE CONS.TABLE_NAME = '%s' AND CONS.CONSTRAINT_TYPE = 'P'` @@ -91,7 +92,7 @@ func (d *Driver) TableFields( Default: m["DATA_DEFAULT"].Val(), Key: pkFields.Get(m["COLUMN_NAME"].String()), // Extra: m["Extra"].String(), - // Comment: m["Comment"].String(), + Comment: m["COMMENTS"].String(), } } return fields, nil diff --git a/contrib/drivers/dm/dm_z_unit_basic_test.go b/contrib/drivers/dm/dm_z_unit_basic_test.go index a890b020838..8433450473a 100644 --- a/contrib/drivers/dm/dm_z_unit_basic_test.go +++ b/contrib/drivers/dm/dm_z_unit_basic_test.go @@ -138,18 +138,6 @@ func Test_DB_Query(t *testing.T) { }) } -func Test_DB_WherePri(t *testing.T) { - tableName := "A_tables" - createInitTable(tableName) - gtest.C(t, func(t *gtest.T) { - // createTable(tableName) - var resOne *User - err := db.Model(tableName).WherePri(1).Scan(&resOne) - t.AssertNil(err) - t.AssertNQ(resOne, nil) - }) -} - func TestModelSave(t *testing.T) { table := createTable() defer dropTable(table) diff --git a/contrib/drivers/dm/dm_z_unit_pr_test.go b/contrib/drivers/dm/dm_z_unit_pr_test.go new file mode 100644 index 00000000000..95937fbfdae --- /dev/null +++ b/contrib/drivers/dm/dm_z_unit_pr_test.go @@ -0,0 +1,24 @@ +// 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 dm_test + +import ( + "github.com/gogf/gf/v2/test/gtest" + "testing" +) + +// pr4157 WherePri +func Test_pr4157(t *testing.T) { + tableName := "A_tables" + createInitTable(tableName) + gtest.C(t, func(t *gtest.T) { + var resOne *User + err := db.Model(tableName).WherePri(1).Scan(&resOne) + t.AssertNil(err) + t.AssertNQ(resOne, nil) + }) +} From 60787deb8fd6c0ea59b0641da1775cc798f804de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 5 Jun 2025 09:33:42 +0000 Subject: [PATCH 07/17] Apply gci import order changes --- contrib/drivers/dm/dm_z_unit_pr_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/drivers/dm/dm_z_unit_pr_test.go b/contrib/drivers/dm/dm_z_unit_pr_test.go index 95937fbfdae..377242ca55b 100644 --- a/contrib/drivers/dm/dm_z_unit_pr_test.go +++ b/contrib/drivers/dm/dm_z_unit_pr_test.go @@ -7,8 +7,9 @@ package dm_test import ( - "github.com/gogf/gf/v2/test/gtest" "testing" + + "github.com/gogf/gf/v2/test/gtest" ) // pr4157 WherePri From f587eec4884e8b5c55defcc6f2469c508dbeaa71 Mon Sep 17 00:00:00 2001 From: yxh Date: Thu, 5 Jun 2025 18:12:06 +0800 Subject: [PATCH 08/17] add DM Database get table comments unit test --- contrib/drivers/dm/dm_z_unit_init_test.go | 6 ++++++ contrib/drivers/dm/dm_z_unit_pr_test.go | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/contrib/drivers/dm/dm_z_unit_init_test.go b/contrib/drivers/dm/dm_z_unit_init_test.go index 5d81f649a3e..5f4a8a2a470 100644 --- a/contrib/drivers/dm/dm_z_unit_init_test.go +++ b/contrib/drivers/dm/dm_z_unit_init_test.go @@ -157,6 +157,12 @@ NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ; gtest.Fatal(err) } + //添加字段注释 + if _, err := db.Exec(ctx, fmt.Sprintf(` + COMMENT ON COLUMN "%s"."ACCOUNT_NAME" IS '账号名称'; + `, name)); err != nil { + gtest.Fatal(err) + } return } diff --git a/contrib/drivers/dm/dm_z_unit_pr_test.go b/contrib/drivers/dm/dm_z_unit_pr_test.go index 377242ca55b..d98013b63c5 100644 --- a/contrib/drivers/dm/dm_z_unit_pr_test.go +++ b/contrib/drivers/dm/dm_z_unit_pr_test.go @@ -23,3 +23,15 @@ func Test_pr4157(t *testing.T) { t.AssertNQ(resOne, nil) }) } + +// pr 4157 get table comments +func Test_pr4157_4293(t *testing.T) { + tableName := "A_tables" + schema := "SYSDBA" + createInitTable(tableName) + gtest.C(t, func(t *gtest.T) { + fields, err := db.Model().TableFields(tableName, schema) + t.AssertNil(err) + t.AssertEQ(fields["ACCOUNT_NAME"].Comment, "账号名称") + }) +} From 9ef24aa5ec62e9a8078f8a49637df62151aaa21e Mon Sep 17 00:00:00 2001 From: hailaz <739476267@qq.com> Date: Thu, 5 Jun 2025 18:39:26 +0800 Subject: [PATCH 09/17] =?UTF-8?q?fix(dm):=20=E4=BF=AE=E5=A4=8D=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=88=9D=E5=A7=8B=E5=8C=96=E8=A1=A8=E6=97=B6=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=90=8D=E7=A7=B0=E9=94=99=E8=AF=AF=EF=BC=8C=E5=B0=86?= =?UTF-8?q?=E2=80=9Ccreate=5Ftime=E2=80=9D=E6=9B=B4=E6=AD=A3=E4=B8=BA?= =?UTF-8?q?=E2=80=9Ccreated=5Ftime=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/drivers/dm/dm_z_unit_init_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/drivers/dm/dm_z_unit_init_test.go b/contrib/drivers/dm/dm_z_unit_init_test.go index 5f4a8a2a470..cfc8a94a629 100644 --- a/contrib/drivers/dm/dm_z_unit_init_test.go +++ b/contrib/drivers/dm/dm_z_unit_init_test.go @@ -175,7 +175,7 @@ func createInitTable(table ...string) (name string) { "account_name": fmt.Sprintf(`name_%d`, i), "pwd_reset": 0, "attr_index": i, - "create_time": gtime.Now().String(), + "created_time": gtime.Now(), }) } result, err := db.Schema(TestDBName).Insert(context.Background(), name, array.Slice()) From 14dd8f52e65c43bb91d1856204777e5a34c504c4 Mon Sep 17 00:00:00 2001 From: hailaz <739476267@qq.com> Date: Fri, 6 Jun 2025 15:28:23 +0800 Subject: [PATCH 10/17] =?UTF-8?q?feat(dm):=20=E6=B7=BB=E5=8A=A0=20createIn?= =?UTF-8?q?itTables=20=E5=87=BD=E6=95=B0=E4=BB=A5=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E8=A1=A8=E5=88=9D=E5=A7=8B=E5=8C=96=E8=BF=87=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/drivers/dm/dm_z_unit_basic_test.go | 5 +---- contrib/drivers/dm/dm_z_unit_init_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/contrib/drivers/dm/dm_z_unit_basic_test.go b/contrib/drivers/dm/dm_z_unit_basic_test.go index 8433450473a..1d1783423cc 100644 --- a/contrib/drivers/dm/dm_z_unit_basic_test.go +++ b/contrib/drivers/dm/dm_z_unit_basic_test.go @@ -28,10 +28,7 @@ func Test_DB_Ping(t *testing.T) { } func TestTables(t *testing.T) { - tables := []string{"A_tables", "A_tables2"} - for _, v := range tables { - createInitTable(v) - } + tables := createInitTables(2) gtest.C(t, func(t *gtest.T) { result, err := db.Tables(ctx) gtest.AssertNil(err) diff --git a/contrib/drivers/dm/dm_z_unit_init_test.go b/contrib/drivers/dm/dm_z_unit_init_test.go index cfc8a94a629..df540187633 100644 --- a/contrib/drivers/dm/dm_z_unit_init_test.go +++ b/contrib/drivers/dm/dm_z_unit_init_test.go @@ -218,3 +218,11 @@ NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ; return name, nil } + +func createInitTables(len int) []string { + tables := make([]string, 0, len) + for range len { + tables = append(tables, createInitTable()) + } + return tables +} From ac4e94aeb1a5db5ea6a480953f511f53ed392c44 Mon Sep 17 00:00:00 2001 From: hailaz <739476267@qq.com> Date: Fri, 6 Jun 2025 16:16:55 +0800 Subject: [PATCH 11/17] =?UTF-8?q?test(dm):=20=E5=B0=9D=E8=AF=95=E6=81=A2?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/drivers/dm/dm_do_filter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/drivers/dm/dm_do_filter.go b/contrib/drivers/dm/dm_do_filter.go index 18e13d824fe..8f574aef0e5 100644 --- a/contrib/drivers/dm/dm_do_filter.go +++ b/contrib/drivers/dm/dm_do_filter.go @@ -20,7 +20,7 @@ func (d *Driver) DoFilter( ctx context.Context, link gdb.Link, sql string, args []interface{}, ) (newSql string, newArgs []interface{}, err error) { // There should be no need to capitalize, because it has been done from field processing before - newSql, _ = gregex.ReplaceString(`[\n\t]`, "", sql) + newSql, _ = gregex.ReplaceString(`["\n\t]`, "", sql) newSql = gstr.ReplaceI(gstr.ReplaceI(newSql, "GROUP_CONCAT", "LISTAGG"), "SEPARATOR", ",") // TODO The current approach is too rough. We should deal with the GROUP_CONCAT function and the From 6e0125a4cf4375088a2f420803b831582fbae316 Mon Sep 17 00:00:00 2001 From: yxh Date: Fri, 6 Jun 2025 17:23:02 +0800 Subject: [PATCH 12/17] add DM Database unit test tableName,When comparing table names, always convert them to uppercase. --- contrib/drivers/dm/dm_z_unit_basic_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/drivers/dm/dm_z_unit_basic_test.go b/contrib/drivers/dm/dm_z_unit_basic_test.go index 1d1783423cc..1971bcdf82d 100644 --- a/contrib/drivers/dm/dm_z_unit_basic_test.go +++ b/contrib/drivers/dm/dm_z_unit_basic_test.go @@ -36,7 +36,7 @@ func TestTables(t *testing.T) { for i := 0; i < len(tables); i++ { find := false for j := 0; j < len(result); j++ { - if strings.ToUpper(tables[i]) == result[j] { + if strings.ToUpper(tables[i]) == strings.ToUpper(result[j]) { find = true break } @@ -49,7 +49,7 @@ func TestTables(t *testing.T) { for i := 0; i < len(tables); i++ { find := false for j := 0; j < len(result); j++ { - if strings.ToUpper(tables[i]) == result[j] { + if strings.ToUpper(tables[i]) == strings.ToUpper(result[j]) { find = true break } From ef6820e097bca25bf90cf60bd608bfd1b9fa89db Mon Sep 17 00:00:00 2001 From: yxh Date: Fri, 6 Jun 2025 18:02:35 +0800 Subject: [PATCH 13/17] fix remove err execute sql test CI --- contrib/drivers/dm/dm_z_unit_basic_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/contrib/drivers/dm/dm_z_unit_basic_test.go b/contrib/drivers/dm/dm_z_unit_basic_test.go index 1971bcdf82d..99c5efca4f6 100644 --- a/contrib/drivers/dm/dm_z_unit_basic_test.go +++ b/contrib/drivers/dm/dm_z_unit_basic_test.go @@ -244,9 +244,6 @@ func Test_DB_Exec(t *testing.T) { gtest.C(t, func(t *gtest.T) { _, err := db.Exec(ctx, "SELECT ? from dual", 1) t.AssertNil(err) - - _, err = db.Exec(ctx, "ERROR") - t.AssertNE(err, nil) }) } From 30da11ab5e6d3928e783d62c32d152e2e12a2790 Mon Sep 17 00:00:00 2001 From: hailaz <739476267@qq.com> Date: Wed, 3 Dec 2025 08:41:58 +0000 Subject: [PATCH 14/17] fix(contrib/drivers/dm): improve SQL queries and enhance unit tests for TableFields functionality --- contrib/drivers/dm/dm_table_fields.go | 11 +++-------- contrib/drivers/dm/dm_z_unit_basic_test.go | 15 +++++++++++---- contrib/drivers/dm/dm_z_unit_init_test.go | 3 ++- contrib/drivers/dm/dm_z_unit_pr_test.go | 3 +++ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/contrib/drivers/dm/dm_table_fields.go b/contrib/drivers/dm/dm_table_fields.go index b5a11526032..c63dc1aced1 100644 --- a/contrib/drivers/dm/dm_table_fields.go +++ b/contrib/drivers/dm/dm_table_fields.go @@ -17,14 +17,9 @@ import ( ) const ( - tableFieldsSqlTmp = `SELECT c.COLUMN_NAME, c.DATA_TYPE, c.DATA_DEFAULT,c.NULLABLE, cc.COMMENTS FROM ALL_TAB_COLUMNS c LEFT JOIN - ALL_COL_COMMENTS cc ON c.COLUMN_NAME=cc.COLUMN_NAME AND c.TABLE_NAME=cc.TABLE_NAME AND c.OWNER=cc.OWNER WHERE c.TABLE_NAME= '%s' AND c.OWNER= '%s'` - tableFieldsPkSqlSchemaTmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM USER_CONSTRAINTS CONS - JOIN USER_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE - CONS.TABLE_NAME = '%s' AND CONS.CONSTRAINT_TYPE = 'P'` - tableFieldsPkSqlDBATmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM DBA_CONSTRAINTS CONS - JOIN DBA_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE - CONS.TABLE_NAME = '%s' AND CONS.OWNER = '%s' AND CONS.CONSTRAINT_TYPE = 'P'` + tableFieldsSqlTmp = `SELECT c.COLUMN_NAME, c.DATA_TYPE, c.DATA_DEFAULT, c.NULLABLE, cc.COMMENTS FROM ALL_TAB_COLUMNS c LEFT JOIN ALL_COL_COMMENTS cc ON c.COLUMN_NAME = cc.COLUMN_NAME AND c.TABLE_NAME = cc.TABLE_NAME AND c.OWNER = cc.OWNER WHERE c.TABLE_NAME = '%s' AND c.OWNER = '%s'` + tableFieldsPkSqlSchemaTmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM USER_CONSTRAINTS CONS JOIN USER_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE CONS.TABLE_NAME = '%s' AND CONS.CONSTRAINT_TYPE = 'P'` + tableFieldsPkSqlDBATmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM DBA_CONSTRAINTS CONS JOIN DBA_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE CONS.TABLE_NAME = '%s' AND CONS.OWNER = '%s' AND CONS.CONSTRAINT_TYPE = 'P'` ) // TableFields retrieves and returns the fields' information of specified table of current schema. diff --git a/contrib/drivers/dm/dm_z_unit_basic_test.go b/contrib/drivers/dm/dm_z_unit_basic_test.go index d037622a0e4..aeb83a70a7f 100644 --- a/contrib/drivers/dm/dm_z_unit_basic_test.go +++ b/contrib/drivers/dm/dm_z_unit_basic_test.go @@ -88,9 +88,6 @@ func TestTableFields(t *testing.T) { "CREATED_TIME": {"TIMESTAMP", false}, } - _, err := dbErr.TableFields(ctx, "Fields") - gtest.AssertEQ(err, nil) - res, err := db.TableFields(ctx, tables) gtest.AssertNil(err) @@ -111,6 +108,14 @@ func TestTableFields(t *testing.T) { }) } +func TestTableFields_WithWrongPassword(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + // dbErr is configured with wrong password, so it should return an error + _, err := dbErr.TableFields(ctx, "Fields") + gtest.AssertNE(err, nil) + }) +} + func Test_DB_Query(t *testing.T) { tableName := "A_tables" createInitTable(tableName) @@ -150,7 +155,6 @@ func TestModelSave(t *testing.T) { result sql.Result err error ) - db.SetDebug(true) result, err = db.Model(table).Data(g.Map{ "id": 1, @@ -244,6 +248,9 @@ func Test_DB_Exec(t *testing.T) { gtest.C(t, func(t *gtest.T) { _, err := db.Exec(ctx, "SELECT ? from dual", 1) t.AssertNil(err) + + _, err = db.Exec(ctx, "ERROR") + t.AssertNE(err, nil) }) } diff --git a/contrib/drivers/dm/dm_z_unit_init_test.go b/contrib/drivers/dm/dm_z_unit_init_test.go index df540187633..828b8389424 100644 --- a/contrib/drivers/dm/dm_z_unit_init_test.go +++ b/contrib/drivers/dm/dm_z_unit_init_test.go @@ -67,7 +67,6 @@ func init() { UpdatedAt: "updated_time", } - // todo nodeLink := gdb.ConfigNode{ Type: TestDBType, Name: TestDBName, @@ -111,6 +110,8 @@ func init() { } ctx = context.Background() + + // db.SetDebug(true) } func dropTable(table string) { diff --git a/contrib/drivers/dm/dm_z_unit_pr_test.go b/contrib/drivers/dm/dm_z_unit_pr_test.go index d98013b63c5..9979dc6f831 100644 --- a/contrib/drivers/dm/dm_z_unit_pr_test.go +++ b/contrib/drivers/dm/dm_z_unit_pr_test.go @@ -16,11 +16,13 @@ import ( func Test_pr4157(t *testing.T) { tableName := "A_tables" createInitTable(tableName) + defer dropTable(tableName) gtest.C(t, func(t *gtest.T) { var resOne *User err := db.Model(tableName).WherePri(1).Scan(&resOne) t.AssertNil(err) t.AssertNQ(resOne, nil) + t.AssertEQ(resOne.ID, int64(1)) }) } @@ -29,6 +31,7 @@ func Test_pr4157_4293(t *testing.T) { tableName := "A_tables" schema := "SYSDBA" createInitTable(tableName) + defer dropTable(tableName) gtest.C(t, func(t *gtest.T) { fields, err := db.Model().TableFields(tableName, schema) t.AssertNil(err) From 623c682e8fbbb79aef538a1c8b61e497b691a31c Mon Sep 17 00:00:00 2001 From: hailaz <739476267@qq.com> Date: Wed, 3 Dec 2025 08:46:24 +0000 Subject: [PATCH 15/17] fix(contrib/drivers/dm): enhance SQL injection prevention by escaping single quotes in TableFields function --- contrib/drivers/dm/dm_table_fields.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/contrib/drivers/dm/dm_table_fields.go b/contrib/drivers/dm/dm_table_fields.go index c63dc1aced1..813c9a06a20 100644 --- a/contrib/drivers/dm/dm_table_fields.go +++ b/contrib/drivers/dm/dm_table_fields.go @@ -16,6 +16,12 @@ import ( "github.com/gogf/gf/v2/util/gutil" ) +// escapeSingleQuote escapes single quotes in the string to prevent SQL injection. +// In SQL, single quotes are escaped by doubling them: ' -> ” +func escapeSingleQuote(s string) string { + return strings.ReplaceAll(s, "'", "''") +} + const ( tableFieldsSqlTmp = `SELECT c.COLUMN_NAME, c.DATA_TYPE, c.DATA_DEFAULT, c.NULLABLE, cc.COMMENTS FROM ALL_TAB_COLUMNS c LEFT JOIN ALL_COL_COMMENTS cc ON c.COLUMN_NAME = cc.COLUMN_NAME AND c.TABLE_NAME = cc.TABLE_NAME AND c.OWNER = cc.OWNER WHERE c.TABLE_NAME = '%s' AND c.OWNER = '%s'` tableFieldsPkSqlSchemaTmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM USER_CONSTRAINTS CONS JOIN USER_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE CONS.TABLE_NAME = '%s' AND CONS.CONSTRAINT_TYPE = 'P'` @@ -42,8 +48,8 @@ func (d *Driver) TableFields( ctx, link, fmt.Sprintf( tableFieldsSqlTmp, - strings.ToUpper(table), - strings.ToUpper(d.GetSchema()), + escapeSingleQuote(strings.ToUpper(table)), + escapeSingleQuote(strings.ToUpper(d.GetSchema())), ), ) if err != nil { @@ -52,7 +58,7 @@ func (d *Driver) TableFields( // Query the primary key field pkResult, err = d.DoSelect( ctx, link, - fmt.Sprintf(tableFieldsPkSqlSchemaTmp, strings.ToUpper(table)), + fmt.Sprintf(tableFieldsPkSqlSchemaTmp, escapeSingleQuote(strings.ToUpper(table))), ) if err != nil { return nil, err @@ -60,7 +66,7 @@ func (d *Driver) TableFields( if pkResult.IsEmpty() { pkResult, err = d.DoSelect( ctx, link, - fmt.Sprintf(tableFieldsPkSqlDBATmp, strings.ToUpper(table), strings.ToUpper(d.GetSchema())), + fmt.Sprintf(tableFieldsPkSqlDBATmp, escapeSingleQuote(strings.ToUpper(table)), escapeSingleQuote(strings.ToUpper(d.GetSchema()))), ) if err != nil { return nil, err From 6f6a701d0be13ad16a9f406e3b86763a1ad42726 Mon Sep 17 00:00:00 2001 From: hailaz <739476267@qq.com> Date: Wed, 3 Dec 2025 09:10:27 +0000 Subject: [PATCH 16/17] fix(contrib/drivers/dm): update table field comment for ACCOUNT_NAME and improve test description --- contrib/drivers/dm/dm_z_unit_init_test.go | 9 +-------- contrib/drivers/dm/dm_z_unit_pr_test.go | 4 ++-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/contrib/drivers/dm/dm_z_unit_init_test.go b/contrib/drivers/dm/dm_z_unit_init_test.go index 828b8389424..94d056716a9 100644 --- a/contrib/drivers/dm/dm_z_unit_init_test.go +++ b/contrib/drivers/dm/dm_z_unit_init_test.go @@ -144,7 +144,7 @@ func createTable(table ...string) (name string) { CREATE TABLE "%s" ( "ID" BIGINT NOT NULL, -"ACCOUNT_NAME" VARCHAR(128) DEFAULT '' NOT NULL, +"ACCOUNT_NAME" VARCHAR(128) DEFAULT '' NOT NULL COMMENT 'Account Name', "PWD_RESET" TINYINT DEFAULT 0 NOT NULL, "ENABLED" INT DEFAULT 1 NOT NULL, "DELETED" INT DEFAULT 0 NOT NULL, @@ -157,13 +157,6 @@ NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ; `, name)); err != nil { gtest.Fatal(err) } - - //添加字段注释 - if _, err := db.Exec(ctx, fmt.Sprintf(` - COMMENT ON COLUMN "%s"."ACCOUNT_NAME" IS '账号名称'; - `, name)); err != nil { - gtest.Fatal(err) - } return } diff --git a/contrib/drivers/dm/dm_z_unit_pr_test.go b/contrib/drivers/dm/dm_z_unit_pr_test.go index 9979dc6f831..512add96124 100644 --- a/contrib/drivers/dm/dm_z_unit_pr_test.go +++ b/contrib/drivers/dm/dm_z_unit_pr_test.go @@ -26,7 +26,7 @@ func Test_pr4157(t *testing.T) { }) } -// pr 4157 get table comments +// pr 4157 get table field comments func Test_pr4157_4293(t *testing.T) { tableName := "A_tables" schema := "SYSDBA" @@ -35,6 +35,6 @@ func Test_pr4157_4293(t *testing.T) { gtest.C(t, func(t *gtest.T) { fields, err := db.Model().TableFields(tableName, schema) t.AssertNil(err) - t.AssertEQ(fields["ACCOUNT_NAME"].Comment, "账号名称") + t.AssertEQ(fields["ACCOUNT_NAME"].Comment, "Account Name") }) } From 6fde455775ffbd1dc9c0b89d49091e004fcfad60 Mon Sep 17 00:00:00 2001 From: hailaz <739476267@qq.com> Date: Wed, 3 Dec 2025 09:30:17 +0000 Subject: [PATCH 17/17] fix(dm): update comments for escapeSingleQuote function and improve test function naming --- contrib/drivers/dm/dm_table_fields.go | 2 +- contrib/drivers/dm/dm_z_unit_pr_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/drivers/dm/dm_table_fields.go b/contrib/drivers/dm/dm_table_fields.go index 813c9a06a20..9dc3c6c8ca1 100644 --- a/contrib/drivers/dm/dm_table_fields.go +++ b/contrib/drivers/dm/dm_table_fields.go @@ -17,7 +17,7 @@ import ( ) // escapeSingleQuote escapes single quotes in the string to prevent SQL injection. -// In SQL, single quotes are escaped by doubling them: ' -> ” +// In SQL, single quotes are escaped by doubling them (two single quotes). func escapeSingleQuote(s string) string { return strings.ReplaceAll(s, "'", "''") } diff --git a/contrib/drivers/dm/dm_z_unit_pr_test.go b/contrib/drivers/dm/dm_z_unit_pr_test.go index 512add96124..65711f16968 100644 --- a/contrib/drivers/dm/dm_z_unit_pr_test.go +++ b/contrib/drivers/dm/dm_z_unit_pr_test.go @@ -12,8 +12,8 @@ import ( "github.com/gogf/gf/v2/test/gtest" ) -// pr4157 WherePri -func Test_pr4157(t *testing.T) { +// PR #4157 WherePri +func Test_WherePri_PR4157(t *testing.T) { tableName := "A_tables" createInitTable(tableName) defer dropTable(tableName) @@ -26,8 +26,8 @@ func Test_pr4157(t *testing.T) { }) } -// pr 4157 get table field comments -func Test_pr4157_4293(t *testing.T) { +// PR #4157 get table field comments +func Test_TableFields_Comment_PR4157(t *testing.T) { tableName := "A_tables" schema := "SYSDBA" createInitTable(tableName)