Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Syngnat
2026-07-28 14:10:33 +08:00
4 changed files with 122 additions and 1 deletions

View File

@@ -51,6 +51,22 @@ func (damengColumnsMetadataConn) QueryContext(_ context.Context, query string, _
failAutoIncrementQuery := damengColumnsMetadataQueryState.failAutoIncrementQuery
damengColumnsMetadataQueryState.Unlock()
if strings.Contains(query, "DBMS_METADATA.GET_DDL") {
return &damengColumnsMetadataRows{
columns: []string{"DDL"},
values: [][]driver.Value{{`CREATE TABLE "BIZ"."ORDERS" (
"ID" NUMBER NOT NULL
)`}},
}, nil
}
if strings.Contains(query, "all_tab_comments") {
return &damengColumnsMetadataRows{
columns: []string{"TABLE_COMMENT"},
values: [][]driver.Value{{"订单'归档"}},
}, nil
}
if strings.Contains(query, "SYS.SYSCOLUMNS") {
if failAutoIncrementQuery {
return nil, errors.New("insufficient privilege for SYS.SYSCOLUMNS")
@@ -174,6 +190,33 @@ func TestDamengGetColumnsKeepsBaseMetadataWhenAutoIncrementQueryFails(t *testing
}
}
func TestDamengGetCreateStatementAppendsTableComment(t *testing.T) {
resetDamengColumnsMetadataQueryState(t, false)
damengDB := &DamengDB{conn: openDamengColumnsMetadataDB(t)}
ddl, err := damengDB.GetCreateStatement("biz", "orders")
if err != nil {
t.Fatalf("GetCreateStatement returned error: %v", err)
}
for _, want := range []string{
`CREATE TABLE "BIZ"."ORDERS"`,
`COMMENT ON TABLE "BIZ"."ORDERS" IS '订单''归档';`,
} {
if !strings.Contains(ddl, want) {
t.Fatalf("expected DDL to contain %q, got: %s", want, ddl)
}
}
queries := damengColumnsMetadataQueries()
if len(queries) != 2 || !strings.Contains(queries[1], "all_tab_comments") {
t.Fatalf("expected DDL and table comment metadata queries, got=%v", queries)
}
if !strings.Contains(queries[1], "owner = 'BIZ'") || !strings.Contains(queries[1], "table_name = 'ORDERS'") {
t.Fatalf("expected normalized schema and table comment predicates, got=%s", queries[1])
}
}
func TestDamengGetIndexesUsesIndexOwnerJoinAndMapsColumnOrder(t *testing.T) {
resetDamengColumnsMetadataQueryState(t, false)

View File

@@ -305,7 +305,17 @@ func (d *DamengDB) GetCreateStatement(dbName, tableName string) (string, error)
if len(data) > 0 {
if val, ok := data[0]["DDL"]; ok {
return fmt.Sprintf("%v", val), nil
ddl := fmt.Sprintf("%v", val)
commentData, _, commentErr := d.Query(buildDamengTableCommentQuery(dbName, tableName))
if commentErr != nil {
logger.Warnf("达梦 GetCreateStatement 表注释元数据查询失败,已返回基础 DDL%v", commentErr)
return ddl, nil
}
if len(commentData) == 0 {
return ddl, nil
}
comment := getDamengRowString(commentData[0], "TABLE_COMMENT", "COMMENT", "COMMENTS")
return appendDamengTableCommentDDL(ddl, dbName, tableName, comment), nil
}
}
return "", localizedDatabaseRuntimeError("db.backend.error.create_table_statement_not_found", nil)

View File

@@ -148,6 +148,43 @@ func buildDamengColumnsQuery(dbName, tableName string) string {
ORDER BY c.column_id`, upperDBName, upperTableName, upperDBName, upperTableName, upperDBName, upperTableName)
}
func buildDamengTableCommentQuery(dbName, tableName string) string {
upperTableName := strings.ReplaceAll(strings.ToUpper(strings.TrimSpace(tableName)), "'", "''")
upperDBName := strings.ReplaceAll(strings.ToUpper(strings.TrimSpace(dbName)), "'", "''")
if upperDBName == "" {
return fmt.Sprintf(`SELECT comments AS "TABLE_COMMENT"
FROM user_tab_comments
WHERE table_name = '%s' AND comments IS NOT NULL`, upperTableName)
}
return fmt.Sprintf(`SELECT comments AS "TABLE_COMMENT"
FROM all_tab_comments
WHERE owner = '%s' AND table_name = '%s' AND comments IS NOT NULL`, upperDBName, upperTableName)
}
func appendDamengTableCommentDDL(ddl, dbName, tableName, comment string) string {
baseDDL := strings.TrimSpace(ddl)
comment = strings.TrimSpace(comment)
if baseDDL == "" || comment == "" || strings.Contains(strings.ToUpper(baseDDL), "COMMENT ON TABLE ") {
return baseDDL
}
quoteIdentifier := func(value string) string {
value = strings.ToUpper(strings.TrimSpace(value))
return `"` + strings.ReplaceAll(value, `"`, `""`) + `"`
}
tableRef := quoteIdentifier(tableName)
if strings.TrimSpace(dbName) != "" {
tableRef = quoteIdentifier(dbName) + "." + tableRef
}
baseDDL = strings.TrimRight(baseDDL, " \t\r\n")
if !strings.HasSuffix(baseDDL, ";") && !strings.HasSuffix(baseDDL, "/") {
baseDDL += ";"
}
escapedComment := strings.ReplaceAll(comment, "'", "''")
return fmt.Sprintf("%s\n\nCOMMENT ON TABLE %s IS '%s';", baseDDL, tableRef, escapedComment)
}
// buildDamengAutoIncrementColumnsQuery reads the stable system-table flag that
// records both IDENTITY and AUTO_INCREMENT columns. It intentionally remains a
// separate query so restricted accounts can still load base column metadata.

View File

@@ -146,6 +146,37 @@ func TestBuildDamengColumnsQuery_IncludesColumnCommentsJoin(t *testing.T) {
}
}
func TestBuildDamengTableCommentQueryUsesSchemaAppropriateDictionaryView(t *testing.T) {
t.Parallel()
userQuery := buildDamengTableCommentQuery("", "orders")
if !strings.Contains(userQuery, "FROM user_tab_comments") || !strings.Contains(userQuery, "table_name = 'ORDERS'") {
t.Fatalf("expected current-schema table comment query, got: %s", userQuery)
}
allQuery := buildDamengTableCommentQuery("biz", "orders")
if !strings.Contains(allQuery, "FROM all_tab_comments") || !strings.Contains(allQuery, "owner = 'BIZ'") || !strings.Contains(allQuery, "table_name = 'ORDERS'") {
t.Fatalf("expected schema table comment query, got: %s", allQuery)
}
}
func TestAppendDamengTableCommentDDLAvoidsDuplicateAndEscapesLiteral(t *testing.T) {
t.Parallel()
ddl := appendDamengTableCommentDDL(`CREATE TABLE "BIZ"."ORDERS" ("ID" NUMBER)`, "biz", "orders", "订单'归档")
if !strings.Contains(ddl, `COMMENT ON TABLE "BIZ"."ORDERS" IS '订单''归档';`) {
t.Fatalf("expected escaped table comment DDL, got: %s", ddl)
}
if !strings.Contains(ddl, "(\"ID\" NUMBER);\n\nCOMMENT ON TABLE") {
t.Fatalf("expected create statement terminator before table comment, got: %s", ddl)
}
duplicated := appendDamengTableCommentDDL(ddl, "biz", "orders", "新备注")
if duplicated != ddl {
t.Fatalf("expected existing table comment DDL to remain unchanged, got: %s", duplicated)
}
}
func TestBuildDamengColumnDefinitions_MapsComment(t *testing.T) {
t.Parallel()