This is an automated email from the ASF dual-hosted git repository.
snuyanzin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git
The following commit(s) were added to refs/heads/master by this push:
new 995865e08a7 [FLINK-40490][table] Add runtime serialization and codegen
for the `UUID` type
995865e08a7 is described below
commit 995865e08a7633df7a403abedccf8f27747cdf84
Author: Ramin Gharib <[email protected]>
AuthorDate: Fri Sep 4 09:09:33 2026 +0200
[FLINK-40490][table] Add runtime serialization and codegen for the `UUID`
type
---
.../flink/api/common/typeinfo/BasicTypeInfo.java | 10 ++
.../apache/flink/api/common/typeinfo/Types.java | 4 +
.../api/common/typeutils/base/UuidComparator.java | 144 +++++++++++++++++++++
.../api/common/typeutils/base/UuidSerializer.java | 112 ++++++++++++++++
.../common/typeutils/base/UuidComparatorTest.java | 59 +++++++++
.../common/typeutils/base/UuidSerializerTest.java | 55 ++++++++
.../org/apache/flink/table/data/ArrayData.java | 1 +
.../java/org/apache/flink/table/data/RowData.java | 3 +
.../flink/table/data/binary/BinaryArrayData.java | 1 +
.../apache/flink/table/types/logical/UuidType.java | 3 +-
.../types/logical/utils/LogicalTypeUtils.java | 1 +
.../table/types/utils/ClassDataTypeConverter.java | 1 +
.../utils/LegacyTypeInfoDataTypeConverter.java | 3 +
.../types/utils/TypeInfoDataTypeConverter.java | 2 +
.../table/types/ClassDataTypeConverterTest.java | 1 +
.../apache/flink/table/types/LogicalTypesTest.java | 4 +-
.../types/extraction/DataTypeExtractorTest.java | 3 +
.../table/planner/plan/utils/RexLiteralUtil.java | 10 ++
.../flink/table/planner/codegen/CodeGenUtils.scala | 8 +-
.../table/planner/codegen/ExpressionReducer.scala | 6 +-
.../table/planner/codegen/GenerateUtils.scala | 2 +-
.../planner/plan/metadata/FlinkRelMdSize.scala | 2 +-
.../plan/nodes/exec/stream/UuidSemanticTest.java | 40 ++++++
.../plan/nodes/exec/stream/UuidTestPrograms.java | 115 ++++++++++++++++
.../data/conversion/DataStructureConverters.java | 3 +
.../table/data/conversion/UuidUuidConverter.java | 53 ++++++++
.../flink/table/data/writer/BinaryArrayWriter.java | 1 +
.../flink/table/data/writer/BinaryWriter.java | 2 +
.../runtime/typeutils/InternalSerializers.java | 1 +
.../table/data/DataStructureConvertersTest.java | 5 +
.../TypeSerializerTestCoverageTest.java | 4 +-
31 files changed, 646 insertions(+), 13 deletions(-)
diff --git
a/flink-core/src/main/java/org/apache/flink/api/common/typeinfo/BasicTypeInfo.java
b/flink-core/src/main/java/org/apache/flink/api/common/typeinfo/BasicTypeInfo.java
index afe11eb110f..a3bbdf9889b 100644
---
a/flink-core/src/main/java/org/apache/flink/api/common/typeinfo/BasicTypeInfo.java
+++
b/flink-core/src/main/java/org/apache/flink/api/common/typeinfo/BasicTypeInfo.java
@@ -51,6 +51,8 @@ import
org.apache.flink.api.common.typeutils.base.ShortComparator;
import org.apache.flink.api.common.typeutils.base.ShortSerializer;
import org.apache.flink.api.common.typeutils.base.StringComparator;
import org.apache.flink.api.common.typeutils.base.StringSerializer;
+import org.apache.flink.api.common.typeutils.base.UuidComparator;
+import org.apache.flink.api.common.typeutils.base.UuidSerializer;
import org.apache.flink.api.common.typeutils.base.VoidSerializer;
import java.lang.reflect.Constructor;
@@ -62,6 +64,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
+import java.util.UUID;
import static org.apache.flink.util.Preconditions.checkNotNull;
@@ -160,6 +163,9 @@ public class BasicTypeInfo<T> extends TypeInformation<T>
implements AtomicType<T
new Class<?>[] {},
InstantSerializer.INSTANCE,
InstantComparator.class);
+ public static final BasicTypeInfo<UUID> UUID_TYPE_INFO =
+ new BasicTypeInfo<>(
+ UUID.class, new Class<?>[] {}, UuidSerializer.INSTANCE,
UuidComparator.class);
//
--------------------------------------------------------------------------------------------
@@ -338,5 +344,9 @@ public class BasicTypeInfo<T> extends TypeInformation<T>
implements AtomicType<T
TYPES.put(BigInteger.class, BIG_INT_TYPE_INFO);
TYPES.put(BigDecimal.class, BIG_DEC_TYPE_INFO);
TYPES.put(Instant.class, INSTANT_TYPE_INFO);
+ // UUID is intentionally not registered here. Automatic reflective
extraction of
+ // java.util.UUID to UUID_TYPE_INFO in the DataStream API stays opt-in
via Types.UUID to
+ // avoid silently changing the serializer of existing java.util.UUID
fields (currently
+ // handled by Kryo). This is planned to change in the next major Flink
version.
}
}
diff --git
a/flink-core/src/main/java/org/apache/flink/api/common/typeinfo/Types.java
b/flink-core/src/main/java/org/apache/flink/api/common/typeinfo/Types.java
index 52b4f827b53..32b6925d12b 100644
--- a/flink-core/src/main/java/org/apache/flink/api/common/typeinfo/Types.java
+++ b/flink-core/src/main/java/org/apache/flink/api/common/typeinfo/Types.java
@@ -56,6 +56,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
/**
* This class gives access to the type information of the most common types
for which Flink has
@@ -158,6 +159,9 @@ public class Types {
/** Returns type information for {@link java.time.Instant}. Supports a
null value. */
public static final TypeInformation<Instant> INSTANT =
BasicTypeInfo.INSTANT_TYPE_INFO;
+ /** Returns type information for {@link java.util.UUID}. */
+ public static final TypeInformation<UUID> UUID =
BasicTypeInfo.UUID_TYPE_INFO;
+
public static final TypeInformation<Variant> VARIANT =
VariantTypeInfo.INSTANCE;
/**
diff --git
a/flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/UuidComparator.java
b/flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/UuidComparator.java
new file mode 100644
index 00000000000..f190aa03b4c
--- /dev/null
+++
b/flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/UuidComparator.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.api.common.typeutils.base;
+
+import org.apache.flink.annotation.Internal;
+import org.apache.flink.api.common.typeutils.TypeComparator;
+import org.apache.flink.core.memory.DataInputView;
+import org.apache.flink.core.memory.MemorySegment;
+
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * Comparator for {@link UUID}.
+ *
+ * <p>Ordering follows the canonical unsigned big-endian byte comparison of
the 16-byte encoding, so
+ * every 128-bit value sorts by its raw bytes. This deliberately differs from
{@link
+ * UUID#compareTo(UUID)}, which compares the two 64-bit halves as signed
longs; the unsigned order
+ * is the one defined by the type and used consistently across serialized,
normalized-key, and
+ * object comparisons.
+ */
+@Internal
+public final class UuidComparator extends BasicTypeComparator<UUID> {
+
+ private static final long serialVersionUID = 1L;
+
+ private transient UUID reference;
+
+ public UuidComparator(boolean ascending) {
+ super(ascending);
+ }
+
+ private static int compareUnsigned(UUID first, UUID second) {
+ int comp =
+ Long.compareUnsigned(
+ first.getMostSignificantBits(),
second.getMostSignificantBits());
+ if (comp == 0) {
+ comp =
+ Long.compareUnsigned(
+ first.getLeastSignificantBits(),
second.getLeastSignificantBits());
+ }
+ return comp;
+ }
+
+ @Override
+ public void setReference(UUID toCompare) {
+ super.setReference(toCompare);
+ this.reference = toCompare;
+ }
+
+ @Override
+ public int compareToReference(TypeComparator<UUID> referencedComparator) {
+ // Mirror BasicTypeComparator's inverted operand order (referenced vs.
this) using the
+ // unsigned ordering, so it stays consistent with
compare/compareSerialized.
+ final int comp =
+ compareUnsigned(((UuidComparator)
referencedComparator).reference, this.reference);
+ return ascendingComparison ? comp : -comp;
+ }
+
+ @Override
+ public int compare(UUID first, UUID second) {
+ final int comp = compareUnsigned(first, second);
+ return ascendingComparison ? comp : -comp;
+ }
+
+ @Override
+ public int compareSerialized(DataInputView firstSource, DataInputView
secondSource)
+ throws IOException {
+ final long lMostSignificantBits = firstSource.readLong();
+ final long rMostSignificantBits = secondSource.readLong();
+ int comp = Long.compareUnsigned(lMostSignificantBits,
rMostSignificantBits);
+ if (comp == 0) {
+ final long lLeastSignificantBits = firstSource.readLong();
+ final long rLeastSignificantBits = secondSource.readLong();
+ comp = Long.compareUnsigned(lLeastSignificantBits,
rLeastSignificantBits);
+ }
+ return ascendingComparison ? comp : -comp;
+ }
+
+ @Override
+ public boolean supportsNormalizedKey() {
+ return true;
+ }
+
+ @Override
+ public int getNormalizeKeyLen() {
+ return UuidSerializer.UUID_BYTES;
+ }
+
+ @Override
+ public boolean isNormalizedKeyPrefixOnly(int keyBytes) {
+ return keyBytes < getNormalizeKeyLen();
+ }
+
+ @Override
+ public void putNormalizedKey(UUID record, MemorySegment target, int
offset, int numBytes) {
+ // The raw 16-byte big-endian encoding is already order-preserving
under the unsigned
+ // byte-wise comparison used for normalized keys, so no sign flip is
applied.
+ final long mostSignificantBits = record.getMostSignificantBits();
+ final long leastSignificantBits = record.getLeastSignificantBits();
+ if (numBytes >= Long.BYTES) {
+ target.putLongBigEndian(offset, mostSignificantBits);
+ offset += Long.BYTES;
+ numBytes -= Long.BYTES;
+ if (numBytes >= Long.BYTES) {
+ target.putLongBigEndian(offset, leastSignificantBits);
+ offset += Long.BYTES;
+ numBytes -= Long.BYTES;
+ for (int i = 0; i < numBytes; i++) {
+ target.put(offset + i, (byte) 0);
+ }
+ } else {
+ for (int i = 0; i < numBytes; i++) {
+ target.put(offset + i, (byte) (leastSignificantBits >>>
((7 - i) << 3)));
+ }
+ }
+ } else {
+ for (int i = 0; i < numBytes; i++) {
+ target.put(offset + i, (byte) (mostSignificantBits >>> ((7 -
i) << 3)));
+ }
+ }
+ }
+
+ @Override
+ public TypeComparator<UUID> duplicate() {
+ return new UuidComparator(ascendingComparison);
+ }
+}
diff --git
a/flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/UuidSerializer.java
b/flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/UuidSerializer.java
new file mode 100644
index 00000000000..e0d76c212d4
--- /dev/null
+++
b/flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/UuidSerializer.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.api.common.typeutils.base;
+
+import org.apache.flink.annotation.Internal;
+import org.apache.flink.api.common.typeutils.SimpleTypeSerializerSnapshot;
+import org.apache.flink.api.common.typeutils.TypeSerializerSnapshot;
+import org.apache.flink.core.memory.DataInputView;
+import org.apache.flink.core.memory.DataOutputView;
+
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * Serializer for {@link UUID}.
+ *
+ * <p>A UUID is written as its canonical 16-byte big-endian form: the most
significant 64 bits
+ * followed by the least significant 64 bits. All 128 bits are valid, so there
is no reserved value
+ * for {@code null}; nullability is handled by wrapping serializers (e.g.
{@code NullableSerializer}
+ * or the row/POJO serializers) as for the other fixed-width base serializers.
+ */
+@Internal
+public final class UuidSerializer extends TypeSerializerSingleton<UUID> {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Length of a serialized UUID: two 64-bit longs. */
+ static final int UUID_BYTES = 2 * Long.BYTES;
+
+ public static final UuidSerializer INSTANCE = new UuidSerializer();
+
+ @Override
+ public boolean isImmutableType() {
+ return true;
+ }
+
+ @Override
+ public UUID createInstance() {
+ return new UUID(0L, 0L);
+ }
+
+ @Override
+ public UUID copy(UUID from) {
+ return from;
+ }
+
+ @Override
+ public UUID copy(UUID from, UUID reuse) {
+ return from;
+ }
+
+ @Override
+ public int getLength() {
+ return UUID_BYTES;
+ }
+
+ @Override
+ public void serialize(UUID record, DataOutputView target) throws
IOException {
+ target.writeLong(record.getMostSignificantBits());
+ target.writeLong(record.getLeastSignificantBits());
+ }
+
+ @Override
+ public UUID deserialize(DataInputView source) throws IOException {
+ final long mostSignificantBits = source.readLong();
+ final long leastSignificantBits = source.readLong();
+ return new UUID(mostSignificantBits, leastSignificantBits);
+ }
+
+ @Override
+ public UUID deserialize(UUID reuse, DataInputView source) throws
IOException {
+ return deserialize(source);
+ }
+
+ @Override
+ public void copy(DataInputView source, DataOutputView target) throws
IOException {
+ target.writeLong(source.readLong());
+ target.writeLong(source.readLong());
+ }
+
+ @Override
+ public TypeSerializerSnapshot<UUID> snapshotConfiguration() {
+ return new UuidSerializerSnapshot();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /** Serializer configuration snapshot for compatibility and format
evolution. */
+ @Internal
+ public static final class UuidSerializerSnapshot extends
SimpleTypeSerializerSnapshot<UUID> {
+
+ public UuidSerializerSnapshot() {
+ super(() -> INSTANCE);
+ }
+ }
+}
diff --git
a/flink-core/src/test/java/org/apache/flink/api/common/typeutils/base/UuidComparatorTest.java
b/flink-core/src/test/java/org/apache/flink/api/common/typeutils/base/UuidComparatorTest.java
new file mode 100644
index 00000000000..34b67048bf9
--- /dev/null
+++
b/flink-core/src/test/java/org/apache/flink/api/common/typeutils/base/UuidComparatorTest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.api.common.typeutils.base;
+
+import org.apache.flink.api.common.typeutils.ComparatorTestBase;
+import org.apache.flink.api.common.typeutils.TypeComparator;
+import org.apache.flink.api.common.typeutils.TypeSerializer;
+
+import java.util.UUID;
+
+/**
+ * A test for the {@link UuidComparator}.
+ *
+ * <p>The sorted data spans the signed-long boundary (a {@code 0x8000...}
most-significant half
+ * sorts after {@code 0x7FFF...}) to assert the unsigned big-endian ordering,
which differs from
+ * {@link UUID#compareTo(UUID)}.
+ */
+class UuidComparatorTest extends ComparatorTestBase<UUID> {
+
+ @Override
+ protected TypeComparator<UUID> createComparator(boolean ascending) {
+ return new UuidComparator(ascending);
+ }
+
+ @Override
+ protected TypeSerializer<UUID> createSerializer() {
+ return new UuidSerializer();
+ }
+
+ @Override
+ protected UUID[] getSortedTestData() {
+ return new UUID[] {
+ new UUID(0x0000000000000000L, 0x0000000000000000L),
+ new UUID(0x0000000000000000L, 0x0000000000000001L),
+ new UUID(0x0000000000000000L, 0xFFFFFFFFFFFFFFFFL),
+ new UUID(0x0000000000000001L, 0x0000000000000000L),
+ new UUID(0x7FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL),
+ new UUID(0x8000000000000000L, 0x0000000000000000L),
+ new UUID(0xFFFFFFFFFFFFFFFFL, 0x0000000000000000L),
+ new UUID(0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL)
+ };
+ }
+}
diff --git
a/flink-core/src/test/java/org/apache/flink/api/common/typeutils/base/UuidSerializerTest.java
b/flink-core/src/test/java/org/apache/flink/api/common/typeutils/base/UuidSerializerTest.java
new file mode 100644
index 00000000000..9d62538a7f8
--- /dev/null
+++
b/flink-core/src/test/java/org/apache/flink/api/common/typeutils/base/UuidSerializerTest.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.api.common.typeutils.base;
+
+import org.apache.flink.api.common.typeutils.SerializerTestBase;
+import org.apache.flink.api.common.typeutils.TypeSerializer;
+
+import java.util.UUID;
+
+/** A test for the {@link UuidSerializer}. */
+class UuidSerializerTest extends SerializerTestBase<UUID> {
+
+ @Override
+ protected TypeSerializer<UUID> createSerializer() {
+ return new UuidSerializer();
+ }
+
+ @Override
+ protected int getLength() {
+ return 16;
+ }
+
+ @Override
+ protected Class<UUID> getTypeClass() {
+ return UUID.class;
+ }
+
+ @Override
+ protected UUID[] getTestData() {
+ return new UUID[] {
+ new UUID(0L, 0L),
+ new UUID(0x8000000000000000L, 0x0000000000000000L),
+ new UUID(0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL),
+ UUID.fromString("00000000-0000-0000-0000-000000000001"),
+ UUID.fromString("550e8400-e29b-41d4-a716-446655440000"),
+ UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479")
+ };
+ }
+}
diff --git
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/ArrayData.java
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/ArrayData.java
index 811c9be70e6..c56955c4a5c 100644
---
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/ArrayData.java
+++
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/ArrayData.java
@@ -164,6 +164,7 @@ public interface ArrayData {
break;
case BINARY:
case VARBINARY:
+ case UUID:
elementGetter = ArrayData::getBinary;
break;
case DECIMAL:
diff --git
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/RowData.java
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/RowData.java
index ca43f1608f9..1a28ebfd833 100644
---
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/RowData.java
+++
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/RowData.java
@@ -111,6 +111,8 @@ import static
org.apache.flink.table.types.logical.utils.LogicalTypeChecks.getSc
* +--------------------------------+-----------------------------------------+
* | BITMAP | {@link Bitmap} |
* +--------------------------------+-----------------------------------------+
+ * | UUID | byte[] (16 big-endian bytes) |
+ * +--------------------------------+-----------------------------------------+
* </pre>
*
* <p>Nullability is always handled by the container data structure.
@@ -238,6 +240,7 @@ public interface RowData {
break;
case BINARY:
case VARBINARY:
+ case UUID:
fieldGetter = row -> row.getBinary(fieldPos);
break;
case DECIMAL:
diff --git
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/binary/BinaryArrayData.java
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/binary/BinaryArrayData.java
index 10a8b3e6ef7..a8e3087d72c 100644
---
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/binary/BinaryArrayData.java
+++
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/binary/BinaryArrayData.java
@@ -95,6 +95,7 @@ public final class BinaryArrayData extends BinarySection
implements ArrayData, T
case RAW:
case VARIANT:
case BITMAP:
+ case UUID:
// long and double are 8 bytes;
// otherwise it stores the length and offset of the
variable-length part for types
// such as is string, map, etc.
diff --git
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/UuidType.java
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/UuidType.java
index 2973a89b601..f18076685d6 100644
---
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/UuidType.java
+++
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/UuidType.java
@@ -38,7 +38,8 @@ public final class UuidType extends LogicalType {
private static final long serialVersionUID = 1L;
- private static final Set<String> INPUT_OUTPUT_CONVERSION =
conversionSet(UUID.class.getName());
+ private static final Set<String> INPUT_OUTPUT_CONVERSION =
+ conversionSet(UUID.class.getName(), byte[].class.getName());
public UuidType(boolean isNullable) {
super(isNullable, LogicalTypeRoot.UUID);
diff --git
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/utils/LogicalTypeUtils.java
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/utils/LogicalTypeUtils.java
index 98629b15fc1..849c2f22bbf 100644
---
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/utils/LogicalTypeUtils.java
+++
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/utils/LogicalTypeUtils.java
@@ -71,6 +71,7 @@ public final class LogicalTypeUtils {
return Boolean.class;
case BINARY:
case VARBINARY:
+ case UUID:
return byte[].class;
case DECIMAL:
return DecimalData.class;
diff --git
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/ClassDataTypeConverter.java
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/ClassDataTypeConverter.java
index f0fca13ea29..726843ce284 100644
---
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/ClassDataTypeConverter.java
+++
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/ClassDataTypeConverter.java
@@ -79,6 +79,7 @@ public final class ClassDataTypeConverter {
addDefaultDataType(
java.time.Period.class, DataTypes.INTERVAL(DataTypes.YEAR(4),
DataTypes.MONTH()));
addDefaultDataType(ColumnList.class, DataTypes.DESCRIPTOR());
+ addDefaultDataType(java.util.UUID.class, DataTypes.UUID());
addDefaultDataType(Variant.class, DataTypes.VARIANT());
addDefaultDataType(Bitmap.class, DataTypes.BITMAP());
addDefaultDataType(RoaringBitmapData.class, DataTypes.BITMAP());
diff --git
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/LegacyTypeInfoDataTypeConverter.java
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/LegacyTypeInfoDataTypeConverter.java
index 1071a661ef1..dc82a07ba81 100644
---
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/LegacyTypeInfoDataTypeConverter.java
+++
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/LegacyTypeInfoDataTypeConverter.java
@@ -73,6 +73,7 @@ import static
org.apache.flink.table.types.logical.LogicalTypeRoot.STRUCTURED_TY
import static
org.apache.flink.table.types.logical.LogicalTypeRoot.TIMESTAMP_WITHOUT_TIME_ZONE;
import static
org.apache.flink.table.types.logical.LogicalTypeRoot.TIMESTAMP_WITH_LOCAL_TIME_ZONE;
import static
org.apache.flink.table.types.logical.LogicalTypeRoot.TIME_WITHOUT_TIME_ZONE;
+import static org.apache.flink.table.types.logical.LogicalTypeRoot.UUID;
import static org.apache.flink.table.types.logical.LogicalTypeRoot.VARCHAR;
import static org.apache.flink.table.types.logical.LogicalTypeRoot.VARIANT;
import static
org.apache.flink.table.types.logical.utils.LogicalTypeChecks.isRowtimeAttribute;
@@ -228,6 +229,8 @@ public final class LegacyTypeInfoDataTypeConverter {
return Types.STRING;
} else if (logicalType.is(VARIANT)) {
return Types.VARIANT;
+ } else if (logicalType.is(UUID)) {
+ return Types.UUID;
}
// relax the precision constraint as Timestamp can store the highest
precision
diff --git
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/TypeInfoDataTypeConverter.java
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/TypeInfoDataTypeConverter.java
index 7d8163aba53..941a8c854ef 100644
---
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/TypeInfoDataTypeConverter.java
+++
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/utils/TypeInfoDataTypeConverter.java
@@ -58,6 +58,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -149,6 +150,7 @@ public final class TypeInfoDataTypeConverter {
PrimitiveArrayTypeInfo.DOUBLE_PRIMITIVE_ARRAY_TYPE_INFO,
DataTypes.ARRAY(DataTypes.DOUBLE().notNull().bridgedTo(double.class))
.bridgedTo(double[].class));
+ conversionMap.put(Types.UUID, DataTypes.UUID().bridgedTo(UUID.class));
conversionMap.put(Types.VARIANT,
DataTypes.VARIANT().bridgedTo(Variant.class));
conversionMap.put(Types.BITMAP,
DataTypes.BITMAP().bridgedTo(Bitmap.class));
}
diff --git
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/ClassDataTypeConverterTest.java
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/ClassDataTypeConverterTest.java
index ebf629a0f72..00f07e9375a 100644
---
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/ClassDataTypeConverterTest.java
+++
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/ClassDataTypeConverterTest.java
@@ -94,6 +94,7 @@ class ClassDataTypeConverterTest {
TimeIntervalUnit.class,
new AtomicDataType(new
SymbolType<>()).bridgedTo(TimeIntervalUnit.class)),
of(Row.class, null),
+ of(java.util.UUID.class, DataTypes.UUID()),
of(Variant.class, DataTypes.VARIANT()),
of(Bitmap.class, DataTypes.BITMAP().bridgedTo(Bitmap.class)),
of(RoaringBitmapData.class,
DataTypes.BITMAP().bridgedTo(RoaringBitmapData.class)));
diff --git
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/LogicalTypesTest.java
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/LogicalTypesTest.java
index 0703e16c78e..03dacc344ee 100644
---
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/LogicalTypesTest.java
+++
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/LogicalTypesTest.java
@@ -636,8 +636,8 @@ public class LogicalTypesTest {
baseAssertions(
"UUID",
"UUID",
- new Class[] {UUID.class},
- new Class[] {UUID.class},
+ new Class[] {UUID.class, byte[].class},
+ new Class[] {UUID.class, byte[].class},
new LogicalType[] {},
new UuidType(false)));
}
diff --git
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/DataTypeExtractorTest.java
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/DataTypeExtractorTest.java
index da019284223..f5e4423b9de 100644
---
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/DataTypeExtractorTest.java
+++
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/DataTypeExtractorTest.java
@@ -81,6 +81,9 @@ class DataTypeExtractorTest {
// simple extraction of BYTES
TestSpec.forType(byte[].class).expectDataType(DataTypes.BYTES()),
+ // automatic extraction of UUID for Table/SQL
+
TestSpec.forType(java.util.UUID.class).expectDataType(DataTypes.UUID()),
+
// extraction from hint conversion class
TestSpec.forType(
new DataTypeHintMock() {
diff --git
a/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/plan/utils/RexLiteralUtil.java
b/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/plan/utils/RexLiteralUtil.java
index dc3875ce4a7..2e3561f3d5f 100644
---
a/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/plan/utils/RexLiteralUtil.java
+++
b/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/plan/utils/RexLiteralUtil.java
@@ -39,6 +39,7 @@ import org.apache.calcite.util.TimeString;
import org.apache.calcite.util.TimestampString;
import java.math.BigDecimal;
+import java.nio.ByteBuffer;
import java.time.ZoneOffset;
import static
org.apache.flink.table.planner.utils.TimestampStringUtils.toLocalDateTime;
@@ -102,6 +103,15 @@ public class RexLiteralUtil {
return ((ByteString) value).getBytes();
}
break;
+ case UUID:
+ if (value instanceof java.util.UUID) {
+ final java.util.UUID uuidValue = (java.util.UUID) value;
+ return ByteBuffer.allocate(16)
+ .putLong(uuidValue.getMostSignificantBits())
+ .putLong(uuidValue.getLeastSignificantBits())
+ .array();
+ }
+ break;
case DECIMAL:
if (value instanceof BigDecimal) {
return DecimalData.fromBigDecimal(
diff --git
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/CodeGenUtils.scala
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/CodeGenUtils.scala
index 739858689bf..0dd59e18235 100644
---
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/CodeGenUtils.scala
+++
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/CodeGenUtils.scala
@@ -263,7 +263,7 @@ object CodeGenUtils {
// ordered by type root definition
case CHAR | VARCHAR => BINARY_STRING
case BOOLEAN => className[JBoolean]
- case BINARY | VARBINARY => "byte[]"
+ case BINARY | VARBINARY | UUID => "byte[]"
case DECIMAL => className[DecimalData]
case TINYINT => className[JByte]
case SMALLINT => className[JShort]
@@ -329,7 +329,7 @@ object CodeGenUtils {
s"$term.hashCode()"
case BOOLEAN =>
s"${className[JBoolean]}.hashCode($term)"
- case BINARY | VARBINARY =>
+ case BINARY | VARBINARY | UUID =>
// Instead of computing the BYTE_ARRAY_BASE_OFFSET value in JM,
generate the code
// and evaluate it in TM. This is required so that byte array offset
will be consistent.
// See FLINK-37833 for more details.
@@ -510,7 +510,7 @@ object CodeGenUtils {
s"(($BINARY_STRING) $rowTerm.getString($indexTerm))"
case BOOLEAN =>
s"$rowTerm.getBoolean($indexTerm)"
- case BINARY | VARBINARY =>
+ case BINARY | VARBINARY | UUID =>
s"$rowTerm.getBinary($indexTerm)"
case DECIMAL =>
s"$rowTerm.getDecimal($indexTerm, ${getPrecision(t)}, ${getScale(t)})"
@@ -798,7 +798,7 @@ object CodeGenUtils {
s"$writerTerm.writeString($indexTerm, $fieldValTerm)"
case BOOLEAN =>
s"$writerTerm.writeBoolean($indexTerm, $fieldValTerm)"
- case BINARY | VARBINARY =>
+ case BINARY | VARBINARY | UUID =>
s"$writerTerm.writeBinary($indexTerm, $fieldValTerm)"
case DECIMAL =>
s"$writerTerm.writeDecimal($indexTerm, $fieldValTerm,
${getPrecision(t)})"
diff --git
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/ExpressionReducer.scala
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/ExpressionReducer.scala
index 3dc12b93000..3645c7b46c1 100644
---
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/ExpressionReducer.scala
+++
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/ExpressionReducer.scala
@@ -146,8 +146,8 @@ class ExpressionReducer(
unreduced.getType.getSqlTypeName match {
// we insert the original expression for object literals
case SqlTypeName.ANY | SqlTypeName.OTHER | SqlTypeName.ROW |
SqlTypeName.STRUCTURED |
- SqlTypeName.ARRAY | SqlTypeName.MAP | SqlTypeName.MULTISET |
- SqlTypeName.VARIANT =>
+ SqlTypeName.ARRAY | SqlTypeName.MAP | SqlTypeName.MULTISET |
SqlTypeName.VARIANT |
+ SqlTypeName.UUID =>
reducedValues.add(unreduced)
case SqlTypeName.VARCHAR | SqlTypeName.CHAR =>
val escapeVarchar = BinaryStringDataUtil.safeToString(
@@ -274,7 +274,7 @@ class ExpressionReducer(
// we don't support object literals yet, we skip those constant
expressions
case (SqlTypeName.ANY, _) | (SqlTypeName.OTHER, _) | (SqlTypeName.ROW,
_) |
(SqlTypeName.STRUCTURED, _) | (SqlTypeName.ARRAY, _) |
(SqlTypeName.MAP, _) |
- (SqlTypeName.MULTISET, _) | (SqlTypeName.VARIANT, _) =>
+ (SqlTypeName.MULTISET, _) | (SqlTypeName.VARIANT, _) |
(SqlTypeName.UUID, _) =>
None
case (_, call: RexCall) => {
diff --git
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/GenerateUtils.scala
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/GenerateUtils.scala
index 8a864de361c..d8b2490ac61 100644
---
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/GenerateUtils.scala
+++
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/GenerateUtils.scala
@@ -314,7 +314,7 @@ object GenerateUtils {
// so that the literalValue can be also used directly when needed
generateNonNullLiteral(literalType, field, str)
- case BINARY | VARBINARY =>
+ case BINARY | VARBINARY | UUID =>
val bytesVal = literalValue.asInstanceOf[Array[Byte]]
val fieldTerm =
ctx.addReusableObject(bytesVal, "binary",
bytesVal.getClass.getCanonicalName)
diff --git
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/plan/metadata/FlinkRelMdSize.scala
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/plan/metadata/FlinkRelMdSize.scala
index c5f66f8c46e..a05ab9a01fb 100644
---
a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/plan/metadata/FlinkRelMdSize.scala
+++
b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/plan/metadata/FlinkRelMdSize.scala
@@ -435,7 +435,7 @@ object FlinkRelMdSize {
SqlTypeName.DATE =>
12d
case SqlTypeName.ANY | SqlTypeName.OTHER => 128d // 128 is an arbitrary
estimate
- case SqlTypeName.BINARY | SqlTypeName.VARBINARY | SqlTypeName.VARIANT =>
+ case SqlTypeName.BINARY | SqlTypeName.VARBINARY | SqlTypeName.VARIANT |
SqlTypeName.UUID =>
16d // 16 is an arbitrary estimate
case _ => throw new TableException(s"Unsupported data type encountered:
$sqlType")
}
diff --git
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/stream/UuidSemanticTest.java
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/stream/UuidSemanticTest.java
new file mode 100644
index 00000000000..debd1873403
--- /dev/null
+++
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/stream/UuidSemanticTest.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.planner.plan.nodes.exec.stream;
+
+import org.apache.flink.table.api.DataTypes;
+import
org.apache.flink.table.planner.plan.nodes.exec.testutils.SemanticTestBase;
+import org.apache.flink.table.test.program.TableTestProgram;
+
+import java.util.List;
+
+/** Semantic tests for the {@link DataTypes#UUID()} type. */
+public class UuidSemanticTest extends SemanticTestBase {
+
+ @Override
+ public List<TableTestProgram> programs() {
+ return List.of(
+ UuidTestPrograms.UUID_SOURCE_SINK,
+ UuidTestPrograms.UUID_LITERAL,
+ UuidTestPrograms.UUID_ARRAY,
+ UuidTestPrograms.UUID_MAP,
+ UuidTestPrograms.UUID_NESTED_ROW,
+ UuidTestPrograms.UUID_INVALID_LITERAL);
+ }
+}
diff --git
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/stream/UuidTestPrograms.java
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/stream/UuidTestPrograms.java
new file mode 100644
index 00000000000..4e60704520c
--- /dev/null
+++
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/nodes/exec/stream/UuidTestPrograms.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.planner.plan.nodes.exec.stream;
+
+import org.apache.flink.table.api.DataTypes;
+import org.apache.flink.table.api.ValidationException;
+import org.apache.flink.table.test.program.SinkTestStep;
+import org.apache.flink.table.test.program.SourceTestStep;
+import org.apache.flink.table.test.program.TableTestProgram;
+import org.apache.flink.types.Row;
+
+import java.util.Map;
+import java.util.UUID;
+
+/** {@link TableTestProgram}s for the {@link DataTypes#UUID()} type. */
+public class UuidTestPrograms {
+
+ private static final String LITERAL_A =
"550e8400-e29b-41d4-a716-446655440000";
+ private static final String LITERAL_B =
"f47ac10b-58cc-4372-a567-0e02b2c3d479";
+ private static final UUID UUID_A = UUID.fromString(LITERAL_A);
+ private static final UUID UUID_B = UUID.fromString(LITERAL_B);
+
+ private static SourceTestStep singleRowDriver() {
+ return SourceTestStep.newBuilder("t").addSchema("d
INT").producedValues(Row.of(1)).build();
+ }
+
+ static final TableTestProgram UUID_SOURCE_SINK =
+ TableTestProgram.of("uuid-source-sink", "round-trips a UUID column
including null")
+ .setupTableSource(
+ SourceTestStep.newBuilder("t")
+ .addSchema("id UUID")
+ .producedValues(Row.of(UUID_A),
Row.of(UUID_B), new Row(1))
+ .build())
+ .setupTableSink(
+ SinkTestStep.newBuilder("sink_t")
+ .addSchema("id UUID")
+ .consumedValues(Row.of(UUID_A),
Row.of(UUID_B), new Row(1))
+ .build())
+ .runSql("INSERT INTO sink_t SELECT id FROM t")
+ .build();
+
+ static final TableTestProgram UUID_LITERAL =
+ TableTestProgram.of("uuid-literal", "materializes a UUID literal")
+ .setupTableSource(singleRowDriver())
+ .setupTableSink(
+ SinkTestStep.newBuilder("sink_t")
+ .addSchema("u UUID")
+ .consumedValues(Row.of(UUID_A))
+ .build())
+ .runSql("INSERT INTO sink_t SELECT UUID '" + LITERAL_A +
"' FROM t")
+ .build();
+
+ static final TableTestProgram UUID_ARRAY =
+ TableTestProgram.of("uuid-array", "reads UUID array elements")
+ .setupTableSource(singleRowDriver())
+ .setupTableSink(
+ SinkTestStep.newBuilder("sink_t")
+ .addSchema("arr ARRAY<UUID>")
+ .consumedValues(Row.of((Object) new UUID[]
{UUID_A, UUID_B}))
+ .build())
+ .runSql(
+ "INSERT INTO sink_t SELECT ARRAY[UUID '"
+ + LITERAL_A
+ + "', UUID '"
+ + LITERAL_B
+ + "'] FROM t")
+ .build();
+
+ static final TableTestProgram UUID_MAP =
+ TableTestProgram.of("uuid-map", "reads a UUID map value")
+ .setupTableSource(singleRowDriver())
+ .setupTableSink(
+ SinkTestStep.newBuilder("sink_t")
+ .addSchema("m MAP<STRING, UUID>")
+ .consumedValues(Row.of(Map.of("a",
UUID_A)))
+ .build())
+ .runSql("INSERT INTO sink_t SELECT MAP['a', UUID '" +
LITERAL_A + "'] FROM t")
+ .build();
+
+ static final TableTestProgram UUID_NESTED_ROW =
+ TableTestProgram.of("uuid-nested-row", "reads a UUID field of a
nested row")
+ .setupTableSource(singleRowDriver())
+ .setupTableSink(
+ SinkTestStep.newBuilder("sink_t")
+ .addSchema("r ROW<f0 UUID, f1 INT>")
+ .consumedValues(Row.of(Row.of(UUID_A, 42)))
+ .build())
+ .runSql("INSERT INTO sink_t SELECT (UUID '" + LITERAL_A +
"', 42) FROM t")
+ .build();
+
+ static final TableTestProgram UUID_INVALID_LITERAL =
+ TableTestProgram.of("uuid-invalid-literal", "rejects a malformed
UUID literal")
+ .setupTableSource(singleRowDriver())
+ .runFailingSql(
+ "SELECT UUID 'abcd' FROM t",
+ ValidationException.class,
+ "Invalid UUID string: abcd")
+ .build();
+}
diff --git
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/conversion/DataStructureConverters.java
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/conversion/DataStructureConverters.java
index f01a1aca779..9d7ffdaea3d 100644
---
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/conversion/DataStructureConverters.java
+++
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/conversion/DataStructureConverters.java
@@ -41,6 +41,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.UUID;
import java.util.function.Supplier;
/**
@@ -197,6 +198,8 @@ public final class DataStructureConverters {
putConverter(LogicalTypeRoot.STRUCTURED_TYPE, RowData.class,
identity());
putConverter(LogicalTypeRoot.RAW, byte[].class,
RawByteArrayConverter::create);
putConverter(LogicalTypeRoot.RAW, RawValueData.class, identity());
+ putConverter(LogicalTypeRoot.UUID, UUID.class,
constructor(UuidUuidConverter::new));
+ putConverter(LogicalTypeRoot.UUID, byte[].class, identity());
putConverter(LogicalTypeRoot.VARIANT, Variant.class, identity());
putConverter(LogicalTypeRoot.BITMAP, Bitmap.class,
constructor(BitmapBitmapConverter::new));
putConverter(LogicalTypeRoot.BITMAP, RoaringBitmapData.class,
identity());
diff --git
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/conversion/UuidUuidConverter.java
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/conversion/UuidUuidConverter.java
new file mode 100644
index 00000000000..a3f97f9da6c
--- /dev/null
+++
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/conversion/UuidUuidConverter.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.data.conversion;
+
+import org.apache.flink.annotation.Internal;
+import org.apache.flink.table.types.logical.UuidType;
+
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Converter for {@link UuidType} of {@link UUID} external type.
+ *
+ * <p>The internal representation is the canonical 16-byte big-endian
encoding: the most significant
+ * 64 bits followed by the least significant 64 bits.
+ */
+@Internal
+public class UuidUuidConverter implements DataStructureConverter<byte[], UUID>
{
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public byte[] toInternal(UUID external) {
+ return ByteBuffer.allocate(16)
+ .putLong(external.getMostSignificantBits())
+ .putLong(external.getLeastSignificantBits())
+ .array();
+ }
+
+ @Override
+ public UUID toExternal(byte[] internal) {
+ final ByteBuffer buffer = ByteBuffer.wrap(internal);
+ final long mostSignificantBits = buffer.getLong();
+ final long leastSignificantBits = buffer.getLong();
+ return new UUID(mostSignificantBits, leastSignificantBits);
+ }
+}
diff --git
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/writer/BinaryArrayWriter.java
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/writer/BinaryArrayWriter.java
index 857c2ecd424..0bfebd4cb99 100644
---
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/writer/BinaryArrayWriter.java
+++
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/writer/BinaryArrayWriter.java
@@ -247,6 +247,7 @@ public final class BinaryArrayWriter extends
AbstractBinaryWriter {
case RAW:
case VARIANT:
case BITMAP:
+ case UUID:
return BinaryArrayWriter::setNullLong;
case BOOLEAN:
return BinaryArrayWriter::setNullBoolean;
diff --git
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/writer/BinaryWriter.java
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/writer/BinaryWriter.java
index 4db8977ccd2..13efc76cf56 100644
---
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/writer/BinaryWriter.java
+++
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/data/writer/BinaryWriter.java
@@ -166,6 +166,7 @@ public interface BinaryWriter {
break;
case BINARY:
case VARBINARY:
+ case UUID:
writer.writeBinary(pos, (byte[]) o);
break;
case VARIANT:
@@ -194,6 +195,7 @@ public interface BinaryWriter {
return (writer, pos, value) -> writer.writeBoolean(pos,
(boolean) value);
case BINARY:
case VARBINARY:
+ case UUID:
return (writer, pos, value) -> writer.writeBinary(pos,
(byte[]) value);
case DECIMAL:
final int decimalPrecision = getPrecision(elementType);
diff --git
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/runtime/typeutils/InternalSerializers.java
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/runtime/typeutils/InternalSerializers.java
index 4334591cbd1..ef4d7477634 100644
---
a/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/runtime/typeutils/InternalSerializers.java
+++
b/flink-table/flink-table-type-utils/src/main/java/org/apache/flink/table/runtime/typeutils/InternalSerializers.java
@@ -75,6 +75,7 @@ public final class InternalSerializers {
return BooleanSerializer.INSTANCE;
case BINARY:
case VARBINARY:
+ case UUID:
return BytePrimitiveArraySerializer.INSTANCE;
case DECIMAL:
return new DecimalDataSerializer(getPrecision(type),
getScale(type));
diff --git
a/flink-table/flink-table-type-utils/src/test/java/org/apache/flink/table/data/DataStructureConvertersTest.java
b/flink-table/flink-table-type-utils/src/test/java/org/apache/flink/table/data/DataStructureConvertersTest.java
index 2c19c579a4e..8336f90a182 100644
---
a/flink-table/flink-table-type-utils/src/test/java/org/apache/flink/table/data/DataStructureConvertersTest.java
+++
b/flink-table/flink-table-type-utils/src/test/java/org/apache/flink/table/data/DataStructureConvertersTest.java
@@ -57,6 +57,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.UUID;
import java.util.function.Supplier;
import static java.util.Arrays.asList;
@@ -108,6 +109,10 @@ class DataStructureConvertersTest {
.convertedTo(byte[].class, new byte[] {1, 2, 3, 4, 5}),
TestSpec.forDataType(VARBINARY(100))
.convertedTo(byte[].class, new byte[] {1, 2, 3, 4, 5}),
+ TestSpec.forDataType(DataTypes.UUID())
+ .convertedTo(
+ UUID.class,
+
UUID.fromString("550e8400-e29b-41d4-a716-446655440000")),
TestSpec.forDataType(DECIMAL(3, 2))
.convertedTo(BigDecimal.class, new BigDecimal("1.23"))
.convertedTo(DecimalData.class,
DecimalData.fromUnscaledLong(123, 3, 2)),
diff --git
a/flink-tests/src/test/java/org/apache/flink/test/completeness/TypeSerializerTestCoverageTest.java
b/flink-tests/src/test/java/org/apache/flink/test/completeness/TypeSerializerTestCoverageTest.java
index b46b69ddcc6..7f91776f841 100644
---
a/flink-tests/src/test/java/org/apache/flink/test/completeness/TypeSerializerTestCoverageTest.java
+++
b/flink-tests/src/test/java/org/apache/flink/test/completeness/TypeSerializerTestCoverageTest.java
@@ -31,6 +31,7 @@ import
org.apache.flink.api.common.typeutils.base.LocalDateTimeSerializer;
import org.apache.flink.api.common.typeutils.base.LocalTimeSerializer;
import org.apache.flink.api.common.typeutils.base.NullValueSerializer;
import org.apache.flink.api.common.typeutils.base.SetSerializer;
+import org.apache.flink.api.common.typeutils.base.UuidSerializer;
import org.apache.flink.api.common.typeutils.base.VoidSerializer;
import
org.apache.flink.api.common.typeutils.base.array.BooleanPrimitiveArraySerializer;
import
org.apache.flink.api.common.typeutils.base.array.BytePrimitiveArraySerializer;
@@ -269,7 +270,8 @@ class TypeSerializerTestCoverageTest {
RowSqnInfoSerializer.class.getName(),
MetaSqnInfoSerializer.class.getName(),
SetSerializer.class.getName(),
- SortedLongSerializer.class.getName());
+ SortedLongSerializer.class.getName(),
+ UuidSerializer.class.getName());
// check if a test exists for each type serializer
for (Class<? extends TypeSerializer> typeSerializer : typeSerializers)
{