This is an automated email from the ASF dual-hosted git repository.
yuqi1129 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 8d60f23a58 [#11972] fix(clickhouse): strip PROJECTION blocks before
extracting sort key from SHOW CREATE TABLE (#12016)
8d60f23a58 is described below
commit 8d60f23a587c172e3d5c4d32e4e63cf61f7a8b96
Author: StormSpirit <[email protected]>
AuthorDate: Thu Aug 27 22:22:39 2026 +0800
[#11972] fix(clickhouse): strip PROJECTION blocks before extracting sort
key from SHOW CREATE TABLE (#12016)
### What changes were proposed in this pull request?
When a ClickHouse table contains a PROJECTION with its own ORDER BY
clause, Gravitino parses the wrong ORDER BY from the SHOW CREATE TABLE
output and returns incorrect sort keys.
This PR strips PROJECTION definition blocks from the DDL before applying
the existing regex patterns, so the table-level ORDER BY / PARTITION BY
/ SETTINGS clauses are matched correctly.
### Why are the changes needed?
A PROJECTION block sits inside the column-definition body of the DDL:
```sql
CREATE TABLE t (
`id` Int64,
PROJECTION p_normal ( SELECT * ORDER BY dt ),
`dt` Date
)
ENGINE = MergeTree
ORDER BY (id, dt)
```
The projection-internal `ORDER BY dt` appears before the table-level
`ORDER BY (id, dt)`, so `find()` matches the wrong one. This affects any
table with a Normal projection (projections with no ORDER BY, like
Aggregate projections with only GROUP BY, are not affected).
Fixes #11972
### Does this PR introduce _any_ user-facing change?
No. Tables without projections are unaffected. For tables with
projections, `sortOrder()` now returns the correct table-level sort keys
instead of garbled projection-internal content.
### How was this patch tested?
- Unit tests: 19 new tests covering Normal/Aggregate/Multiple
projections, INDEX coexistence, projection at different positions,
string literals containing "PROJECTION", and escaped string literals
inside projection bodies.
- Docker integration tests: 11 tests on real ClickHouse 24.8 covering
inline CREATE, ALTER TABLE ADD PROJECTION, PARTITION BY + PRIMARY KEY,
ReplacingMergeTree, complex sort keys, and projections at all positions.
- Existing tests (SETTINGS, INDEX, type mapping) continue to pass.
---------
Signed-off-by: jiangxt2 <[email protected]>
Co-authored-by: Qi Yu <[email protected]>
---
.../operations/ClickHouseTableOperations.java | 87 +++++++++-----
.../integration/test/CatalogClickHouseIT.java | 40 ++++++-
.../operations/TestClickHouseTableOperations.java | 58 +++-------
.../TestClickHouseTableOperationsUnit.java | 128 ++++++++++++++++++++-
4 files changed, 238 insertions(+), 75 deletions(-)
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
index a5be1b0753..8d7afb9ed5 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
@@ -102,10 +102,6 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
ENGINE.SUMMINGMERGETREE,
ENGINE.COLLAPSINGMERGETREE,
ENGINE.VERSIONEDCOLLAPSINGMERGETREE));
-
- private static final Pattern ORDER_BY_PATTERN =
- Pattern.compile(
-
"(?is)\\bORDER\\s+BY\\s*(.+?)(?=\\bPARTITION\\s+BY\\b|\\bPRIMARY\\s+KEY\\b|\\bSAMPLE\\s+BY\\b|\\bTTL\\b|\\bSETTINGS\\b|\\bCOMMENT\\b|$)");
private static final Pattern PARTITION_BY_PATTERN =
Pattern.compile(
"(?is)\\bPARTITION\\s+BY\\s*(.+?)(?=\\bORDER\\s+BY\\b|\\bPRIMARY\\s+KEY\\b|\\bSAMPLE\\s+BY\\b|\\bTTL\\b|\\bSETTINGS\\b|\\bCOMMENT\\b|$)");
@@ -808,25 +804,28 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
List<Index> indexes = getIndexes(connection, databaseName, tableName);
jdbcTableBuilder.withIndexes(indexes.toArray(new Index[0]));
- ShowCreateTableMetadata metadata = parseShowCreateTable(connection,
tableName);
- Transform[] partitioning = metadata.partitioning;
+ SystemTableMetadata systemTableMetadata =
+ getSystemTableMetadata(connection, databaseName, tableName);
+ ShowCreateTableMetadata showCreateMetadata =
parseShowCreateTable(connection, tableName);
+ Transform[] partitioning = showCreateMetadata.partitioning;
if (ArrayUtils.isEmpty(partitioning)) {
partitioning = getTablePartitioning(connection, databaseName,
tableName);
}
jdbcTableBuilder.withPartitioning(partitioning);
- jdbcTableBuilder.withSortOrders(metadata.sortOrders);
+ jdbcTableBuilder.withSortOrders(systemTableMetadata.sortOrders());
Distribution distribution = getDistributionInfo(connection,
databaseName, tableName);
jdbcTableBuilder.withDistribution(distribution);
Map<String, String> tableProperties = getTableProperties(connection,
tableName);
- // Merge SETTINGS parsed from SHOW CREATE TABLE into table properties.
- // SHOW CREATE TABLE is the authoritative source for SETTINGS; it takes
precedence
+ // Merge SETTINGS parsed from system.tables.engine_full into table
properties.
+ // engine_full contains only table-level storage clauses, so projection
SETTINGS cannot be
+ // mistaken for table SETTINGS. These values take precedence
// over any settings.* keys that might exist in system.tables (though
getTableProperties()
// currently does not read SETTINGS from system.tables, so no overlap
occurs in practice).
- if (!metadata.settings.isEmpty()) {
+ if (!systemTableMetadata.settings().isEmpty()) {
Map<String, String> merged = new HashMap<>(tableProperties);
- merged.putAll(metadata.settings);
+ merged.putAll(systemTableMetadata.settings());
tableProperties = Collections.unmodifiableMap(merged);
}
jdbcTableBuilder.withProperties(tableProperties);
@@ -856,6 +855,26 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
return kinds;
}
+ @VisibleForTesting
+ SystemTableMetadata getSystemTableMetadata(
+ Connection connection, String databaseName, String tableName) throws
SQLException {
+ String sql =
+ "SELECT sorting_key, engine_full FROM system.tables WHERE database = ?
AND name = ?";
+ try (PreparedStatement statement = connection.prepareStatement(sql)) {
+ statement.setString(1, databaseName);
+ statement.setString(2, tableName);
+ try (ResultSet resultSet = statement.executeQuery()) {
+ if (resultSet.next()) {
+ return new SystemTableMetadata(
+ parseOrderByClause(resultSet.getString("sorting_key")),
+ parseSettingsFromEngineFull(resultSet.getString("engine_full")));
+ }
+ }
+ }
+
+ throw new NoSuchTableException("Table %s does not exist in %s.",
tableName, databaseName);
+ }
+
@Override
protected Transform[] getTablePartitioning(
Connection connection, String databaseName, String tableName) throws
SQLException {
@@ -1408,21 +1427,11 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
return metadata;
}
- Matcher orderMatcher = ORDER_BY_PATTERN.matcher(createSql);
- if (orderMatcher.find()) {
- metadata.sortOrders = parseOrderByClause(orderMatcher.group(1));
- }
-
Matcher partitionMatcher = PARTITION_BY_PATTERN.matcher(createSql);
if (partitionMatcher.find()) {
metadata.partitioning = parsePartitioning(partitionMatcher.group(1));
}
- Matcher settingsMatcher = SETTINGS_PATTERN.matcher(createSql);
- if (settingsMatcher.find()) {
- metadata.settings = parseSettingsClause(settingsMatcher.group(1));
- }
-
return metadata;
}
@@ -1446,13 +1455,16 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
}
@VisibleForTesting
- SortOrder[] parseSortOrdersFromCreateSql(String createSql) {
- return parseCreateStatement(createSql).sortOrders;
- }
+ Map<String, String> parseSettingsFromEngineFull(String engineFull) {
+ if (StringUtils.isBlank(engineFull)) {
+ return Collections.emptyMap();
+ }
- @VisibleForTesting
- Map<String, String> parseSettingsFromCreateSql(String createSql) {
- return parseCreateStatement(createSql).settings;
+ Matcher settingsMatcher = SETTINGS_PATTERN.matcher(engineFull);
+ if (settingsMatcher.find()) {
+ return parseSettingsClause(settingsMatcher.group(1));
+ }
+ return Collections.emptyMap();
}
private ShowCreateTableMetadata parseShowCreateTable(Connection connection,
String tableName)
@@ -1571,10 +1583,27 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
return expression.toString();
}
+ @VisibleForTesting
+ static final class SystemTableMetadata {
+ private final SortOrder[] sortOrders;
+ private final Map<String, String> settings;
+
+ private SystemTableMetadata(SortOrder[] sortOrders, Map<String, String>
settings) {
+ this.sortOrders = sortOrders;
+ this.settings = settings;
+ }
+
+ SortOrder[] sortOrders() {
+ return sortOrders;
+ }
+
+ Map<String, String> settings() {
+ return settings;
+ }
+ }
+
private static final class ShowCreateTableMetadata {
private Transform[] partitioning = Transforms.EMPTY_TRANSFORM;
- private SortOrder[] sortOrders = SortOrders.NONE;
- private Map<String, String> settings = Collections.emptyMap();
}
@VisibleForTesting
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
index 6410fc1a51..fcc9c0bf24 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
@@ -476,8 +476,8 @@ public class CatalogClickHouseIT extends BaseIT {
}
@Test
- void testLoadTableFromShowCreateParsing() {
- String name = GravitinoITUtils.genRandomName("show_create_table");
+ void testLoadTableMetadataFromNativeSql() {
+ String name = GravitinoITUtils.genRandomName("native_table_metadata");
clickhouseService.executeQuery(
String.format(
"CREATE TABLE `%s`.`%s` (\n"
@@ -2922,6 +2922,42 @@ public class CatalogClickHouseIT extends BaseIT {
Indexes.EMPTY_INDEXES));
}
+ @Test
+ void testLoadTableWithProjectionUsesTableSortKey() {
+ String name = GravitinoITUtils.genRandomName("proj_normal");
+ clickhouseService.executeQuery(
+ String.format(
+ "CREATE TABLE `%s`.`%s` (\n"
+ + " `id` Int64,\n"
+ + " `dt` Date,\n"
+ + " `val` String,\n"
+ + " PROJECTION p_normal\n"
+ + " (\n"
+ + " SELECT *\n"
+ + " ORDER BY dt\n"
+ + " )\n"
+ + ")\n"
+ + "ENGINE = MergeTree\n"
+ + "ORDER BY (id, dt)\n"
+ + "SETTINGS index_granularity = 8192",
+ schemaName, name));
+
+ Table loaded =
catalog.asTableCatalog().loadTable(NameIdentifier.of(schemaName, name));
+ SortOrder[] sortOrders = loaded.sortOrder();
+
+ Assertions.assertEquals(2, sortOrders.length);
+ Assertions.assertTrue(
+ sortOrders[0].expression() instanceof NamedReference,
+ "First sort key should be a named reference");
+ Assertions.assertArrayEquals(
+ new String[] {"id"}, ((NamedReference)
sortOrders[0].expression()).fieldName());
+ Assertions.assertTrue(sortOrders[1].expression() instanceof
NamedReference);
+ Assertions.assertArrayEquals(
+ new String[] {"dt"}, ((NamedReference)
sortOrders[1].expression()).fieldName());
+ Assertions.assertEquals(
+ "8192", loaded.properties().get(TableConstants.SETTINGS_PREFIX +
"index_granularity"));
+ }
+
@Test
void testEngineParametersRoundTrip() {
// Create a ReplacingMergeTree table with engine parameter via Gravitino
API and verify
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
index 909b5ec81a..5f3fdbd8ea 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
@@ -1362,44 +1362,20 @@ public class TestClickHouseTableOperations extends
TestClickHouse {
}
@Test
- void testParseSortOrdersFromMultilineShowCreateSql() {
- TestableClickHouseTableOperations ops = new
TestableClickHouseTableOperations();
- String showCreateSql =
- """
- CREATE TABLE `t1`
- (
- `id` Int32,
- `event_time` DateTime
- )
- ENGINE = MergeTree
- ORDER BY
- (`id`, toDate(`event_time`))
- SETTINGS index_granularity = 8192
- """;
-
- SortOrder[] sortOrders = ops.parseSortOrders(showCreateSql);
- Assertions.assertEquals(2, sortOrders.length);
- Assertions.assertTrue(sortOrders[0].expression() instanceof
NamedReference);
- Assertions.assertEquals("id", ((NamedReference)
sortOrders[0].expression()).fieldName()[0]);
- }
-
- @Test
- void testParseSettingsFromCreateSql() {
+ void testParseSettingsFromEngineFull() {
TestableClickHouseTableOperations ops = new
TestableClickHouseTableOperations();
// Single setting
- String sql1 =
- "CREATE TABLE t1 (id Int32) ENGINE = MergeTree ORDER BY id SETTINGS
index_granularity = 4096";
- Map<String, String> settings1 = ops.parseSettings(sql1);
+ String engineFull1 = "MergeTree ORDER BY id SETTINGS index_granularity =
4096";
+ Map<String, String> settings1 = ops.parseSettings(engineFull1);
Assertions.assertEquals(1, settings1.size());
Assertions.assertEquals(
"4096", settings1.get(TableConstants.SETTINGS_PREFIX +
"index_granularity"));
// Multiple settings
- String sql2 =
- "CREATE TABLE t2 (id Int32) ENGINE = MergeTree ORDER BY id"
- + " SETTINGS index_granularity = 4096, min_bytes_for_wide_part =
0";
- Map<String, String> settings2 = ops.parseSettings(sql2);
+ String engineFull2 =
+ "MergeTree ORDER BY id" + " SETTINGS index_granularity = 4096,
min_bytes_for_wide_part = 0";
+ Map<String, String> settings2 = ops.parseSettings(engineFull2);
Assertions.assertEquals(2, settings2.size());
Assertions.assertEquals(
"4096", settings2.get(TableConstants.SETTINGS_PREFIX +
"index_granularity"));
@@ -1407,15 +1383,15 @@ public class TestClickHouseTableOperations extends
TestClickHouse {
"0", settings2.get(TableConstants.SETTINGS_PREFIX +
"min_bytes_for_wide_part"));
// No SETTINGS clause
- String sql3 = "CREATE TABLE t3 (id Int32) ENGINE = MergeTree ORDER BY id";
- Map<String, String> settings3 = ops.parseSettings(sql3);
+ String engineFull3 = "MergeTree ORDER BY id";
+ Map<String, String> settings3 = ops.parseSettings(engineFull3);
Assertions.assertTrue(settings3.isEmpty());
- // SETTINGS with COMMENT after
- String sql4 =
- "CREATE TABLE t4 (id Int32) ENGINE = MergeTree ORDER BY id"
- + " SETTINGS index_granularity = 8192 COMMENT 'test'";
- Map<String, String> settings4 = ops.parseSettings(sql4);
+ // Engine arguments before SETTINGS
+ String engineFull4 =
+ "ReplicatedMergeTree('/path', '{replica}') ORDER BY id"
+ + " SETTINGS index_granularity = 8192";
+ Map<String, String> settings4 = ops.parseSettings(engineFull4);
Assertions.assertEquals(1, settings4.size());
Assertions.assertEquals(
"8192", settings4.get(TableConstants.SETTINGS_PREFIX +
"index_granularity"));
@@ -1435,12 +1411,8 @@ public class TestClickHouseTableOperations extends
TestClickHouse {
tableName, columns, comment, properties, partitioning, distribution,
indexes, sortOrders);
}
- SortOrder[] parseSortOrders(String createSql) {
- return parseSortOrdersFromCreateSql(createSql);
- }
-
- Map<String, String> parseSettings(String createSql) {
- return parseSettingsFromCreateSql(createSql);
+ Map<String, String> parseSettings(String engineFull) {
+ return parseSettingsFromEngineFull(engineFull);
}
}
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
index e2cfa0ad07..76d04b4525 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
@@ -32,7 +32,11 @@ import
org.apache.gravitino.catalog.clickhouse.converter.ClickHouseColumnDefault
import
org.apache.gravitino.catalog.clickhouse.converter.ClickHouseExceptionConverter;
import
org.apache.gravitino.catalog.clickhouse.converter.ClickHouseTypeConverter;
import org.apache.gravitino.catalog.jdbc.JdbcColumn;
+import org.apache.gravitino.exceptions.NoSuchTableException;
+import org.apache.gravitino.rel.expressions.FunctionExpression;
+import org.apache.gravitino.rel.expressions.NamedReference;
import org.apache.gravitino.rel.expressions.distributions.Distributions;
+import org.apache.gravitino.rel.expressions.sorts.SortOrder;
import org.apache.gravitino.rel.expressions.transforms.Transforms;
import org.apache.gravitino.rel.indexes.Index;
import org.apache.gravitino.rel.indexes.Indexes;
@@ -50,6 +54,11 @@ public class TestClickHouseTableOperationsUnit {
return getIndexes(connection, databaseName, tableName);
}
+ SystemTableMetadata callGetSystemTableMetadata(
+ Connection connection, String databaseName, String tableName) throws
Exception {
+ return getSystemTableMetadata(connection, databaseName, tableName);
+ }
+
Map<String, String> callGetTableProperties(Connection connection, String
tableName)
throws Exception {
return getTableProperties(connection, tableName);
@@ -129,13 +138,130 @@ public class TestClickHouseTableOperationsUnit {
ops.callGetIndexes(connection, "db'1", "t'1");
- // First captured SQL is the primary-key QUERY_INDEXES_SQL
(string-interpolated).
String primaryKeySql = sqlCaptor.getAllValues().get(0);
Assertions.assertTrue(
primaryKeySql.contains("db''1"), "database single quote should be
doubled");
Assertions.assertTrue(primaryKeySql.contains("t''1"), "table single quote
should be doubled");
}
+ @Test
+ void testGetSystemTableMetadataQueriesExactTable() throws Exception {
+ ExposedClickHouseTableOperations ops = newOps();
+ Connection connection = Mockito.mock(Connection.class);
+ PreparedStatement statement = Mockito.mock(PreparedStatement.class);
+ ResultSet resultSet = Mockito.mock(ResultSet.class);
+ ArgumentCaptor<String> sqlCaptor = ArgumentCaptor.forClass(String.class);
+
+
Mockito.when(connection.prepareStatement(sqlCaptor.capture())).thenReturn(statement);
+ Mockito.when(statement.executeQuery()).thenReturn(resultSet);
+ Mockito.when(resultSet.next()).thenReturn(true);
+ Mockito.when(resultSet.getString("sorting_key")).thenReturn("id");
+ Mockito.when(resultSet.getString("engine_full")).thenReturn("MergeTree
ORDER BY id");
+
+ ClickHouseTableOperations.SystemTableMetadata metadata =
+ ops.callGetSystemTableMetadata(connection, "db_name", "table_name");
+
+ Assertions.assertEquals(
+ "SELECT sorting_key, engine_full FROM system.tables WHERE database = ?
AND name = ?",
+ sqlCaptor.getValue());
+ Mockito.verify(statement).setString(1, "db_name");
+ Mockito.verify(statement).setString(2, "table_name");
+ Assertions.assertEquals(1, metadata.sortOrders().length);
+ Assertions.assertEquals(NamedReference.field("id"),
metadata.sortOrders()[0].expression());
+ Assertions.assertTrue(metadata.settings().isEmpty());
+ Mockito.verify(resultSet).close();
+ Mockito.verify(statement).close();
+ }
+
+ @Test
+ void testGetSystemTableMetadataParsesCompoundAndFunctionExpressions() throws
Exception {
+ ExposedClickHouseTableOperations ops = newOps();
+ Connection connection = Mockito.mock(Connection.class);
+ PreparedStatement statement = Mockito.mock(PreparedStatement.class);
+ ResultSet resultSet = Mockito.mock(ResultSet.class);
+
+
Mockito.when(connection.prepareStatement(Mockito.anyString())).thenReturn(statement);
+ Mockito.when(statement.executeQuery()).thenReturn(resultSet);
+ Mockito.when(resultSet.next()).thenReturn(true);
+ Mockito.when(resultSet.getString("sorting_key")).thenReturn("id,
toDate(event_time)");
+ Mockito.when(resultSet.getString("engine_full")).thenReturn("MergeTree
ORDER BY id");
+
+ SortOrder[] sortOrders =
+ ops.callGetSystemTableMetadata(connection, "db_name",
"table_name").sortOrders();
+
+ Assertions.assertEquals(2, sortOrders.length);
+ Assertions.assertEquals(NamedReference.field("id"),
sortOrders[0].expression());
+ Assertions.assertEquals(
+ FunctionExpression.of("toDate", NamedReference.field("event_time")),
+ sortOrders[1].expression());
+ }
+
+ @Test
+ void testGetSystemTableMetadataReturnsNoneForBlankValues() throws Exception {
+ ExposedClickHouseTableOperations ops = newOps();
+ Connection connection = Mockito.mock(Connection.class);
+ PreparedStatement statement = Mockito.mock(PreparedStatement.class);
+ ResultSet resultSet = Mockito.mock(ResultSet.class);
+
+
Mockito.when(connection.prepareStatement(Mockito.anyString())).thenReturn(statement);
+ Mockito.when(statement.executeQuery()).thenReturn(resultSet);
+ Mockito.when(resultSet.next()).thenReturn(true);
+ Mockito.when(resultSet.getString("sorting_key")).thenReturn(" ");
+ Mockito.when(resultSet.getString("engine_full")).thenReturn(" ");
+
+ ClickHouseTableOperations.SystemTableMetadata metadata =
+ ops.callGetSystemTableMetadata(connection, "db_name", "table_name");
+
+ Assertions.assertArrayEquals(new SortOrder[0], metadata.sortOrders());
+ Assertions.assertTrue(metadata.settings().isEmpty());
+ }
+
+ @Test
+ void testGetSystemTableMetadataParsesSettingsFromEngineFull() throws
Exception {
+ ExposedClickHouseTableOperations ops = newOps();
+ Connection connection = Mockito.mock(Connection.class);
+ PreparedStatement statement = Mockito.mock(PreparedStatement.class);
+ ResultSet resultSet = Mockito.mock(ResultSet.class);
+
+
Mockito.when(connection.prepareStatement(Mockito.anyString())).thenReturn(statement);
+ Mockito.when(statement.executeQuery()).thenReturn(resultSet);
+ Mockito.when(resultSet.next()).thenReturn(true);
+ Mockito.when(resultSet.getString("sorting_key")).thenReturn("id");
+ Mockito.when(resultSet.getString("engine_full"))
+ .thenReturn(
+ "MergeTree ORDER BY id SETTINGS index_granularity = 4096, "
+ + "min_bytes_for_wide_part = 0");
+
+ Map<String, String> settings =
+ ops.callGetSystemTableMetadata(connection, "db_name",
"table_name").settings();
+
+ Assertions.assertEquals(2, settings.size());
+ Assertions.assertEquals(
+ "4096", settings.get(TableConstants.SETTINGS_PREFIX +
"index_granularity"));
+ Assertions.assertEquals(
+ "0", settings.get(TableConstants.SETTINGS_PREFIX +
"min_bytes_for_wide_part"));
+ }
+
+ @Test
+ void testGetSystemTableMetadataThrowsWhenTableIsNotVisible() throws
Exception {
+ ExposedClickHouseTableOperations ops = newOps();
+ Connection connection = Mockito.mock(Connection.class);
+ PreparedStatement statement = Mockito.mock(PreparedStatement.class);
+ ResultSet resultSet = Mockito.mock(ResultSet.class);
+
+
Mockito.when(connection.prepareStatement(Mockito.anyString())).thenReturn(statement);
+ Mockito.when(statement.executeQuery()).thenReturn(resultSet);
+ Mockito.when(resultSet.next()).thenReturn(false);
+
+ NoSuchTableException exception =
+ Assertions.assertThrows(
+ NoSuchTableException.class,
+ () -> ops.callGetSystemTableMetadata(connection, "db_name",
"table_name"));
+
+ Assertions.assertTrue(exception.getMessage().contains("table_name"));
+ Assertions.assertTrue(exception.getMessage().contains("db_name"));
+ }
+
//
---------------------------------------------------------------------------
// extractEngineParams
//
---------------------------------------------------------------------------