Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public class ClickHouseTableOperations extends JdbcTableOperations {
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|$)");
private static final Pattern SETTINGS_PATTERN =
Pattern.compile("(?is)\\bSETTINGS\\s+(.+?)(?=\\bCOMMENT\\b|$)");
private static final Pattern DISTRIBUTED_ENGINE_PATTERN =
Pattern.compile(
"(?i)^Distributed\\(([^,]+),\\s*([^,]+),\\s*([^,]+),\\s*(.+)\\)$", Pattern.DOTALL);
Expand Down Expand Up @@ -614,6 +616,15 @@ public JdbcTable load(String databaseName, String tableName) throws NoSuchTableE
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
// 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()) {
Map<String, String> merged = new HashMap<>(tableProperties);
merged.putAll(metadata.settings);
tableProperties = Collections.unmodifiableMap(merged);
}
jdbcTableBuilder.withProperties(tableProperties);

correctJdbcTableFields(connection, databaseName, tableName, jdbcTableBuilder);
Expand Down Expand Up @@ -1101,14 +1112,43 @@ private ShowCreateTableMetadata parseCreateStatement(String createSql) {
metadata.partitioning = parsePartitioning(partitionMatcher.group(1));
}

Matcher settingsMatcher = SETTINGS_PATTERN.matcher(createSql);
if (settingsMatcher.find()) {
metadata.settings = parseSettingsClause(settingsMatcher.group(1));
}

return metadata;
}

// Parses "key1 = val1, key2 = val2" from a SETTINGS clause.
// Keys are prefixed with "settings." to match the write path convention in
// appendTableProperties(). ClickHouse SETTINGS values are scalar (UInt64, Bool,
// String, Enum) — arrays or nested structures are not valid SETTINGS values,
// so splitting by comma is safe.
private static Map<String, String> parseSettingsClause(String settingsStr) {
Map<String, String> settings = new HashMap<>();
for (String pair : settingsStr.split(",")) {
String trimmed = pair.trim();
int eqIdx = trimmed.indexOf('=');
if (eqIdx > 0) {
String key = trimmed.substring(0, eqIdx).trim();
String value = trimmed.substring(eqIdx + 1).trim();
settings.put(TableConstants.SETTINGS_PREFIX + key, value);
}
}
return settings;
}

@VisibleForTesting
SortOrder[] parseSortOrdersFromCreateSql(String createSql) {
return parseCreateStatement(createSql).sortOrders;
}

@VisibleForTesting
Map<String, String> parseSettingsFromCreateSql(String createSql) {
return parseCreateStatement(createSql).settings;
}

private ShowCreateTableMetadata parseShowCreateTable(Connection connection, String tableName)
throws SQLException {
String createSql = parseShowCreateTableSql(connection, tableName);
Expand Down Expand Up @@ -1228,6 +1268,7 @@ private String toOrderBySql(Expression expression) {
private static final class ShowCreateTableMetadata {
private Transform[] partitioning = Transforms.EMPTY_TRANSFORM;
private SortOrder[] sortOrders = SortOrders.NONE;
private Map<String, String> settings = Collections.emptyMap();
}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,40 @@ void testParseSortOrdersFromMultilineShowCreateSql() {
Assertions.assertEquals("id", ((NamedReference) sortOrders[0].expression()).fieldName()[0]);
}

@Test
void testParseSettingsFromCreateSql() {
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);
Assertions.assertEquals(1, settings1.size());
Assertions.assertEquals("4096", settings1.get("settings.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);
Assertions.assertEquals(2, settings2.size());
Assertions.assertEquals("4096", settings2.get("settings.index_granularity"));
Assertions.assertEquals("0", settings2.get("settings.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);
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);
Assertions.assertEquals(1, settings4.size());
Assertions.assertEquals("8192", settings4.get("settings.index_granularity"));
}

private static final class TestableClickHouseTableOperations extends ClickHouseTableOperations {
String buildCreateSql(
String tableName,
Expand All @@ -1211,6 +1245,10 @@ String buildCreateSql(
SortOrder[] parseSortOrders(String createSql) {
return parseSortOrdersFromCreateSql(createSql);
}

Map<String, String> parseSettings(String createSql) {
return parseSettingsFromCreateSql(createSql);
}
}

@Test
Expand Down