This is an automated email from the ASF dual-hosted git repository.
pvary pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/master by this push:
new 619603c fix: add and remove partition transform on same column failed
when use v1 metadata (#2691)
619603c is described below
commit 619603c443a200f687284c01d13e5961a920c036
Author: vinson0526 <[email protected]>
AuthorDate: Mon Jun 21 19:28:25 2021 +0800
fix: add and remove partition transform on same column failed when use v1
metadata (#2691)
---
.../apache/iceberg/BaseUpdatePartitionSpec.java | 96 ++++++++++++++++++----
.../apache/iceberg/TestUpdatePartitionSpec.java | 45 ++++++++++
2 files changed, 127 insertions(+), 14 deletions(-)
diff --git a/core/src/main/java/org/apache/iceberg/BaseUpdatePartitionSpec.java
b/core/src/main/java/org/apache/iceberg/BaseUpdatePartitionSpec.java
index e1fe84b..80f8188 100644
--- a/core/src/main/java/org/apache/iceberg/BaseUpdatePartitionSpec.java
+++ b/core/src/main/java/org/apache/iceberg/BaseUpdatePartitionSpec.java
@@ -142,13 +142,26 @@ class BaseUpdatePartitionSpec implements
UpdatePartitionSpec {
PartitionField newField = new PartitionField(
sourceTransform.first(), assignFieldId(), name,
sourceTransform.second());
- checkForRedundantAddedPartitions(newField);
+ if (newField.name() == null) {
+ String partitionName = PartitionSpecVisitor.visit(schema, newField,
PartitionNameGenerator.INSTANCE);
+ newField = new PartitionField(newField.sourceId(), newField.fieldId(),
partitionName, newField.transform());
+ }
+ checkForRedundantAddedPartitions(newField);
transformToAddedField.put(validationKey, newField);
- if (name != null) {
- nameToAddedField.put(name, newField);
+
+ PartitionField existingField = nameToField.get(newField.name());
+ if (existingField != null) {
+ if (isVoidTransform(existingField)) {
+ // rename the old deleted field that is being replaced by the new field
+ renameField(existingField.name(), existingField.name() + "_" +
existingField.fieldId());
+ } else {
+ throw new IllegalArgumentException(String.format("Cannot add duplicate
partition field name: %s", name));
+ }
}
+ nameToAddedField.put(newField.name(), newField);
+
adds.add(newField);
return this;
@@ -192,6 +205,12 @@ class BaseUpdatePartitionSpec implements
UpdatePartitionSpec {
@Override
public BaseUpdatePartitionSpec renameField(String name, String newName) {
+ PartitionField existingField = nameToField.get(newName);
+ if (existingField != null && isVoidTransform(existingField)) {
+ // rename the old deleted field that is being replaced by the new field
+ renameField(existingField.name(), existingField.name() + "_" +
existingField.fieldId());
+ }
+
PartitionField added = nameToAddedField.get(name);
Preconditions.checkArgument(added == null,
"Cannot rename newly added partition field: %s", name);
@@ -228,14 +247,7 @@ class BaseUpdatePartitionSpec implements
UpdatePartitionSpec {
}
for (PartitionField newField : adds) {
- String partitionName;
- if (newField.name() != null) {
- partitionName = newField.name();
- } else {
- partitionName = PartitionSpecVisitor.visit(schema, newField,
PartitionNameGenerator.INSTANCE);
- }
-
- builder.add(newField.sourceId(), newField.fieldId(), partitionName,
newField.transform());
+ builder.add(newField.sourceId(), newField.fieldId(), newField.name(),
newField.transform());
}
return builder.build();
@@ -287,13 +299,13 @@ class BaseUpdatePartitionSpec implements
UpdatePartitionSpec {
}
private static Map<Pair<Integer, String>, PartitionField>
indexSpecByTransform(PartitionSpec spec) {
- ImmutableMap.Builder<Pair<Integer, String>, PartitionField> builder =
ImmutableMap.builder();
+ Map<Pair<Integer, String>, PartitionField> indexSpecs = Maps.newHashMap();
List<PartitionField> fields = spec.fields();
for (PartitionField field : fields) {
- builder.put(Pair.of(field.sourceId(), field.transform().toString()),
field);
+ indexSpecs.put(Pair.of(field.sourceId(), field.transform().toString()),
field);
}
- return builder.build();
+ return indexSpecs;
}
private boolean isTimeTransform(PartitionField field) {
@@ -352,6 +364,62 @@ class BaseUpdatePartitionSpec implements
UpdatePartitionSpec {
}
}
+ private boolean isVoidTransform(PartitionField field) {
+ return PartitionSpecVisitor.visit(schema, field, IsVoidTransform.INSTANCE);
+ }
+
+ private static class IsVoidTransform implements
PartitionSpecVisitor<Boolean> {
+ private static final IsVoidTransform INSTANCE = new IsVoidTransform();
+
+ private IsVoidTransform() {
+ }
+
+ @Override
+ public Boolean identity(int fieldId, String sourceName, int sourceId) {
+ return false;
+ }
+
+ @Override
+ public Boolean bucket(int fieldId, String sourceName, int sourceId, int
numBuckets) {
+ return false;
+ }
+
+ @Override
+ public Boolean truncate(int fieldId, String sourceName, int sourceId, int
width) {
+ return false;
+ }
+
+ @Override
+ public Boolean year(int fieldId, String sourceName, int sourceId) {
+ return false;
+ }
+
+ @Override
+ public Boolean month(int fieldId, String sourceName, int sourceId) {
+ return false;
+ }
+
+ @Override
+ public Boolean day(int fieldId, String sourceName, int sourceId) {
+ return false;
+ }
+
+ @Override
+ public Boolean hour(int fieldId, String sourceName, int sourceId) {
+ return false;
+ }
+
+ @Override
+ public Boolean alwaysNull(int fieldId, String sourceName, int sourceId) {
+ return true;
+ }
+
+ @Override
+ public Boolean unknown(int fieldId, String sourceName, int sourceId,
String transform) {
+ return false;
+ }
+ }
+
private static class PartitionNameGenerator implements
PartitionSpecVisitor<String> {
private static final PartitionNameGenerator INSTANCE = new
PartitionNameGenerator();
diff --git a/core/src/test/java/org/apache/iceberg/TestUpdatePartitionSpec.java
b/core/src/test/java/org/apache/iceberg/TestUpdatePartitionSpec.java
index 1c0fc76..c65dd2e 100644
--- a/core/src/test/java/org/apache/iceberg/TestUpdatePartitionSpec.java
+++ b/core/src/test/java/org/apache/iceberg/TestUpdatePartitionSpec.java
@@ -569,6 +569,51 @@ public class TestUpdatePartitionSpec extends TableTestBase
{
.renameField("shard", "id_bucket"));
}
+ @Test
+ public void testRemoveAndAddMultiTimes() {
+ PartitionSpec addFirstTime = new BaseUpdatePartitionSpec(formatVersion,
UNPARTITIONED)
+ .addField("ts_date", day("ts"))
+ .apply();
+ PartitionSpec removeFirstTime = new BaseUpdatePartitionSpec(formatVersion,
addFirstTime)
+ .removeField(day("ts"))
+ .apply();
+ PartitionSpec addSecondTime = new BaseUpdatePartitionSpec(formatVersion,
removeFirstTime)
+ .addField("ts_date", day("ts"))
+ .apply();
+ PartitionSpec removeSecondTime = new
BaseUpdatePartitionSpec(formatVersion, addSecondTime)
+ .removeField(day("ts"))
+ .apply();
+ PartitionSpec addThirdTime = new BaseUpdatePartitionSpec(formatVersion,
removeSecondTime)
+ .addField(month("ts"))
+ .apply();
+ PartitionSpec updated = new BaseUpdatePartitionSpec(formatVersion,
addThirdTime)
+ .renameField("ts_month", "ts_date")
+ .apply();
+
+ if (formatVersion == 1) {
+ Assert.assertEquals("Should match expected spec field size", 3,
updated.fields().size());
+
+ Assert.assertTrue("Should match expected field name",
+ updated.fields().get(0).name().matches("^ts_date(?:_\\d+)+$"));
+ Assert.assertTrue("Should match expected field name",
+ updated.fields().get(1).name().matches("^ts_date_(?:\\d+)+$"));
+ Assert.assertEquals("Should match expected field name", "ts_date",
updated.fields().get(2).name());
+
+ Assert.assertEquals("Should match expected field transform", "void",
+ updated.fields().get(0).transform().toString());
+ Assert.assertEquals("Should match expected field transform", "void",
+ updated.fields().get(1).transform().toString());
+ Assert.assertEquals("Should match expected field transform", "month",
+ updated.fields().get(2).transform().toString());
+ }
+
+ PartitionSpec v2Expected = PartitionSpec.builderFor(SCHEMA)
+ .month("ts", "ts_date")
+ .build();
+
+ V2Assert.assertEquals("Should match expected spec", v2Expected, updated);
+ }
+
private static int id(String name) {
return SCHEMA.findField(name).fieldId();
}