From 3974f25e806c8973cd3cae897d3546e100582184 Mon Sep 17 00:00:00 2001 From: Nevin Zheng Date: Fri, 17 Jul 2026 23:32:27 -0700 Subject: [PATCH 1/5] fix(starrocks): handle timestamp precision safely --- .../converter/StarRocksTypeConverter.java | 13 ++++ .../converter/TestStarRocksTypeConverter.java | 69 +++++++++++++++++++ .../integration/test/CatalogStarRocksIT.java | 42 +++++++++++ ...StarRocksTableOperationsSqlGeneration.java | 33 +++++++++ docs/jdbc-starrocks-catalog.md | 34 +++------ 5 files changed, 168 insertions(+), 23 deletions(-) create mode 100644 catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java diff --git a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java index 1adebd7cf68..1968357e91e 100644 --- a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java @@ -146,6 +146,19 @@ public String fromGravitino(Type type) { } else if (type instanceof Types.DateType) { return DATE; } else if (type instanceof Types.TimestampType) { + Types.TimestampType timestampType = (Types.TimestampType) type; + if (timestampType.hasTimeZone()) { + throw new IllegalArgumentException( + String.format( + "StarRocks DATETIME does not preserve time-zone semantics; cannot convert Gravitino type %s", + type.simpleString())); + } + if (timestampType.hasPrecisionSet()) { + throw new IllegalArgumentException( + String.format( + "StarRocks DATETIME columns do not preserve declared fractional precision; cannot convert Gravitino type %s", + type.simpleString())); + } return DATETIME; } throw new IllegalArgumentException( diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java new file mode 100644 index 00000000000..ac89b98d241 --- /dev/null +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.gravitino.catalog.starrocks.converter; + +import org.apache.gravitino.catalog.jdbc.converter.JdbcTypeConverter; +import org.apache.gravitino.rel.types.Type; +import org.apache.gravitino.rel.types.Types; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class TestStarRocksTypeConverter { + + private static final StarRocksTypeConverter TYPE_CONVERTER = new StarRocksTypeConverter(); + + @Test + void testTimestampMapping() { + Assertions.assertEquals(Types.TimestampType.withoutTimeZone(), toGravitino("datetime", null)); + Assertions.assertEquals(Types.TimestampType.withoutTimeZone(), toGravitino("datetime", 0)); + Assertions.assertEquals(Types.TimestampType.withoutTimeZone(), toGravitino("datetime", 6)); + + Assertions.assertEquals( + "datetime", TYPE_CONVERTER.fromGravitino(Types.TimestampType.withoutTimeZone())); + } + + @Test + void testRejectPrecisionQualifiedTimestampTypes() { + Type[] timestampTypes = { + Types.TimestampType.withoutTimeZone(3), Types.TimestampType.withoutTimeZone(9) + }; + for (Type timestampType : timestampTypes) { + IllegalArgumentException timestampException = + Assertions.assertThrows( + IllegalArgumentException.class, () -> TYPE_CONVERTER.fromGravitino(timestampType)); + Assertions.assertTrue( + timestampException + .getMessage() + .contains( + "StarRocks DATETIME columns do not preserve declared fractional precision")); + } + + IllegalArgumentException timestampTzException = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> TYPE_CONVERTER.fromGravitino(Types.TimestampType.withTimeZone(9))); + Assertions.assertTrue( + timestampTzException + .getMessage() + .contains("StarRocks DATETIME does not preserve time-zone semantics")); + } + + private static Type toGravitino(String typeName, Integer datetimePrecision) { + JdbcTypeConverter.JdbcTypeBean typeBean = new JdbcTypeConverter.JdbcTypeBean(typeName); + typeBean.setDatetimePrecision(datetimePrecision); + return TYPE_CONVERTER.toGravitino(typeBean); + } +} diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java index a314fb52dd0..194a704f41d 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java @@ -74,6 +74,7 @@ import org.apache.gravitino.rel.partitions.Partition; import org.apache.gravitino.rel.partitions.Partitions; import org.apache.gravitino.rel.partitions.RangePartition; +import org.apache.gravitino.rel.types.Type; import org.apache.gravitino.rel.types.Types; import org.apache.gravitino.utils.RandomNameUtils; import org.awaitility.Awaitility; @@ -808,6 +809,22 @@ void testTableWithTimeStampColumn() { Assertions.assertEquals(Types.TimestampType.withoutTimeZone(), timestampColumn.dataType()); } + @Test + void testRejectPrecisionQualifiedTimestampTypesWithoutSideEffects() { + assertCreateRejectedWithoutSideEffects( + "timestamp_3", + Types.TimestampType.withoutTimeZone(3), + "StarRocks DATETIME columns do not preserve declared fractional precision"); + assertCreateRejectedWithoutSideEffects( + "timestamp_ns", + Types.TimestampType.withoutTimeZone(9), + "StarRocks DATETIME columns do not preserve declared fractional precision"); + assertCreateRejectedWithoutSideEffects( + "timestamptz_ns", + Types.TimestampType.withTimeZone(9), + "StarRocks DATETIME does not preserve time-zone semantics"); + } + @Test void testNonPartitionedTable() { // create a non-partitioned table @@ -1000,4 +1017,29 @@ void testColumnDefaultValue() { colDefaultValues[1].defaultValue()); Assertions.assertEquals(DEFAULT_VALUE_OF_CURRENT_TIMESTAMP, colDefaultValues[2].defaultValue()); } + + private void assertCreateRejectedWithoutSideEffects( + String typeName, Type type, String expectedMessage) { + String rejectedTableName = GravitinoITUtils.genRandomName("rejected_" + typeName); + NameIdentifier tableIdentifier = NameIdentifier.of(schemaName, rejectedTableName); + TableCatalog tableCatalog = catalog.asTableCatalog(); + Distribution distribution = Distributions.hash(2, NamedReference.field("unsupported_col")); + + IllegalArgumentException exception = + assertThrows( + IllegalArgumentException.class, + () -> + tableCatalog.createTable( + tableIdentifier, + new Column[] {Column.of("unsupported_col", type)}, + null, + ImmutableMap.of(), + Transforms.EMPTY_TRANSFORM, + distribution, + null, + null)); + + Assertions.assertTrue(exception.getMessage().contains(expectedMessage)); + Assertions.assertFalse(tableCatalog.tableExists(tableIdentifier)); + } } diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java index f8eab07a93f..57ff20faf33 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java @@ -120,4 +120,37 @@ public void testCreateTableWithWhitespaceDefaultValue() { sql.contains("DEFAULT " + converter.fromGravitino(col1.defaultValue())), "Should contain DEFAULT ' ' but was: " + sql); } + + @Test + public void testCreateTableUsesUnparameterizedDatetime() { + TestableStarRocksTableOperations ops = new TestableStarRocksTableOperations(); + JdbcColumn column = + JdbcColumn.builder() + .withName("timestamp_col") + .withType(Types.TimestampType.withoutTimeZone()) + .build(); + Distribution distribution = Distributions.hash(1, NamedReference.field("timestamp_col")); + + String sql = ops.createTableSql("test_table", new JdbcColumn[] {column}, distribution); + + Assertions.assertTrue(sql.contains("`timestamp_col` datetime")); + } + + @Test + public void testCreateTableRejectsPrecisionQualifiedTimestampTypesBeforeSqlGeneration() { + TestableStarRocksTableOperations ops = new TestableStarRocksTableOperations(); + Types.TimestampType[] unsupportedTypes = { + Types.TimestampType.withoutTimeZone(3), + Types.TimestampType.withoutTimeZone(9), + Types.TimestampType.withTimeZone(9) + }; + Distribution distribution = Distributions.hash(1, NamedReference.field("unsupported_col")); + + for (Types.TimestampType type : unsupportedTypes) { + JdbcColumn column = JdbcColumn.builder().withName("unsupported_col").withType(type).build(); + Assertions.assertThrows( + IllegalArgumentException.class, + () -> ops.createTableSql("test_table", new JdbcColumn[] {column}, distribution)); + } + } } diff --git a/docs/jdbc-starrocks-catalog.md b/docs/jdbc-starrocks-catalog.md index a69d808b119..cf1aa28412a 100644 --- a/docs/jdbc-starrocks-catalog.md +++ b/docs/jdbc-starrocks-catalog.md @@ -55,28 +55,8 @@ Gravitino doesn't package the JDBC driver for StarRocks due to licensing issues. ### Driver Version Compatibility -The StarRocks catalog includes driver version compatibility checks for datetime precision calculation: - -- **MySQL Connector/J versions >= 8.0.16**: Full support for datetime precision calculation -- **MySQL Connector/J versions < 8.0.16**: Limited support - datetime precision calculation returns `null` with a warning log - -This limitation affects the following datetime types: -- `DATETIME(p)` - datetime precision - -When using an unsupported driver version, the system will: -1. Continue to work normally with default precision (0) -2. Log a warning message indicating the driver version limitation -3. Return `null` for precision calculations to avoid incorrect results - -**Example warning log:** -``` -WARN: MySQL driver version mysql-connector-java-8.0.11 is below 8.0.16, -columnSize may not be accurate for precision calculation. -Returning null for DATETIME type precision. Driver version: mysql-connector-java-8.0.11 -``` - -**Recommended driver versions:** -- `mysql-connector-java-8.0.16` or higher +Use MySQL Connector/J 8.0.16 or later because older versions can report inaccurate temporal column sizes. +StarRocks 3.3 `DATETIME` column declarations do not carry a fractional-precision parameter, so the connector loads them as unparameterized Gravitino `Timestamp` values regardless of the driver. ### Catalog Operations @@ -129,6 +109,14 @@ Refer to | `String` | `String` | | `Binary` | `Binary` | +#### V3 Type Compatibility + +| Gravitino Type | StarRocks outcome | +|-------------------------------------|-------------------------------------------------------------------------------------------------------------------------| +| `Timestamp(9)` / `Timestamp_tz(9)` | Rejected before DDL. `DATETIME` has no time zone or declared fractional-precision parameter. | + +Although StarRocks 3.3.5 and later can store fractional seconds in `DATETIME` values, its column type cannot preserve a declared Gravitino `Timestamp(p)` precision. +The connector therefore rejects every precision-qualified `Timestamp(p)`; native fractional-precision metadata support remains separate Phase 3 work. StarRocks doesn't support Gravitino `Fixed` `Timestamp_tz` `IntervalDay` `IntervalYear` `Union` `UUID` type. The data types other than those listed above are mapped to Gravitino's **[Unparsed Type](./manage-relational-metadata-using-gravitino.md#unparsed-type)** that represents an unresolvable data type since 1.0.0. @@ -197,4 +185,4 @@ Please be aware that: execute a schema query immediately after the alteration. Pause briefly after the alteration. Gravitino will surface the schema-alteration status in the schema information in an upcoming release to solve this. -- StarRocks has limited support for [alert table properties](https://docs.starrocks.io/docs/3.3/sql-reference/sql-statements/table_bucket_part_index/ALTER_TABLE/#modify-table-properties), And it suggests modify one property at a time. \ No newline at end of file +- StarRocks has limited support for [alert table properties](https://docs.starrocks.io/docs/3.3/sql-reference/sql-statements/table_bucket_part_index/ALTER_TABLE/#modify-table-properties), And it suggests modify one property at a time. From 05f57a71be5a96bf0f7d2adab9046f256e26e01b Mon Sep 17 00:00:00 2001 From: Nevin Zheng Date: Fri, 17 Jul 2026 23:34:17 -0700 Subject: [PATCH 2/5] fix(starrocks): reject variant type --- .../converter/StarRocksTypeConverter.java | 3 +++ .../converter/TestStarRocksTypeConverter.java | 14 ++++++++++++++ .../integration/test/CatalogStarRocksIT.java | 8 ++++++++ ...stStarRocksTableOperationsSqlGeneration.java | 17 +++++++++++++++++ docs/jdbc-starrocks-catalog.md | 1 + 5 files changed, 43 insertions(+) diff --git a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java index 1968357e91e..bc43dd9d50c 100644 --- a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java @@ -160,6 +160,9 @@ public String fromGravitino(Type type) { type.simpleString())); } return DATETIME; + } else if (type instanceof Types.VariantType) { + throw new IllegalArgumentException( + "StarRocks JSON is not an exact representation of Gravitino Variant; cannot convert Gravitino type variant"); } throw new IllegalArgumentException( String.format("Couldn't convert Gravitino type %s to StarRocks type", type.simpleString())); diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java index ac89b98d241..90562cc321d 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java @@ -61,6 +61,20 @@ void testRejectPrecisionQualifiedTimestampTypes() { .contains("StarRocks DATETIME does not preserve time-zone semantics")); } + @Test + void testRejectVariantType() { + Assertions.assertEquals(Types.ExternalType.of("json"), toGravitino("json", null)); + + IllegalArgumentException exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> TYPE_CONVERTER.fromGravitino(Types.VariantType.get())); + Assertions.assertTrue( + exception + .getMessage() + .contains("StarRocks JSON is not an exact representation of Gravitino Variant")); + } + private static Type toGravitino(String typeName, Integer datetimePrecision) { JdbcTypeConverter.JdbcTypeBean typeBean = new JdbcTypeConverter.JdbcTypeBean(typeName); typeBean.setDatetimePrecision(datetimePrecision); diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java index 194a704f41d..1c55e5468f3 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java @@ -825,6 +825,14 @@ void testRejectPrecisionQualifiedTimestampTypesWithoutSideEffects() { "StarRocks DATETIME does not preserve time-zone semantics"); } + @Test + void testRejectVariantWithoutSideEffects() { + assertCreateRejectedWithoutSideEffects( + "variant", + Types.VariantType.get(), + "StarRocks JSON is not an exact representation of Gravitino Variant"); + } + @Test void testNonPartitionedTable() { // create a non-partitioned table diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java index 57ff20faf33..2bde4168c1c 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java @@ -153,4 +153,21 @@ public void testCreateTableRejectsPrecisionQualifiedTimestampTypesBeforeSqlGener () -> ops.createTableSql("test_table", new JdbcColumn[] {column}, distribution)); } } + + @Test + public void testCreateTableRejectsVariantBeforeSqlGeneration() { + TestableStarRocksTableOperations ops = new TestableStarRocksTableOperations(); + JdbcColumn column = + JdbcColumn.builder().withName("unsupported_col").withType(Types.VariantType.get()).build(); + Distribution distribution = Distributions.hash(1, NamedReference.field("unsupported_col")); + + IllegalArgumentException exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> ops.createTableSql("test_table", new JdbcColumn[] {column}, distribution)); + Assertions.assertTrue( + exception + .getMessage() + .contains("StarRocks JSON is not an exact representation of Gravitino Variant")); + } } diff --git a/docs/jdbc-starrocks-catalog.md b/docs/jdbc-starrocks-catalog.md index cf1aa28412a..44c2b78232c 100644 --- a/docs/jdbc-starrocks-catalog.md +++ b/docs/jdbc-starrocks-catalog.md @@ -114,6 +114,7 @@ Refer to | Gravitino Type | StarRocks outcome | |-------------------------------------|-------------------------------------------------------------------------------------------------------------------------| | `Timestamp(9)` / `Timestamp_tz(9)` | Rejected before DDL. `DATETIME` has no time zone or declared fractional-precision parameter. | +| `Variant` | Rejected before DDL. Native `JSON` columns load as `External` because JSON is not an exact Variant representation. | Although StarRocks 3.3.5 and later can store fractional seconds in `DATETIME` values, its column type cannot preserve a declared Gravitino `Timestamp(p)` precision. The connector therefore rejects every precision-qualified `Timestamp(p)`; native fractional-precision metadata support remains separate Phase 3 work. From dd3584b304b4916d0713b24f28259eb9983f1276 Mon Sep 17 00:00:00 2001 From: Nevin Zheng Date: Fri, 17 Jul 2026 23:35:49 -0700 Subject: [PATCH 3/5] fix(starrocks): reject unknown type --- .../converter/StarRocksTypeConverter.java | 3 +++ .../converter/TestStarRocksTypeConverter.java | 14 ++++++++++++++ .../integration/test/CatalogStarRocksIT.java | 8 ++++++++ ...stStarRocksTableOperationsSqlGeneration.java | 17 +++++++++++++++++ docs/jdbc-starrocks-catalog.md | 1 + 5 files changed, 43 insertions(+) diff --git a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java index bc43dd9d50c..d949ad7dcbf 100644 --- a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java @@ -163,6 +163,9 @@ public String fromGravitino(Type type) { } else if (type instanceof Types.VariantType) { throw new IllegalArgumentException( "StarRocks JSON is not an exact representation of Gravitino Variant; cannot convert Gravitino type variant"); + } else if (type instanceof Types.NullType) { + throw new IllegalArgumentException( + "StarRocks table columns cannot represent Gravitino Unknown (NullType); cannot convert Gravitino type null"); } throw new IllegalArgumentException( String.format("Couldn't convert Gravitino type %s to StarRocks type", type.simpleString())); diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java index 90562cc321d..34f3d259ba6 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java @@ -75,6 +75,20 @@ void testRejectVariantType() { .contains("StarRocks JSON is not an exact representation of Gravitino Variant")); } + @Test + void testRejectUnknownType() { + Assertions.assertEquals(Types.ExternalType.of("unknown"), toGravitino("unknown", null)); + + IllegalArgumentException exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> TYPE_CONVERTER.fromGravitino(Types.NullType.get())); + Assertions.assertTrue( + exception + .getMessage() + .contains("StarRocks table columns cannot represent Gravitino Unknown (NullType)")); + } + private static Type toGravitino(String typeName, Integer datetimePrecision) { JdbcTypeConverter.JdbcTypeBean typeBean = new JdbcTypeConverter.JdbcTypeBean(typeName); typeBean.setDatetimePrecision(datetimePrecision); diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java index 1c55e5468f3..b8f8e2b2af4 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java @@ -833,6 +833,14 @@ void testRejectVariantWithoutSideEffects() { "StarRocks JSON is not an exact representation of Gravitino Variant"); } + @Test + void testRejectUnknownWithoutSideEffects() { + assertCreateRejectedWithoutSideEffects( + "unknown", + Types.NullType.get(), + "StarRocks table columns cannot represent Gravitino Unknown (NullType)"); + } + @Test void testNonPartitionedTable() { // create a non-partitioned table diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java index 2bde4168c1c..dd94a680c69 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java @@ -170,4 +170,21 @@ public void testCreateTableRejectsVariantBeforeSqlGeneration() { .getMessage() .contains("StarRocks JSON is not an exact representation of Gravitino Variant")); } + + @Test + public void testCreateTableRejectsUnknownBeforeSqlGeneration() { + TestableStarRocksTableOperations ops = new TestableStarRocksTableOperations(); + JdbcColumn column = + JdbcColumn.builder().withName("unsupported_col").withType(Types.NullType.get()).build(); + Distribution distribution = Distributions.hash(1, NamedReference.field("unsupported_col")); + + IllegalArgumentException exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> ops.createTableSql("test_table", new JdbcColumn[] {column}, distribution)); + Assertions.assertTrue( + exception + .getMessage() + .contains("StarRocks table columns cannot represent Gravitino Unknown (NullType)")); + } } diff --git a/docs/jdbc-starrocks-catalog.md b/docs/jdbc-starrocks-catalog.md index 44c2b78232c..97150f4c9e5 100644 --- a/docs/jdbc-starrocks-catalog.md +++ b/docs/jdbc-starrocks-catalog.md @@ -115,6 +115,7 @@ Refer to |-------------------------------------|-------------------------------------------------------------------------------------------------------------------------| | `Timestamp(9)` / `Timestamp_tz(9)` | Rejected before DDL. `DATETIME` has no time zone or declared fractional-precision parameter. | | `Variant` | Rejected before DDL. Native `JSON` columns load as `External` because JSON is not an exact Variant representation. | +| `Unknown` | Rejected before DDL. StarRocks table columns cannot represent an optional, null-only Unknown logical type. | Although StarRocks 3.3.5 and later can store fractional seconds in `DATETIME` values, its column type cannot preserve a declared Gravitino `Timestamp(p)` precision. The connector therefore rejects every precision-qualified `Timestamp(p)`; native fractional-precision metadata support remains separate Phase 3 work. From 69e9f17e009565857ad41f30637da04ac1b20b1c Mon Sep 17 00:00:00 2001 From: Nevin Zheng Date: Fri, 17 Jul 2026 23:37:21 -0700 Subject: [PATCH 4/5] fix(starrocks): reject geometry type --- .../converter/StarRocksTypeConverter.java | 5 +++++ .../converter/TestStarRocksTypeConverter.java | 14 +++++++++++++ .../integration/test/CatalogStarRocksIT.java | 8 ++++++++ ...StarRocksTableOperationsSqlGeneration.java | 20 +++++++++++++++++++ docs/jdbc-starrocks-catalog.md | 1 + 5 files changed, 48 insertions(+) diff --git a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java index d949ad7dcbf..5e71c556e22 100644 --- a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java @@ -166,6 +166,11 @@ public String fromGravitino(Type type) { } else if (type instanceof Types.NullType) { throw new IllegalArgumentException( "StarRocks table columns cannot represent Gravitino Unknown (NullType); cannot convert Gravitino type null"); + } else if (type instanceof Types.GeometryType) { + throw new IllegalArgumentException( + String.format( + "StarRocks has no storable GEOMETRY column type with CRS metadata; cannot convert Gravitino type %s", + type.simpleString())); } throw new IllegalArgumentException( String.format("Couldn't convert Gravitino type %s to StarRocks type", type.simpleString())); diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java index 34f3d259ba6..3296b340cf0 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java @@ -89,6 +89,20 @@ void testRejectUnknownType() { .contains("StarRocks table columns cannot represent Gravitino Unknown (NullType)")); } + @Test + void testRejectGeometryType() { + Assertions.assertEquals(Types.ExternalType.of("geometry"), toGravitino("geometry", null)); + + IllegalArgumentException exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> TYPE_CONVERTER.fromGravitino(Types.GeometryType.of("EPSG:3857"))); + Assertions.assertTrue( + exception + .getMessage() + .contains("StarRocks has no storable GEOMETRY column type with CRS metadata")); + } + private static Type toGravitino(String typeName, Integer datetimePrecision) { JdbcTypeConverter.JdbcTypeBean typeBean = new JdbcTypeConverter.JdbcTypeBean(typeName); typeBean.setDatetimePrecision(datetimePrecision); diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java index b8f8e2b2af4..5891f6e3634 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java @@ -841,6 +841,14 @@ void testRejectUnknownWithoutSideEffects() { "StarRocks table columns cannot represent Gravitino Unknown (NullType)"); } + @Test + void testRejectGeometryWithoutSideEffects() { + assertCreateRejectedWithoutSideEffects( + "geometry", + Types.GeometryType.of("EPSG:3857"), + "StarRocks has no storable GEOMETRY column type with CRS metadata"); + } + @Test void testNonPartitionedTable() { // create a non-partitioned table diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java index dd94a680c69..b4e622b33b2 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java @@ -187,4 +187,24 @@ public void testCreateTableRejectsUnknownBeforeSqlGeneration() { .getMessage() .contains("StarRocks table columns cannot represent Gravitino Unknown (NullType)")); } + + @Test + public void testCreateTableRejectsGeometryBeforeSqlGeneration() { + TestableStarRocksTableOperations ops = new TestableStarRocksTableOperations(); + JdbcColumn column = + JdbcColumn.builder() + .withName("unsupported_col") + .withType(Types.GeometryType.of("EPSG:3857")) + .build(); + Distribution distribution = Distributions.hash(1, NamedReference.field("unsupported_col")); + + IllegalArgumentException exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> ops.createTableSql("test_table", new JdbcColumn[] {column}, distribution)); + Assertions.assertTrue( + exception + .getMessage() + .contains("StarRocks has no storable GEOMETRY column type with CRS metadata")); + } } diff --git a/docs/jdbc-starrocks-catalog.md b/docs/jdbc-starrocks-catalog.md index 97150f4c9e5..62741fd10a9 100644 --- a/docs/jdbc-starrocks-catalog.md +++ b/docs/jdbc-starrocks-catalog.md @@ -116,6 +116,7 @@ Refer to | `Timestamp(9)` / `Timestamp_tz(9)` | Rejected before DDL. `DATETIME` has no time zone or declared fractional-precision parameter. | | `Variant` | Rejected before DDL. Native `JSON` columns load as `External` because JSON is not an exact Variant representation. | | `Unknown` | Rejected before DDL. StarRocks table columns cannot represent an optional, null-only Unknown logical type. | +| `Geometry` | Rejected before DDL. Spatial functions produce transient geometry values, but no storable column type carries CRS metadata. | Although StarRocks 3.3.5 and later can store fractional seconds in `DATETIME` values, its column type cannot preserve a declared Gravitino `Timestamp(p)` precision. The connector therefore rejects every precision-qualified `Timestamp(p)`; native fractional-precision metadata support remains separate Phase 3 work. From 9240275ae030be541af2386f3c5af921837e0e43 Mon Sep 17 00:00:00 2001 From: Nevin Zheng Date: Fri, 17 Jul 2026 23:38:42 -0700 Subject: [PATCH 5/5] fix(starrocks): reject geography type --- .../converter/StarRocksTypeConverter.java | 5 +++++ .../converter/TestStarRocksTypeConverter.java | 15 +++++++++++++ .../integration/test/CatalogStarRocksIT.java | 8 +++++++ ...StarRocksTableOperationsSqlGeneration.java | 21 +++++++++++++++++++ docs/jdbc-starrocks-catalog.md | 1 + 5 files changed, 50 insertions(+) diff --git a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java index 5e71c556e22..9a061493890 100644 --- a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/converter/StarRocksTypeConverter.java @@ -171,6 +171,11 @@ public String fromGravitino(Type type) { String.format( "StarRocks has no storable GEOMETRY column type with CRS metadata; cannot convert Gravitino type %s", type.simpleString())); + } else if (type instanceof Types.GeographyType) { + throw new IllegalArgumentException( + String.format( + "StarRocks has no storable GEOGRAPHY column type with CRS and edge-algorithm metadata; cannot convert Gravitino type %s", + type.simpleString())); } throw new IllegalArgumentException( String.format("Couldn't convert Gravitino type %s to StarRocks type", type.simpleString())); diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java index 3296b340cf0..d3610d9f02d 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/converter/TestStarRocksTypeConverter.java @@ -103,6 +103,21 @@ void testRejectGeometryType() { .contains("StarRocks has no storable GEOMETRY column type with CRS metadata")); } + @Test + void testRejectGeographyType() { + Assertions.assertEquals(Types.ExternalType.of("geography"), toGravitino("geography", null)); + + IllegalArgumentException exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> TYPE_CONVERTER.fromGravitino(Types.GeographyType.of("EPSG:4326", "karney"))); + Assertions.assertTrue( + exception + .getMessage() + .contains( + "StarRocks has no storable GEOGRAPHY column type with CRS and edge-algorithm metadata")); + } + private static Type toGravitino(String typeName, Integer datetimePrecision) { JdbcTypeConverter.JdbcTypeBean typeBean = new JdbcTypeConverter.JdbcTypeBean(typeName); typeBean.setDatetimePrecision(datetimePrecision); diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java index 5891f6e3634..bb40cd67fd5 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/integration/test/CatalogStarRocksIT.java @@ -849,6 +849,14 @@ void testRejectGeometryWithoutSideEffects() { "StarRocks has no storable GEOMETRY column type with CRS metadata"); } + @Test + void testRejectGeographyWithoutSideEffects() { + assertCreateRejectedWithoutSideEffects( + "geography", + Types.GeographyType.of("EPSG:4326", "karney"), + "StarRocks has no storable GEOGRAPHY column type with CRS and edge-algorithm metadata"); + } + @Test void testNonPartitionedTable() { // create a non-partitioned table diff --git a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java index b4e622b33b2..27a990e82e3 100644 --- a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java +++ b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java @@ -207,4 +207,25 @@ public void testCreateTableRejectsGeometryBeforeSqlGeneration() { .getMessage() .contains("StarRocks has no storable GEOMETRY column type with CRS metadata")); } + + @Test + public void testCreateTableRejectsGeographyBeforeSqlGeneration() { + TestableStarRocksTableOperations ops = new TestableStarRocksTableOperations(); + JdbcColumn column = + JdbcColumn.builder() + .withName("unsupported_col") + .withType(Types.GeographyType.of("EPSG:4326", "karney")) + .build(); + Distribution distribution = Distributions.hash(1, NamedReference.field("unsupported_col")); + + IllegalArgumentException exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> ops.createTableSql("test_table", new JdbcColumn[] {column}, distribution)); + Assertions.assertTrue( + exception + .getMessage() + .contains( + "StarRocks has no storable GEOGRAPHY column type with CRS and edge-algorithm metadata")); + } } diff --git a/docs/jdbc-starrocks-catalog.md b/docs/jdbc-starrocks-catalog.md index 62741fd10a9..40cc824c4b7 100644 --- a/docs/jdbc-starrocks-catalog.md +++ b/docs/jdbc-starrocks-catalog.md @@ -117,6 +117,7 @@ Refer to | `Variant` | Rejected before DDL. Native `JSON` columns load as `External` because JSON is not an exact Variant representation. | | `Unknown` | Rejected before DDL. StarRocks table columns cannot represent an optional, null-only Unknown logical type. | | `Geometry` | Rejected before DDL. Spatial functions produce transient geometry values, but no storable column type carries CRS metadata. | +| `Geography` | Rejected before DDL. StarRocks has no storable column type carrying both CRS and edge-algorithm metadata. | Although StarRocks 3.3.5 and later can store fractional seconds in `DATETIME` values, its column type cannot preserve a declared Gravitino `Timestamp(p)` precision. The connector therefore rejects every precision-qualified `Timestamp(p)`; native fractional-precision metadata support remains separate Phase 3 work.