mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-05-07 04:52:44 +08:00
🐛 fix(dameng): 修正表格更新无法识别主键列
- 达梦列元数据查询补充主键关联并返回 column_key - GetColumns 正确映射主键标记,避免表格更新退化为整行 WHERE - 补充达梦列元数据回归测试,并验证带驱动 tag 的实现编译通过 Fixes #389
This commit is contained in:
63
internal/db/dameng_columns_test.go
Normal file
63
internal/db/dameng_columns_test.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuildDamengColumnsQuery_IncludesPrimaryKeyMetadata(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ownerQuery := buildDamengColumnsQuery("biz", "orders")
|
||||
if !strings.Contains(ownerQuery, "constraint_type = 'P'") {
|
||||
t.Fatalf("owner query 应包含主键约束过滤, got=%s", ownerQuery)
|
||||
}
|
||||
if !strings.Contains(ownerQuery, "AS column_key") {
|
||||
t.Fatalf("owner query 应返回 column_key, got=%s", ownerQuery)
|
||||
}
|
||||
if !strings.Contains(ownerQuery, "WHERE c.owner = 'BIZ' AND c.table_name = 'ORDERS'") {
|
||||
t.Fatalf("owner query 应按 owner/table 过滤, got=%s", ownerQuery)
|
||||
}
|
||||
|
||||
userQuery := buildDamengColumnsQuery("", "orders")
|
||||
if !strings.Contains(userQuery, "FROM user_tab_columns c") {
|
||||
t.Fatalf("user query 应使用 user_tab_columns, got=%s", userQuery)
|
||||
}
|
||||
if !strings.Contains(userQuery, "JOIN user_cons_columns cols") {
|
||||
t.Fatalf("user query 应关联 user_cons_columns, got=%s", userQuery)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDamengColumnDefinitions_MarksPrimaryKeyColumns(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
columns := buildDamengColumnDefinitions([]map[string]interface{}{
|
||||
{
|
||||
"COLUMN_NAME": "ID",
|
||||
"DATA_TYPE": "INTEGER",
|
||||
"NULLABLE": "N",
|
||||
"DATA_DEFAULT": nil,
|
||||
"COLUMN_KEY": "PRI",
|
||||
},
|
||||
{
|
||||
"COLUMN_NAME": "NAME",
|
||||
"DATA_TYPE": "VARCHAR2",
|
||||
"NULLABLE": "Y",
|
||||
"DATA_DEFAULT": "guest",
|
||||
"COLUMN_KEY": "",
|
||||
},
|
||||
})
|
||||
|
||||
if len(columns) != 2 {
|
||||
t.Fatalf("unexpected column count: %d", len(columns))
|
||||
}
|
||||
if columns[0].Name != "ID" || columns[0].Key != "PRI" {
|
||||
t.Fatalf("主键列未正确标记: %+v", columns[0])
|
||||
}
|
||||
if columns[1].Name != "NAME" || columns[1].Key != "" {
|
||||
t.Fatalf("非主键列标记异常: %+v", columns[1])
|
||||
}
|
||||
if columns[1].Default == nil || *columns[1].Default != "guest" {
|
||||
t.Fatalf("默认值未保留: %+v", columns[1])
|
||||
}
|
||||
}
|
||||
@@ -264,38 +264,12 @@ func (d *DamengDB) GetCreateStatement(dbName, tableName string) (string, error)
|
||||
}
|
||||
|
||||
func (d *DamengDB) GetColumns(dbName, tableName string) ([]connection.ColumnDefinition, error) {
|
||||
query := fmt.Sprintf(`SELECT column_name, data_type, nullable, data_default
|
||||
FROM all_tab_columns
|
||||
WHERE owner = '%s' AND table_name = '%s'`,
|
||||
strings.ToUpper(dbName), strings.ToUpper(tableName))
|
||||
|
||||
if dbName == "" {
|
||||
query = fmt.Sprintf(`SELECT column_name, data_type, nullable, data_default
|
||||
FROM user_tab_columns
|
||||
WHERE table_name = '%s'`, strings.ToUpper(tableName))
|
||||
}
|
||||
|
||||
data, _, err := d.Query(query)
|
||||
data, _, err := d.Query(buildDamengColumnsQuery(dbName, tableName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var columns []connection.ColumnDefinition
|
||||
for _, row := range data {
|
||||
col := connection.ColumnDefinition{
|
||||
Name: fmt.Sprintf("%v", row["COLUMN_NAME"]),
|
||||
Type: fmt.Sprintf("%v", row["DATA_TYPE"]),
|
||||
Nullable: fmt.Sprintf("%v", row["NULLABLE"]),
|
||||
}
|
||||
|
||||
if row["DATA_DEFAULT"] != nil {
|
||||
def := fmt.Sprintf("%v", row["DATA_DEFAULT"])
|
||||
col.Default = &def
|
||||
}
|
||||
|
||||
columns = append(columns, col)
|
||||
}
|
||||
return columns, nil
|
||||
return buildDamengColumnDefinitions(data), nil
|
||||
}
|
||||
|
||||
func (d *DamengDB) GetIndexes(dbName, tableName string) ([]connection.IndexDefinition, error) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"GoNavi-Wails/internal/connection"
|
||||
"GoNavi-Wails/internal/logger"
|
||||
)
|
||||
|
||||
@@ -103,3 +104,57 @@ func getDamengRowString(row map[string]interface{}, keys ...string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func buildDamengColumnsQuery(dbName, tableName string) string {
|
||||
upperTableName := strings.ToUpper(strings.TrimSpace(tableName))
|
||||
upperDBName := strings.ToUpper(strings.TrimSpace(dbName))
|
||||
|
||||
if upperDBName == "" {
|
||||
return fmt.Sprintf(`SELECT c.column_name, c.data_type, c.nullable, c.data_default,
|
||||
CASE WHEN pk.column_name IS NOT NULL THEN 'PRI' ELSE '' END AS column_key
|
||||
FROM user_tab_columns c
|
||||
LEFT JOIN (
|
||||
SELECT cols.table_name, cols.column_name
|
||||
FROM user_constraints cons
|
||||
JOIN user_cons_columns cols USING (constraint_name)
|
||||
WHERE cons.constraint_type = 'P'
|
||||
) pk ON c.table_name = pk.table_name AND c.column_name = pk.column_name
|
||||
WHERE c.table_name = '%s'
|
||||
ORDER BY c.column_id`, upperTableName)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`SELECT c.column_name, c.data_type, c.nullable, c.data_default,
|
||||
CASE WHEN pk.column_name IS NOT NULL THEN 'PRI' ELSE '' END AS column_key
|
||||
FROM all_tab_columns c
|
||||
LEFT JOIN (
|
||||
SELECT cols.owner, cols.table_name, cols.column_name
|
||||
FROM all_constraints cons
|
||||
JOIN all_cons_columns cols
|
||||
ON cons.owner = cols.owner AND cons.constraint_name = cols.constraint_name
|
||||
WHERE cons.constraint_type = 'P'
|
||||
) pk ON c.owner = pk.owner AND c.table_name = pk.table_name AND c.column_name = pk.column_name
|
||||
WHERE c.owner = '%s' AND c.table_name = '%s'
|
||||
ORDER BY c.column_id`, upperDBName, upperTableName)
|
||||
}
|
||||
|
||||
func buildDamengColumnDefinitions(data []map[string]interface{}) []connection.ColumnDefinition {
|
||||
columns := make([]connection.ColumnDefinition, 0, len(data))
|
||||
for _, row := range data {
|
||||
col := connection.ColumnDefinition{
|
||||
Name: getDamengRowString(row, "COLUMN_NAME"),
|
||||
Type: getDamengRowString(row, "DATA_TYPE"),
|
||||
Nullable: getDamengRowString(row, "NULLABLE"),
|
||||
Key: getDamengRowString(row, "COLUMN_KEY"),
|
||||
}
|
||||
|
||||
defaultValue := getDamengRowString(row, "DATA_DEFAULT")
|
||||
if defaultValue != "" {
|
||||
def := defaultValue
|
||||
col.Default = &def
|
||||
}
|
||||
|
||||
columns = append(columns, col)
|
||||
}
|
||||
|
||||
return columns
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user