This is an automated email from the ASF dual-hosted git repository. dataroaring pushed a commit to branch branch-3.0 in repository https://gitbox.apache.org/repos/asf/doris.git
commit cfd34cebf348a0cf2dce0ea85e72f9b2a203bd94 Author: Lijia Liu <liutang...@yeah.net> AuthorDate: Fri Jun 14 14:20:44 2024 +0800 [BUG](Meta) Fix fe exit by wrong dynamic properties (#28138) ## Proposed changes Issue Number: close #xxx `ALTER TABLE tbl SET ("dynamic_partition.some_words" = "");` will cause fe down. ``` java.lang.NumberFormatException: null at java.lang.Integer.parseInt(Integer.java:620) ~[?:?] at java.lang.Integer.parseInt(Integer.java:776) ~[?:?] at org.apache.doris.catalog.DynamicPartitionProperty.<init>(DynamicPartitionProperty.java:75) ~[palo-fe.jar:3.4.0] at org.apache.doris.catalog.TableProperty.executeBuildDynamicProperty(TableProperty.java:115) ~[palo-fe.jar:3.4.0] at org.apache.doris.catalog.TableProperty.buildProperty(TableProperty.java:82) ~[palo-fe.jar:3.4.0] at org.apache.doris.catalog.Catalog.replayModifyTableProperty(Catalog.java:5646) ~[palo-fe.jar:3.4.0] at org.apache.doris.persist.EditLog.loadJournal(EditLog.java:763) [palo-fe.jar:3.4.0] at org.apache.doris.catalog.Catalog.replayJournal(Catalog.java:2516) [palo-fe.jar:3.4.0] at org.apache.doris.catalog.Catalog$3.runOneCycle(Catalog.java:2299) [palo-fe.jar:3.4.0] at org.apache.doris.common.util.Daemon.run(Daemon.java:116) [palo-fe.jar:3.4.0] ``` <!--Describe your changes.--> Prevent setting incorrect table properties ## Further comments If this is a relatively large or complex change, kick off the discussion at [d...@doris.apache.org](mailto:d...@doris.apache.org) by explaining why you chose the solution you did and what alternatives you considered, etc... --------- Co-authored-by: liutang123 <liuli...@gmail.com> --- .../apache/doris/alter/SchemaChangeHandler.java | 1 + .../analysis/ModifyTablePropertiesClause.java | 4 ++- .../doris/catalog/DynamicPartitionProperty.java | 8 ++++++ .../org/apache/doris/catalog/TableProperty.java | 10 +++++--- .../doris/common/util/DynamicPartitionUtil.java | 20 ++++++++++++++- .../apache/doris/datasource/InternalCatalog.java | 1 + .../apache/doris/alter/SchemaChangeJobV2Test.java | 24 ++++++++++++++++++ .../test_dynamic_partition_failed.groovy | 29 ++++++++++++++++++++++ .../test_dynamic_partition_with_alter.groovy | 5 ++++ 9 files changed, 96 insertions(+), 6 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java b/fe/fe-core/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java index b214afe387e..ab77e242a8a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java +++ b/fe/fe-core/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java @@ -1883,6 +1883,7 @@ public class SchemaChangeHandler extends AlterHandler { sendClearAlterTask(db, olapTable); return; } else if (DynamicPartitionUtil.checkDynamicPartitionPropertiesExist(properties)) { + DynamicPartitionUtil.checkDynamicPartitionPropertyKeysValid(properties); if (!olapTable.dynamicPartitionExists()) { try { DynamicPartitionUtil.checkInputDynamicPartitionProperties(properties, diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java index fd85ad0978e..0895890533a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java @@ -18,6 +18,7 @@ package org.apache.doris.analysis; import org.apache.doris.alter.AlterOpType; +import org.apache.doris.catalog.DynamicPartitionProperty; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.MTMV; import org.apache.doris.catalog.ReplicaAllocation; @@ -71,7 +72,8 @@ public class ModifyTablePropertiesClause extends AlterTableClause { } if (properties.size() != 1 - && !TableProperty.isSamePrefixProperties(properties, TableProperty.DYNAMIC_PARTITION_PROPERTY_PREFIX) + && !TableProperty.isSamePrefixProperties( + properties, DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTY_PREFIX) && !TableProperty.isSamePrefixProperties(properties, PropertyAnalyzer.PROPERTIES_BINLOG_PREFIX)) { throw new AnalysisException( "Can only set one table property(without dynamic partition && binlog) at a time"); diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/DynamicPartitionProperty.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/DynamicPartitionProperty.java index 816bb64e0ad..918b0dc9d55 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/DynamicPartitionProperty.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/DynamicPartitionProperty.java @@ -28,7 +28,10 @@ import org.apache.doris.common.util.TimeUtils; import com.google.common.base.Strings; +import java.util.Arrays; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.TimeZone; import java.util.function.BiConsumer; @@ -52,6 +55,11 @@ public class DynamicPartitionProperty { public static final String STORAGE_POLICY = "dynamic_partition.storage_policy"; public static final String STORAGE_MEDIUM = "dynamic_partition.storage_medium"; + public static final Set<String> DYNAMIC_PARTITION_PROPERTIES = new HashSet<>( + Arrays.asList(TIME_UNIT, START, END, PREFIX, BUCKETS, ENABLE, START_DAY_OF_WEEK, START_DAY_OF_MONTH, + TIME_ZONE, REPLICATION_NUM, REPLICATION_ALLOCATION, CREATE_HISTORY_PARTITION, HISTORY_PARTITION_NUM, + HOT_PARTITION_NUM, RESERVED_HISTORY_PERIODS, STORAGE_POLICY, STORAGE_MEDIUM)); + public static final int MIN_START_OFFSET = Integer.MIN_VALUE; public static final int MAX_END_OFFSET = Integer.MAX_VALUE; public static final int NOT_SET_REPLICATION_NUM = -1; diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java index 8f010eead54..f9625a7506e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java @@ -53,8 +53,6 @@ import java.util.Map; public class TableProperty implements Writable { private static final Logger LOG = LogManager.getLogger(TableProperty.class); - public static final String DYNAMIC_PARTITION_PROPERTY_PREFIX = "dynamic_partition"; - @SerializedName(value = "properties") private Map<String, String> properties; @@ -187,10 +185,14 @@ public class TableProperty implements Writable { private TableProperty executeBuildDynamicProperty() { HashMap<String, String> dynamicPartitionProperties = new HashMap<>(); for (Map.Entry<String, String> entry : properties.entrySet()) { - if (entry.getKey().startsWith(DYNAMIC_PARTITION_PROPERTY_PREFIX)) { + if (entry.getKey().startsWith(DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTY_PREFIX)) { + if (!DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTIES.contains(entry.getKey())) { + LOG.warn("Ignore invalid dynamic property key: {}: value: {}", entry.getKey(), entry.getValue()); + } dynamicPartitionProperties.put(entry.getKey(), entry.getValue()); } } + dynamicPartitionProperty = EnvFactory.getInstance().createDynamicPartitionProperty(dynamicPartitionProperties); return this; } @@ -491,7 +493,7 @@ public class TableProperty implements Writable { public Map<String, String> getOriginDynamicPartitionProperty() { Map<String, String> origProp = Maps.newHashMap(); for (Map.Entry<String, String> entry : properties.entrySet()) { - if (entry.getKey().startsWith(DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTY_PREFIX)) { + if (DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTIES.contains(entry.getKey())) { origProp.put(entry.getKey(), entry.getValue()); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/DynamicPartitionUtil.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/DynamicPartitionUtil.java index 6f001ddb2d4..c03ef1b2017 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/util/DynamicPartitionUtil.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/DynamicPartitionUtil.java @@ -64,6 +64,7 @@ import java.util.Calendar; import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TimeZone; @@ -419,10 +420,27 @@ public class DynamicPartitionUtil { return false; } + public static void checkDynamicPartitionPropertyKeysValid(Map<String, String> properties) throws DdlException { + if (properties == null) { + return; + } + List<String> invalidDynamicPartitionProperties = new LinkedList<>(); + for (String key : properties.keySet()) { + if (key.startsWith(DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTY_PREFIX) + && !DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTIES.contains(key)) { + invalidDynamicPartitionProperties.add(key); + } + } + if (!invalidDynamicPartitionProperties.isEmpty()) { + throw new DdlException("Invalid dynamic partition properties: " + + String.join(", ", invalidDynamicPartitionProperties)); + } + } + // Check if all requried properties has been set. // And also check all optional properties, if not set, set them to default value. public static boolean checkInputDynamicPartitionProperties(Map<String, String> properties, - OlapTable olapTable) throws DdlException { + OlapTable olapTable) throws DdlException { if (properties == null || properties.isEmpty()) { return false; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java index 4bc21b27347..5a2a8c48793 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java @@ -2813,6 +2813,7 @@ public class InternalCatalog implements CatalogIf<Database> { // and then check if there still has unknown properties olapTable.setStorageMedium(dataProperty.getStorageMedium()); if (partitionInfo.getType() == PartitionType.RANGE) { + DynamicPartitionUtil.checkDynamicPartitionPropertyKeysValid(properties); DynamicPartitionUtil.checkAndSetDynamicPartitionProperty(olapTable, properties, db); } else if (partitionInfo.getType() == PartitionType.LIST) { if (DynamicPartitionUtil.checkDynamicPartitionPropertiesExist(properties)) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/alter/SchemaChangeJobV2Test.java b/fe/fe-core/src/test/java/org/apache/doris/alter/SchemaChangeJobV2Test.java index 6db68473bdb..4ae7d2775e3 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/alter/SchemaChangeJobV2Test.java +++ b/fe/fe-core/src/test/java/org/apache/doris/alter/SchemaChangeJobV2Test.java @@ -389,6 +389,30 @@ public class SchemaChangeJobV2Test { modifyDynamicPartitionWithoutTableProperty(DynamicPartitionProperty.BUCKETS, "30"); } + @Test + public void testModifyDynamicPartitionWithInvalidProperty() throws UserException { + fakeEnv = new FakeEnv(); + fakeEditLog = new FakeEditLog(); + FakeEnv.setEnv(masterEnv); + SchemaChangeHandler schemaChangeHandler = Env.getCurrentEnv().getSchemaChangeHandler(); + ArrayList<AlterClause> alterClauses = new ArrayList<>(); + Map<String, String> properties = new HashMap<>(); + properties.put(DynamicPartitionProperty.ENABLE, "true"); + properties.put(DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTY_PREFIX + "time_uint", "day"); + properties.put(DynamicPartitionProperty.DYNAMIC_PARTITION_PROPERTY_PREFIX + "edn", "3"); + properties.put(DynamicPartitionProperty.PREFIX, "p"); + properties.put(DynamicPartitionProperty.BUCKETS, "30"); + properties.put("invalid_property", "invalid_value"); + alterClauses.add(new ModifyTablePropertiesClause(properties)); + + Database db = CatalogMocker.mockDb(); + OlapTable olapTable = (OlapTable) db.getTableOrDdlException(CatalogMocker.TEST_TBL2_ID); + expectedEx.expect(DdlException.class); + expectedEx.expectMessage("errCode = 2," + + " detailMessage = Invalid dynamic partition properties: dynamic_partition.time_uint, dynamic_partition.edn"); + schemaChangeHandler.process(alterClauses, db, olapTable); + } + @Test public void testSerializeOfSchemaChangeJob() throws IOException { // prepare file diff --git a/regression-test/suites/partition_p0/dynamic_partition/test_dynamic_partition_failed.groovy b/regression-test/suites/partition_p0/dynamic_partition/test_dynamic_partition_failed.groovy index 7da145a36bc..a19efadf740 100644 --- a/regression-test/suites/partition_p0/dynamic_partition/test_dynamic_partition_failed.groovy +++ b/regression-test/suites/partition_p0/dynamic_partition/test_dynamic_partition_failed.groovy @@ -65,10 +65,39 @@ suite('test_dynamic_partition_failed', 'nonConcurrent') { // 'date/datetime literal [+271768-09-11 00:00:00] is invalid' assertTrue(msg.contains('date/datetime literal') && msg.contains('is invalid')) } + + } + + sql 'DROP TABLE IF EXISTS test_dynamic_partition_failed_3' + test { + sql '''CREATE TABLE test_dynamic_partition_failed_3 + ( `k1` datetime NULL ) + PARTITION BY RANGE (k1)() + DISTRIBUTED BY HASH(`k1`) BUCKETS 1 + PROPERTIES + ( + "replication_num" = "1", + "dynamic_partition.enable" = "true", + "dynamic_partition.end" = "3", + "dynamic_partition.time_uint" = "day", + "dynamic_partition.prefix" = "p", + "dynamic_partition.buckets" = "1", + "dynamic_partition.start" = "2024-06-11", + "dynamic_partition.edn" = "2024-06-13", + "dynamic_partition.create_history_partition" = "true" + )''' + check { result, exception, startTime, endTime -> + assertNotNull(exception) + def msg = exception.toString() + logger.info("exception: " + msg) + // 'Invalid dynamic partition properties: dynamic_partition.time_uint, dynamic_partition.edn' + assertTrue(msg.contains('Invalid dynamic partition properties: dynamic_partition.time_uint, dynamic_partition.edn')) + } } } finally { setFeConfig('max_dynamic_partition_num', old_max_dynamic_partition_num) sql 'DROP TABLE IF EXISTS test_dynamic_partition_failed_1' sql 'DROP TABLE IF EXISTS test_dynamic_partition_failed_2' + sql 'DROP TABLE IF EXISTS test_dynamic_partition_failed_3' } } diff --git a/regression-test/suites/partition_p0/dynamic_partition/test_dynamic_partition_with_alter.groovy b/regression-test/suites/partition_p0/dynamic_partition/test_dynamic_partition_with_alter.groovy index d488a53812f..fe27fdbd77a 100644 --- a/regression-test/suites/partition_p0/dynamic_partition/test_dynamic_partition_with_alter.groovy +++ b/regression-test/suites/partition_p0/dynamic_partition/test_dynamic_partition_with_alter.groovy @@ -48,6 +48,11 @@ suite("test_dynamic_partition_with_alter") { sql "alter table ${tbl} set ('dynamic_partition.start' = '-2147483647')" exception "Too many dynamic partitions" } + + test { + sql "alter table ${tbl} set ('dynamic_partition.time_uint' = 'day')" + exception "Invalid dynamic partition properties: dynamic_partition.time_uint" + } } catch (Exception e) { sql "drop table if exists ${tbl}" throw e --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org