diff --git a/agents/drivers/xugu/main.go b/agents/drivers/xugu/main.go index c27a6dbf5..d0eb7ee69 100644 --- a/agents/drivers/xugu/main.go +++ b/agents/drivers/xugu/main.go @@ -37,7 +37,7 @@ WHERE UPPER(s.SCHEMA_NAME) = UPPER(?) AND UPPER(t.TABLE_NAME) = UPPER(?) AND c.CONS_TYPE = 'P'` const xuguListColumnsSQL = ` -SELECT c.COL_NAME, c.TYPE_NAME, c.NOT_NULL, c.DEF_VAL, c.COMMENTS, c.SCALE +SELECT c.COL_NAME, c.TYPE_NAME, c.NOT_NULL, c.DEF_VAL, c.COMMENTS, c.SCALE, c."VARYING" FROM ALL_COLUMNS c JOIN ALL_TABLES t ON t.DB_ID = c.DB_ID AND t.TABLE_ID = c.TABLE_ID JOIN ALL_SCHEMAS s ON s.DB_ID = t.DB_ID AND s.SCHEMA_ID = t.SCHEMA_ID @@ -879,6 +879,7 @@ func (s *server) getColumns(schema, table string) ([]columnInfo, error) { var item columnInfo var notNull any var scale *int + var varying any if err := rows.Scan( &item.Name, &item.DataType, @@ -886,9 +887,11 @@ func (s *server) getColumns(schema, table string) ([]columnInfo, error) { &item.ColumnDefault, &item.Comment, &scale, + &varying, ); err != nil { return nil, err } + item.DataType = normalizeXuguColumnType(item.DataType, varying) item.IsNullable = !truthy(notNull) item.IsPrimaryKey = primaryKeys[strings.ToUpper(item.Name)] item.NumericPrecision, item.NumericScale, item.CharacterMaximumLength = decodeXuguScale(item.DataType, scale) @@ -1646,6 +1649,21 @@ func decodeXuguScale(dataType string, scale *int) (*int, *int, *int) { return nil, nil, nil } +func normalizeXuguColumnType(dataType string, varying any) string { + upper := strings.ToUpper(strings.TrimSpace(dataType)) + if !truthy(varying) { + return dataType + } + switch upper { + case "CHAR": + return "VARCHAR" + case "BINARY": + return "VARBINARY" + default: + return dataType + } +} + var quotedIdentifierRegexp = regexp.MustCompile(`"([^"]+)"`) func parseQuotedIdentifiers(value string) []string { diff --git a/agents/drivers/xugu/main_test.go b/agents/drivers/xugu/main_test.go index b32c3f11a..95b40e09a 100644 --- a/agents/drivers/xugu/main_test.go +++ b/agents/drivers/xugu/main_test.go @@ -347,7 +347,7 @@ func TestPrimaryKeySQLUsesLowPrivilegeDictionary(t *testing.T) { func TestColumnSQLUsesLowPrivilegeDictionary(t *testing.T) { sqlText := strings.ToUpper(xuguListColumnsSQL) - for _, want := range []string{"ALL_COLUMNS", "ALL_TABLES", "ALL_SCHEMAS", "COMMENTS"} { + for _, want := range []string{"ALL_COLUMNS", "ALL_TABLES", "ALL_SCHEMAS", "COMMENTS", `"VARYING"`} { if !strings.Contains(sqlText, want) { t.Fatalf("column listing should query %s, got: %s", want, xuguListColumnsSQL) } @@ -405,6 +405,29 @@ func TestDecodeXuguScale(t *testing.T) { } } +func TestNormalizeXuguColumnTypeUsesVaryingFlag(t *testing.T) { + tests := []struct { + name string + dataType string + varying any + want string + }{ + {name: "varying char", dataType: "CHAR", varying: true, want: "VARCHAR"}, + {name: "fixed char", dataType: "CHAR", varying: false, want: "CHAR"}, + {name: "varying binary", dataType: "BINARY", varying: true, want: "VARBINARY"}, + {name: "fixed binary", dataType: "BINARY", varying: false, want: "BINARY"}, + {name: "other varying type", dataType: "NUMERIC", varying: true, want: "NUMERIC"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := normalizeXuguColumnType(tt.dataType, tt.varying); got != tt.want { + t.Fatalf("normalizeXuguColumnType(%q, %v) = %q, want %q", tt.dataType, tt.varying, got, tt.want) + } + }) + } +} + func TestAppendDDLStatement(t *testing.T) { got := appendDDLStatement("CREATE TABLE \"T\" (\"ID\" INT)\n", "CREATE INDEX \"IDX\" ON \"T\"(\"ID\");") want := "CREATE TABLE \"T\" (\"ID\" INT);\n\nCREATE INDEX \"IDX\" ON \"T\"(\"ID\");"