fix(xugu): expose identity columns to data generation

This commit is contained in:
Elias
2026-09-19 09:46:53 +08:00
committed by GitHub
parent 85a10be4c9
commit 5a59777246
2 changed files with 74 additions and 1 deletions
+38 -1
View File
@@ -2769,7 +2769,28 @@ func (s *server) getColumns(schema, table string) ([]columnInfo, error) {
item.NumericPrecision, item.NumericScale, item.CharacterMaximumLength = decodeXuguScale(item.DataType, scale)
result = append(result, item)
}
return emptyIfNil(result), rows.Err()
if err := rows.Err(); err != nil {
_ = s.closeRows(rows)
return nil, err
}
if err := s.closeRows(rows); err != nil {
return nil, err
}
// Xugu exposes IDENTITY/AUTO_INCREMENT columns through the serial
// metadata catalogs rather than through DEF_VAL. Enrich the common column
// contract with the value already understood by the desktop data generator.
// This lookup is deliberately optional: an account may read ALL_COLUMNS
// while lacking access to ALL_SEQUENCES, and that must not make ordinary
// column metadata unavailable.
if identities, identityErr := s.tableIdentities(schema, table); identityErr == nil {
for index := range result {
if xuguIdentityMatchesColumn(result[index].Name, identities) {
result[index].Extra = stringPtr("auto_increment")
}
}
}
return emptyIfNil(result), nil
}
func (s *server) queryColumnRows(schema, table string) (*sql.Rows, bool, error) {
@@ -4546,6 +4567,22 @@ func (s *server) tableIdentities(schema, table string) (map[string]xuguIdentityI
return result, rows.Err()
}
// xuguIdentityMatchesColumn keeps identity enrichment safe for catalog views
// that may normalize unquoted names differently from ALL_COLUMNS. Exact
// matches win; a case-insensitive match is accepted only when unambiguous.
func xuguIdentityMatchesColumn(columnName string, identities map[string]xuguIdentityInfo) bool {
if _, ok := identities[columnName]; ok {
return true
}
matches := 0
for identityColumn := range identities {
if strings.EqualFold(identityColumn, columnName) {
matches++
}
}
return matches == 1
}
func (s *server) tableConstraints(schema, table string) ([]xuguConstraintInfo, error) {
return s.readTableConstraints(xuguTableConstraintsSQL, schema, table)
}
+36
View File
@@ -966,6 +966,42 @@ func TestXuguPrimaryKeyMatchingDoesNotGuessAmbiguousCase(t *testing.T) {
}
}
func TestGetColumnsMarksXuguIdentityColumnsAsAutoIncrement(t *testing.T) {
db, err := sql.Open("xugu-test-table-ddl", "")
if err != nil {
t.Fatal(err)
}
defer db.Close()
s := newServer()
s.db = db
columns, err := s.getColumns("APP", "CHILD")
if err != nil {
t.Fatalf("get columns: %v", err)
}
if len(columns) != 2 {
t.Fatalf("expected two columns, got %#v", columns)
}
if columns[0].Name != "ID" || columns[0].Extra == nil || *columns[0].Extra != "auto_increment" {
t.Fatalf("identity column should be marked auto_increment: %#v", columns[0])
}
if columns[1].Name != "PARENT_ID" || columns[1].Extra != nil {
t.Fatalf("ordinary column must not be marked auto_increment: %#v", columns[1])
}
}
func TestXuguIdentityColumnMatchingIsCaseInsensitiveOnlyWhenUnambiguous(t *testing.T) {
if !xuguIdentityMatchesColumn("id", map[string]xuguIdentityInfo{"ID": {Column: "ID"}}) {
t.Fatal("expected an unambiguous case-insensitive identity match")
}
if xuguIdentityMatchesColumn("id", map[string]xuguIdentityInfo{
"ID": {Column: "ID"},
"Id": {Column: "Id"},
}) {
t.Fatal("ambiguous case-insensitive identity names must not match")
}
}
func TestIndexSQLUsesLowPrivilegeDictionary(t *testing.T) {
sqlText := strings.ToUpper(xuguListIndexesSQL)