Skip to content

Commit f900e42

Browse files
yuqi1129claude
andcommitted
[#10519] fix(postgresql): handle unconstrained NUMERIC type with precision=0
Map unconstrained NUMERIC (no precision/scale) columns to DECIMAL(38, 18) instead of throwing IllegalArgumentException. PostgreSQL JDBC metadata returns columnSize=0 for NUMERIC columns without explicit precision, which was passed directly to Types.DecimalType.of() causing a validation failure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e0572b1 commit f900e42

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/converter/PostgreSqlTypeConverter.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,23 @@ public Type toGravitino(JdbcTypeBean typeBean) {
7676
.map(Types.TimestampType::withTimeZone)
7777
.orElseGet(Types.TimestampType::withTimeZone);
7878
case NUMERIC:
79-
return Types.DecimalType.of(typeBean.getColumnSize(), typeBean.getScale());
79+
Integer columnSize = typeBean.getColumnSize();
80+
Integer scale = typeBean.getScale();
81+
// Unconstrained NUMERIC (no precision/scale) — PostgreSQL JDBC returns columnSize=0.
82+
// Use ExternalType to preserve arbitrary-precision semantics (backed by BigDecimal).
83+
if (columnSize == null || columnSize == 0) {
84+
return Types.ExternalType.of(NUMERIC);
85+
}
86+
int effectiveScale = scale != null ? scale : 0;
87+
// NUMERIC(P, 0) with small P can be represented as integer types for better performance.
88+
if (effectiveScale == 0) {
89+
if (columnSize < 10) {
90+
return Types.IntegerType.get();
91+
} else if (columnSize < 19) {
92+
return Types.LongType.get();
93+
}
94+
}
95+
return Types.DecimalType.of(columnSize, effectiveScale);
8096
case VARCHAR:
8197
return typeBean.getColumnSize() == null
8298
? Types.StringType.get()

catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/converter/TestPostgreSqlTypeConverter.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ public void testToGravitinoType() {
6868
checkJdbcTypeToGravitinoType(Types.TimestampType.withoutTimeZone(3), TIMESTAMP, 23, null, 3);
6969
checkJdbcTypeToGravitinoType(Types.TimestampType.withoutTimeZone(6), TIMESTAMP, 26, null, 6);
7070
checkJdbcTypeToGravitinoType(Types.DecimalType.of(10, 2), NUMERIC, 10, 2, 0);
71+
// Unconstrained NUMERIC (no precision) returns columnSize=0 from JDBC metadata;
72+
// mapped to ExternalType to preserve arbitrary-precision semantics (BigDecimal).
73+
checkJdbcTypeToGravitinoType(Types.ExternalType.of(NUMERIC), NUMERIC, 0, 0, 0);
74+
checkJdbcTypeToGravitinoType(Types.ExternalType.of(NUMERIC), NUMERIC, null, null, 0);
75+
// NUMERIC(P, 0) with small P is mapped to integer types for better performance.
76+
checkJdbcTypeToGravitinoType(Types.IntegerType.get(), NUMERIC, 9, 0, 0);
77+
checkJdbcTypeToGravitinoType(Types.LongType.get(), NUMERIC, 18, 0, 0);
78+
checkJdbcTypeToGravitinoType(Types.DecimalType.of(20, 0), NUMERIC, 20, 0, 0);
7179
checkJdbcTypeToGravitinoType(Types.VarCharType.of(20), VARCHAR, 20, null, 0);
7280
checkJdbcTypeToGravitinoType(Types.FixedCharType.of(20), BPCHAR, 20, null, 0);
7381
checkJdbcTypeToGravitinoType(Types.StringType.get(), TEXT, null, null, 0);

0 commit comments

Comments
 (0)