Skip to content

Commit 821aec3

Browse files
authored
API: Add Variant data type (apache#11324)
1 parent 50d310a commit 821aec3

File tree

17 files changed

+208
-51
lines changed

17 files changed

+208
-51
lines changed

api/src/main/java/org/apache/iceberg/Schema.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class Schema implements Serializable {
6060

6161
@VisibleForTesting
6262
static final Map<Type.TypeID, Integer> MIN_FORMAT_VERSIONS =
63-
ImmutableMap.of(Type.TypeID.TIMESTAMP_NANO, 3);
63+
ImmutableMap.of(Type.TypeID.TIMESTAMP_NANO, 3, Type.TypeID.VARIANT, 3);
6464

6565
private final StructType struct;
6666
private final int schemaId;

api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,8 @@ private static String sanitize(Type type, Object value, long now, int today) {
534534
case DECIMAL:
535535
case FIXED:
536536
case BINARY:
537-
// for boolean, uuid, decimal, fixed, and binary, match the string result
537+
case VARIANT:
538+
// for boolean, uuid, decimal, fixed, variant, and binary, match the string result
538539
return sanitizeSimpleString(value.toString());
539540
}
540541
throw new UnsupportedOperationException(
@@ -562,7 +563,7 @@ private static String sanitize(Literal<?> literal, long now, int today) {
562563
} else if (literal instanceof Literals.DoubleLiteral) {
563564
return sanitizeNumber(((Literals.DoubleLiteral) literal).value(), "float");
564565
} else {
565-
// for uuid, decimal, fixed, and binary, match the string result
566+
// for uuid, decimal, fixed, variant, and binary, match the string result
566567
return sanitizeSimpleString(literal.value().toString());
567568
}
568569
}

api/src/main/java/org/apache/iceberg/transforms/Identity.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class Identity<T> implements Transform<T, T> {
3838
*/
3939
@Deprecated
4040
public static <I> Identity<I> get(Type type) {
41+
Preconditions.checkArgument(
42+
type.typeId() != Type.TypeID.VARIANT, "Unsupported type for identity: %s", type);
43+
4144
return new Identity<>(type);
4245
}
4346

api/src/main/java/org/apache/iceberg/types/FindTypeVisitor.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ public Type map(Types.MapType map, Type keyResult, Type valueResult) {
7676
return valueResult;
7777
}
7878

79+
@Override
80+
public Type variant() {
81+
if (predicate.test(Types.VariantType.get())) {
82+
return Types.VariantType.get();
83+
}
84+
85+
return null;
86+
}
87+
7988
@Override
8089
public Type primitive(Type.PrimitiveType primitive) {
8190
if (predicate.test(primitive)) {

api/src/main/java/org/apache/iceberg/types/IndexByName.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ public Map<String, Integer> map(
176176
return nameToId;
177177
}
178178

179+
@Override
180+
public Map<String, Integer> variant() {
181+
return nameToId;
182+
}
183+
179184
@Override
180185
public Map<String, Integer> primitive(Type.PrimitiveType primitive) {
181186
return nameToId;

api/src/main/java/org/apache/iceberg/types/IndexParents.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ public Map<Integer, Integer> map(
7676
return idToParent;
7777
}
7878

79+
@Override
80+
public Map<Integer, Integer> variant() {
81+
return idToParent;
82+
}
83+
7984
@Override
8085
public Map<Integer, Integer> primitive(Type.PrimitiveType primitive) {
8186
return idToParent;

api/src/main/java/org/apache/iceberg/types/Type.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ enum TypeID {
4545
DECIMAL(BigDecimal.class),
4646
STRUCT(StructLike.class),
4747
LIST(List.class),
48-
MAP(Map.class);
48+
MAP(Map.class),
49+
VARIANT(Object.class);
4950

5051
private final Class<?> javaClass;
5152

api/src/main/java/org/apache/iceberg/types/TypeUtil.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ private static int estimateSize(Type type) {
534534
case FIXED:
535535
return ((Types.FixedType) type).length();
536536
case BINARY:
537+
case VARIANT:
537538
return 80;
538539
case DECIMAL:
539540
// 12 (header) + (12 + 12 + 4) (BigInteger) + 4 (scale) = 44 bytes
@@ -612,6 +613,10 @@ public T map(Types.MapType map, T keyResult, T valueResult) {
612613
return null;
613614
}
614615

616+
public T variant() {
617+
return null;
618+
}
619+
615620
public T primitive(Type.PrimitiveType primitive) {
616621
return null;
617622
}
@@ -675,6 +680,9 @@ public static <T> T visit(Type type, SchemaVisitor<T> visitor) {
675680

676681
return visitor.map(map, keyResult, valueResult);
677682

683+
case VARIANT:
684+
return visitor.variant();
685+
678686
default:
679687
return visitor.primitive(type.asPrimitiveType());
680688
}

api/src/main/java/org/apache/iceberg/types/Types.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,41 @@ public String toString() {
412412
}
413413
}
414414

415+
public static class VariantType implements Type {
416+
private static final VariantType INSTANCE = new VariantType();
417+
418+
public static VariantType get() {
419+
return INSTANCE;
420+
}
421+
422+
@Override
423+
public TypeID typeId() {
424+
return TypeID.VARIANT;
425+
}
426+
427+
@Override
428+
public String toString() {
429+
return "variant";
430+
}
431+
432+
@Override
433+
public boolean equals(Object o) {
434+
if (this == o) {
435+
return true;
436+
} else if (!(o instanceof VariantType)) {
437+
return false;
438+
}
439+
440+
VariantType that = (VariantType) o;
441+
return typeId() == that.typeId();
442+
}
443+
444+
@Override
445+
public int hashCode() {
446+
return Objects.hash(VariantType.class, typeId());
447+
}
448+
}
449+
415450
public static class DecimalType extends PrimitiveType {
416451
public static DecimalType of(int precision, int scale) {
417452
return new DecimalType(precision, scale);

api/src/test/java/org/apache/iceberg/TestPartitionSpecValidation.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static org.assertj.core.api.Assertions.assertThat;
2222
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2323

24+
import org.apache.iceberg.exceptions.ValidationException;
2425
import org.apache.iceberg.transforms.Transforms;
2526
import org.apache.iceberg.types.Types;
2627
import org.apache.iceberg.types.Types.NestedField;
@@ -34,7 +35,8 @@ public class TestPartitionSpecValidation {
3435
NestedField.required(3, "another_ts", Types.TimestampType.withZone()),
3536
NestedField.required(4, "d", Types.TimestampType.withZone()),
3637
NestedField.required(5, "another_d", Types.TimestampType.withZone()),
37-
NestedField.required(6, "s", Types.StringType.get()));
38+
NestedField.required(6, "s", Types.StringType.get()),
39+
NestedField.required(7, "v", Types.VariantType.get()));
3840

3941
@Test
4042
public void testMultipleTimestampPartitions() {
@@ -312,4 +314,15 @@ public void testAddPartitionFieldsWithAndWithoutFieldIds() {
312314
assertThat(spec.fields().get(2).fieldId()).isEqualTo(1006);
313315
assertThat(spec.lastAssignedFieldId()).isEqualTo(1006);
314316
}
317+
318+
@Test
319+
public void testVariantUnsupported() {
320+
assertThatThrownBy(
321+
() ->
322+
PartitionSpec.builderFor(SCHEMA)
323+
.add(7, 1005, "variant_partition1", Transforms.bucket(5))
324+
.build())
325+
.isInstanceOf(ValidationException.class)
326+
.hasMessage("Cannot partition by non-primitive source field: variant");
327+
}
315328
}

0 commit comments

Comments
 (0)