diff --git a/apps/desktop/src/lib/__tests__/table/tableStructureEditorState.spec.ts b/apps/desktop/src/lib/__tests__/table/tableStructureEditorState.spec.ts index 763c690b0..476c06c93 100644 --- a/apps/desktop/src/lib/__tests__/table/tableStructureEditorState.spec.ts +++ b/apps/desktop/src/lib/__tests__/table/tableStructureEditorState.spec.ts @@ -28,6 +28,14 @@ describe("tableStructureEditorState", () => { expect(dataTypeLengthInputValue("mysql", "set('manual','auto')")).toBe(""); }); + it("does not expose Oracle-like integer display widths as editable length", () => { + expect(isDataTypeLengthDisabled("dameng", "integer")).toBe(true); + expect(dataTypeLengthInputValue("dameng", "integer(11)")).toBe(""); + expect(combineDataTypeForDatabase("dameng", "integer", "11")).toBe("integer"); + expect(combineDataTypeForDatabase("oracle", "number", "10,0")).toBe("number(10,0)"); + expect(combineDataTypeForDatabase("mysql", "integer", "11")).toBe("integer(11)"); + }); + it("strips SQL Server metadata parentheses from editable defaults", () => { const drafts = createColumnDrafts( [ diff --git a/apps/desktop/src/lib/table/tableStructureEditorState.ts b/apps/desktop/src/lib/table/tableStructureEditorState.ts index ccbb17450..fa9ec06a2 100644 --- a/apps/desktop/src/lib/table/tableStructureEditorState.ts +++ b/apps/desktop/src/lib/table/tableStructureEditorState.ts @@ -423,6 +423,8 @@ export const POSTGRES_TYPE_LENGTH_DISABLES: string[] = [ "xml", ]; +export const ORACLE_LIKE_TYPE_LENGTH_DISABLES: string[] = ["binary_double", "binary_float", "bigint", "boolean", "bool", "byte", "date", "double", "double precision", "float", "integer", "int", "long", "long raw", "nclob", "real", "smallint", "text", "tinyint"]; + export function parseExtraToColumnExtra(extra: string | null | undefined, databaseType?: DatabaseType): ColumnExtra { const result: ColumnExtra = {}; if (!extra) return result; @@ -883,6 +885,10 @@ function isMysqlLikeStructureType(dbType: DatabaseType | undefined): boolean { return dbType === "mysql" || dbType === "doris" || dbType === "starrocks" || dbType === "goldendb" || dbType === "sundb" || dbType === "databend"; } +function isOracleLikeStructureType(dbType: DatabaseType | undefined): boolean { + return dbType === "oracle" || dbType === "dameng" || dbType === "oceanbase-oracle" || dbType === "iris" || dbType === "yashandb" || dbType === "xugu"; +} + function isValidTemporalPrecision(dbType: DatabaseType | undefined, params: string): boolean { if (!/^\d+$/.test(params)) return false; const value = Number(params); @@ -907,6 +913,9 @@ export function isDataTypeLengthDisabled(_dbType: DatabaseType | undefined, base return key !== "bit" && key !== "float_vector"; } else if (_dbType === "postgres" || _dbType === "gaussdb" || _dbType === "kwdb" || _dbType === "opengauss" || _dbType === "highgo" || _dbType === "vastbase" || _dbType === "kingbase") { return POSTGRES_TYPE_LENGTH_DISABLES.includes(key); + } else if (isOracleLikeStructureType(_dbType)) { + // Dameng/Oracle integer aliases have fixed precision; MySQL-style display widths generate invalid DDL. + return ORACLE_LIKE_TYPE_LENGTH_DISABLES.includes(key); } else if (isMysqlLikeStructureType(_dbType)) { return key === "enum" || key === "set"; } else { diff --git a/crates/dbx-core/src/table_structure_sql/column_format.rs b/crates/dbx-core/src/table_structure_sql/column_format.rs index 92f19c2d2..58aac4338 100644 --- a/crates/dbx-core/src/table_structure_sql/column_format.rs +++ b/crates/dbx-core/src/table_structure_sql/column_format.rs @@ -138,6 +138,11 @@ pub(super) fn normalize_column_data_type(dialect: StructureDialect, data_type: & } } + if is_oracle_like(dialect) && is_oracle_lengthless_type(base_type) { + // Dameng/Oracle integer aliases do not accept MySQL-style display widths like INTEGER(11). + return base_type.to_string(); + } + if is_temporal_precision_type(dialect, base_type) { return if is_valid_temporal_precision(params, dialect) { format!("{base_type}({params})") @@ -149,6 +154,32 @@ pub(super) fn normalize_column_data_type(dialect: StructureDialect, data_type: & trimmed.to_string() } +fn is_oracle_lengthless_type(base_type: &str) -> bool { + let normalized = base_type.split_whitespace().collect::>().join(" ").to_ascii_lowercase(); + matches!( + normalized.as_str(), + "binary_double" + | "binary_float" + | "bigint" + | "boolean" + | "bool" + | "byte" + | "date" + | "double" + | "double precision" + | "float" + | "integer" + | "int" + | "long" + | "long raw" + | "nclob" + | "real" + | "smallint" + | "text" + | "tinyint" + ) +} + fn normalize_mysql_numeric_attribute_type(base_type: &str, params: &str) -> Option { let mut parts: Vec<&str> = base_type.split_whitespace().collect(); let type_name = parts.first().copied()?.to_ascii_lowercase(); diff --git a/crates/dbx-core/src/table_structure_sql/tests.rs b/crates/dbx-core/src/table_structure_sql/tests.rs index 3fd2fcafa..017371eb5 100644 --- a/crates/dbx-core/src/table_structure_sql/tests.rs +++ b/crates/dbx-core/src/table_structure_sql/tests.rs @@ -138,6 +138,35 @@ fn builds_mysql_unsigned_integer_column_with_length_before_attribute() { assert_eq!(result.statements, vec!["ALTER TABLE `users` ADD COLUMN `score` int(11) unsigned;"]); } +#[test] +fn dameng_integer_column_omits_mysql_display_width() { + let mut age = column("age"); + age.data_type = "integer(11)".to_string(); + let mut amount = column("amount"); + amount.data_type = "number(10,0)".to_string(); + + let result = build_table_structure_change_sql(TableStructureSqlOptions { + database_type: Some(DatabaseType::Dameng), + schema: Some("SYSDBA".to_string()), + table_name: "users".to_string(), + columns: vec![age, amount], + indexes: Vec::new(), + foreign_keys: Vec::new(), + triggers: Vec::new(), + table_comment: None, + original_table_comment: None, + }); + + assert_eq!(result.warnings, Vec::::new()); + assert_eq!( + result.statements, + vec![ + "ALTER TABLE \"SYSDBA\".\"users\" ADD (\"age\" integer);", + "ALTER TABLE \"SYSDBA\".\"users\" ADD (\"amount\" number(10,0));", + ] + ); +} + #[test] fn builds_highgo_foreign_key_changes_with_postgres_syntax() { let mut old_fk = foreign_key("orders_user_id_fkey", "user_id", "users", "id");