From 00a3aa19d1bd8cd95c07117b134356ac64d3eaa8 Mon Sep 17 00:00:00 2001 From: Eduard Tudenhoefner Date: Tue, 23 Apr 2024 16:46:24 +0200 Subject: [PATCH] Core: Assign fresh IDs to view schema --- .../org/apache/iceberg/view/ViewMetadata.java | 19 ++- .../apache/iceberg/view/TestViewMetadata.java | 114 ++++++++++++++++++ .../apache/iceberg/view/ViewCatalogTests.java | 71 ++++++++--- .../iceberg/spark/extensions/TestViews.java | 8 +- .../iceberg/spark/extensions/TestViews.java | 8 +- 5 files changed, 193 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java b/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java index 94f3a56ba931..50673ad9d758 100644 --- a/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java +++ b/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java @@ -26,6 +26,7 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nullable; @@ -38,6 +39,7 @@ import org.apache.iceberg.relocated.com.google.common.collect.Lists; import org.apache.iceberg.relocated.com.google.common.collect.Maps; import org.apache.iceberg.relocated.com.google.common.collect.Sets; +import org.apache.iceberg.types.TypeUtil; import org.apache.iceberg.util.PropertyUtil; import org.immutables.value.Value; import org.slf4j.Logger; @@ -258,7 +260,22 @@ public Builder setCurrentVersionId(int newVersionId) { } public Builder setCurrentVersion(ViewVersion version, Schema schema) { - int newSchemaId = addSchemaInternal(schema); + Schema freshSchema; + if (history.isEmpty()) { + // view metadata is created + freshSchema = + TypeUtil.assignFreshIds( + INITIAL_SCHEMA_ID, schema, new AtomicInteger(0)::incrementAndGet); + } else { + // view metadata is replaced + Schema baseSchema = schemasById.get(versionsById.get(currentVersionId).schemaId()); + AtomicInteger highestFieldId = + new AtomicInteger( + schemas.stream().map(Schema::highestFieldId).max(Integer::compareTo).orElse(0)); + freshSchema = TypeUtil.assignFreshIds(schema, baseSchema, highestFieldId::incrementAndGet); + } + + int newSchemaId = addSchemaInternal(freshSchema); ViewVersion newVersion = ImmutableViewVersion.builder().from(version).schemaId(newSchemaId).build(); return setCurrentVersionId(addVersionInternal(newVersion)); diff --git a/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java b/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java index 60e615a99310..407ab4885f5a 100644 --- a/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java +++ b/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java @@ -1181,4 +1181,118 @@ public void droppingDialectAllowedAndThenDisallowed() { + "Previous dialects: [trino]\n" + "New dialects: [spark]"); } + + @Test + public void assignFreshSchemaIdWhereNewSchemasFieldIdIsSmallerThanHighestFieldId() { + Schema schemaOne = new Schema(Types.NestedField.required(1, "x", Types.LongType.get())); + Schema schemaTwo = new Schema(Types.NestedField.required(2, "y", Types.LongType.get())); + Schema schemaThree = new Schema(Types.NestedField.required(3, "z", Types.LongType.get())); + Schema newSchema = new Schema(Types.NestedField.required(1, "a", Types.LongType.get())); + + ViewMetadata metadata = + ViewMetadata.builder() + .setLocation("custom-location") + .addSchema(schemaOne) + .addSchema(schemaTwo) + .addSchema(schemaThree) + .setCurrentVersion( + ImmutableViewVersion.builder() + .versionId(1) + .schemaId(0) + .timestampMillis(System.currentTimeMillis()) + .defaultNamespace(Namespace.empty()) + .build(), + schemaOne) + .build(); + + ViewMetadata replacement = + ViewMetadata.buildFrom(metadata) + .setCurrentVersion( + ImmutableViewVersion.builder() + .versionId(2) + .schemaId(0) + .timestampMillis(System.currentTimeMillis()) + .defaultNamespace(Namespace.empty()) + .build(), + newSchema) + .build(); + + assertThat(replacement.schema().highestFieldId()).isEqualTo(4); + } + + @Test + public void assignFreshSchemaIdWhereNewSchemasFieldIdIsGreaterThanHighestFieldId() { + Schema schemaOne = new Schema(Types.NestedField.required(1, "x", Types.LongType.get())); + Schema schemaTwo = new Schema(Types.NestedField.required(2, "y", Types.LongType.get())); + Schema schemaThree = new Schema(Types.NestedField.required(3, "z", Types.LongType.get())); + Schema newSchema = new Schema(Types.NestedField.required(12, "a", Types.LongType.get())); + + ViewMetadata metadata = + ViewMetadata.builder() + .setLocation("custom-location") + .addSchema(schemaOne) + .addSchema(schemaTwo) + .addSchema(schemaThree) + .setCurrentVersion( + ImmutableViewVersion.builder() + .versionId(1) + .schemaId(0) + .timestampMillis(System.currentTimeMillis()) + .defaultNamespace(Namespace.empty()) + .build(), + schemaOne) + .build(); + + ViewMetadata replacement = + ViewMetadata.buildFrom(metadata) + .setCurrentVersion( + ImmutableViewVersion.builder() + .versionId(2) + .schemaId(0) + .timestampMillis(System.currentTimeMillis()) + .defaultNamespace(Namespace.empty()) + .build(), + newSchema) + .build(); + + assertThat(replacement.schema().highestFieldId()).isEqualTo(4); + } + + @Test + public void assignFreshSchemaIdWhereNewSchemasFieldIdSameAsHighestFieldId() { + Schema schemaOne = new Schema(Types.NestedField.required(1, "x", Types.LongType.get())); + Schema schemaTwo = new Schema(Types.NestedField.required(2, "y", Types.LongType.get())); + Schema schemaThree = new Schema(Types.NestedField.required(3, "z", Types.LongType.get())); + Schema newSchema = new Schema(Types.NestedField.required(3, "a", Types.LongType.get())); + + ViewMetadata metadata = + ViewMetadata.builder() + .setLocation("custom-location") + .addSchema(schemaOne) + .addSchema(schemaTwo) + .addSchema(schemaThree) + .setCurrentVersion( + ImmutableViewVersion.builder() + .versionId(1) + .schemaId(0) + .timestampMillis(System.currentTimeMillis()) + .defaultNamespace(Namespace.empty()) + .build(), + schemaOne) + .build(); + + ViewMetadata replacement = + ViewMetadata.buildFrom(metadata) + .setCurrentVersion( + ImmutableViewVersion.builder() + .versionId(2) + .schemaId(0) + .timestampMillis(System.currentTimeMillis()) + .defaultNamespace(Namespace.empty()) + .build(), + newSchema) + .build(); + + assertThat(replacement.schema().highestFieldId()).isEqualTo(4); + } } diff --git a/core/src/test/java/org/apache/iceberg/view/ViewCatalogTests.java b/core/src/test/java/org/apache/iceberg/view/ViewCatalogTests.java index b3765bb1eae7..4c0511aa4aae 100644 --- a/core/src/test/java/org/apache/iceberg/view/ViewCatalogTests.java +++ b/core/src/test/java/org/apache/iceberg/view/ViewCatalogTests.java @@ -52,8 +52,27 @@ public abstract class ViewCatalogTests