You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by tw...@apache.org on 2019/06/19 08:15:01 UTC
[flink] branch master updated: [FLINK-12874][table-common] Improve
the semantics of zero length strings
This is an automated email from the ASF dual-hosted git repository.
twalthr 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 2a3ac58 [FLINK-12874][table-common] Improve the semantics of zero length strings
2a3ac58 is described below
commit 2a3ac580abf5b32c341fe921c1eacbb395b27f25
Author: Timo Walther <tw...@apache.org>
AuthorDate: Tue Jun 18 11:08:27 2019 +0200
[FLINK-12874][table-common] Improve the semantics of zero length strings
This closes #8781.
---
.../flink/table/types/logical/BinaryType.java | 12 ++++++
.../apache/flink/table/types/logical/CharType.java | 12 ++++++
.../flink/table/types/logical/VarBinaryType.java | 35 +++++++++++++++++-
.../flink/table/types/logical/VarCharType.java | 34 ++++++++++++++++-
.../apache/flink/table/types/LogicalTypesTest.java | 43 ++++++++++++++++++++--
5 files changed, 131 insertions(+), 5 deletions(-)
diff --git a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/BinaryType.java b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/BinaryType.java
index 25dbcd4..8a013c6 100644
--- a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/BinaryType.java
+++ b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/BinaryType.java
@@ -19,6 +19,7 @@
package org.apache.flink.table.types.logical;
import org.apache.flink.annotation.PublicEvolving;
+import org.apache.flink.table.api.TableException;
import org.apache.flink.table.api.ValidationException;
import java.util.Collections;
@@ -91,6 +92,8 @@ public final class BinaryType extends LogicalType {
* For consistent behavior, the same logic applies to binary strings.
*
* <p>This method enables this special kind of binary string.
+ *
+ * <p>Zero-length binary strings have no serializable string representation.
*/
public static BinaryType ofEmptyLiteral() {
return new BinaryType(EMPTY_LITERAL_LENGTH, false);
@@ -107,6 +110,15 @@ public final class BinaryType extends LogicalType {
@Override
public String asSerializableString() {
+ if (length == EMPTY_LITERAL_LENGTH) {
+ throw new TableException(
+ "Zero-length binary strings have no serializable string representation.");
+ }
+ return withNullability(FORMAT, length);
+ }
+
+ @Override
+ public String asSummaryString() {
return withNullability(FORMAT, length);
}
diff --git a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/CharType.java b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/CharType.java
index 8385d05..fbff544 100644
--- a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/CharType.java
+++ b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/CharType.java
@@ -19,6 +19,7 @@
package org.apache.flink.table.types.logical;
import org.apache.flink.annotation.PublicEvolving;
+import org.apache.flink.table.api.TableException;
import org.apache.flink.table.api.ValidationException;
import java.util.Collections;
@@ -93,6 +94,8 @@ public final class CharType extends LogicalType {
* (i.e., to contain no characters) even though it is not permitted to declare a type that is zero.
*
* <p>This method enables this special kind of character string.
+ *
+ * <p>Zero-length character strings have no serializable string representation.
*/
public static CharType ofEmptyLiteral() {
return new CharType(EMPTY_LITERAL_LENGTH, false);
@@ -109,6 +112,15 @@ public final class CharType extends LogicalType {
@Override
public String asSerializableString() {
+ if (length == EMPTY_LITERAL_LENGTH) {
+ throw new TableException(
+ "Zero-length character strings have no serializable string representation.");
+ }
+ return withNullability(FORMAT, length);
+ }
+
+ @Override
+ public String asSummaryString() {
return withNullability(FORMAT, length);
}
diff --git a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/VarBinaryType.java b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/VarBinaryType.java
index 4928fd4..538d947 100644
--- a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/VarBinaryType.java
+++ b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/VarBinaryType.java
@@ -19,6 +19,7 @@
package org.apache.flink.table.types.logical;
import org.apache.flink.annotation.PublicEvolving;
+import org.apache.flink.table.api.TableException;
import org.apache.flink.table.api.ValidationException;
import java.util.Collections;
@@ -33,10 +34,15 @@ import java.util.Set;
* number of bytes. {@code n} must have a value between 1 and {@link Integer#MAX_VALUE} (both
* inclusive). If no length is specified, {@code n} is equal to 1. {@code BYTES} is a synonym for
* {@code VARBINARY(2147483647)}.
+ *
+ * <p>For enabling type inference of a zero-length binary string literal to a variable-length binary
+ * string, this type does also support {@code n} to be 0. However, this is not exposed through the API.
*/
@PublicEvolving
public final class VarBinaryType extends LogicalType {
+ public static final int EMPTY_LITERAL_LENGTH = 0;
+
public static final int MIN_LENGTH = 1;
public static final int MAX_LENGTH = Integer.MAX_VALUE;
@@ -75,17 +81,44 @@ public final class VarBinaryType extends LogicalType {
this(DEFAULT_LENGTH);
}
+ /**
+ * Helper constructor for {@link #ofEmptyLiteral()} and {@link #copy(boolean)}.
+ */
+ private VarBinaryType(int length, boolean isNullable) {
+ super(isNullable, LogicalTypeRoot.VARBINARY);
+ this.length = length;
+ }
+
+ /**
+ * The SQL standard defines that character string literals are allowed to be zero-length strings
+ * (i.e., to contain no characters) even though it is not permitted to declare a type that is zero.
+ * For consistent behavior, the same logic applies to binary strings. This has also implications
+ * on variable-length binary strings during type inference because any fixed-length binary string
+ * should be convertible to a variable-length one.
+ *
+ * <p>This method enables this special kind of binary string.
+ *
+ * <p>Zero-length binary strings have no serializable string representation.
+ */
+ public static VarBinaryType ofEmptyLiteral() {
+ return new VarBinaryType(EMPTY_LITERAL_LENGTH, false);
+ }
+
public int getLength() {
return length;
}
@Override
public LogicalType copy(boolean isNullable) {
- return new VarBinaryType(isNullable, length);
+ return new VarBinaryType(length, isNullable);
}
@Override
public String asSerializableString() {
+ if (length == EMPTY_LITERAL_LENGTH) {
+ throw new TableException(
+ "Zero-length binary strings have no serializable string representation.");
+ }
return withNullability(FORMAT, length);
}
diff --git a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/VarCharType.java b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/VarCharType.java
index 1e1f04c..2c73ec6 100644
--- a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/VarCharType.java
+++ b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/logical/VarCharType.java
@@ -19,6 +19,7 @@
package org.apache.flink.table.types.logical;
import org.apache.flink.annotation.PublicEvolving;
+import org.apache.flink.table.api.TableException;
import org.apache.flink.table.api.ValidationException;
import java.util.Collections;
@@ -34,11 +35,16 @@ import java.util.Set;
* inclusive). If no length is specified, {@code n} is equal to 1. {@code STRING} is a synonym for
* {@code VARCHAR(2147483647)}.
*
+ * <p>For enabling type inference of a zero-length character string literal to a variable-length character
+ * string, this type does also support {@code n} to be 0. However, this is not exposed through the API.
+ *
* <p>A conversion from and to {@code byte[]} assumes UTF-8 encoding.
*/
@PublicEvolving
public final class VarCharType extends LogicalType {
+ public static final int EMPTY_LITERAL_LENGTH = 0;
+
public static final int MIN_LENGTH = 1;
public static final int MAX_LENGTH = Integer.MAX_VALUE;
@@ -78,17 +84,43 @@ public final class VarCharType extends LogicalType {
this(DEFAULT_LENGTH);
}
+ /**
+ * Helper constructor for {@link #ofEmptyLiteral()} and {@link #copy(boolean)}.
+ */
+ private VarCharType(int length, boolean isNullable) {
+ super(isNullable, LogicalTypeRoot.VARCHAR);
+ this.length = length;
+ }
+
+ /**
+ * The SQL standard defines that character string literals are allowed to be zero-length strings
+ * (i.e., to contain no characters) even though it is not permitted to declare a type that is zero.
+ * This has also implications on variable-length character strings during type inference because any
+ * fixed-length character string should be convertible to a variable-length one.
+ *
+ * <p>This method enables this special kind of character string.
+ *
+ * <p>Zero-length character strings have no serializable string representation.
+ */
+ public static VarCharType ofEmptyLiteral() {
+ return new VarCharType(EMPTY_LITERAL_LENGTH, false);
+ }
+
public int getLength() {
return length;
}
@Override
public LogicalType copy(boolean isNullable) {
- return new VarCharType(isNullable, length);
+ return new VarCharType(length, isNullable);
}
@Override
public String asSerializableString() {
+ if (length == EMPTY_LITERAL_LENGTH) {
+ throw new TableException(
+ "Zero-length character strings have no serializable string representation.");
+ }
return withNullability(FORMAT, length);
}
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 bdc9d90..edf28cf 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
@@ -23,6 +23,7 @@ import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.typeutils.runtime.kryo.KryoSerializer;
+import org.apache.flink.table.api.TableException;
import org.apache.flink.table.api.ValidationException;
import org.apache.flink.table.catalog.ObjectIdentifier;
import org.apache.flink.table.expressions.TimeIntervalUnit;
@@ -61,7 +62,6 @@ import org.apache.flink.table.types.logical.ZonedTimestampType;
import org.apache.flink.types.Row;
import org.apache.flink.util.InstantiationUtil;
-import org.junit.Assert;
import org.junit.Test;
import java.math.BigDecimal;
@@ -564,6 +564,8 @@ public class LogicalTypesTest {
testJavaSerializability(anyType);
testConversions(anyType, new Class[]{Tuple2.class}, new Class[]{Tuple.class});
+
+ testInvalidStringSerializability(anyType);
}
@Test
@@ -603,6 +605,32 @@ public class LogicalTypesTest {
testJavaSerializability(symbolType);
testConversions(symbolType, new Class[]{TimeIntervalUnit.class}, new Class[]{TimeIntervalUnit.class});
+
+ testInvalidStringSerializability(symbolType);
+ }
+
+ @Test
+ public void testEmptyStringLiterals() {
+ final CharType charType = CharType.ofEmptyLiteral();
+ final VarCharType varcharType = VarCharType.ofEmptyLiteral();
+ final BinaryType binaryType = BinaryType.ofEmptyLiteral();
+ final VarBinaryType varBinaryType = VarBinaryType.ofEmptyLiteral();
+
+ // make the types nullable for testing
+ testEquality(charType.copy(true), new CharType(1));
+ testEquality(varcharType.copy(true), new VarCharType(1));
+ testEquality(binaryType.copy(true), new BinaryType(1));
+ testEquality(varBinaryType.copy(true), new VarBinaryType(1));
+
+ testStringSummary(charType, "CHAR(0) NOT NULL");
+ testStringSummary(varcharType, "VARCHAR(0) NOT NULL");
+ testStringSummary(binaryType, "BINARY(0) NOT NULL");
+ testStringSummary(varBinaryType, "VARBINARY(0) NOT NULL");
+
+ testInvalidStringSerializability(charType);
+ testInvalidStringSerializability(varcharType);
+ testInvalidStringSerializability(binaryType);
+ testInvalidStringSerializability(varBinaryType);
}
// --------------------------------------------------------------------------------------------
@@ -664,11 +692,20 @@ public class LogicalTypesTest {
}
private static void testStringSerializability(LogicalType serializableType, String serializableString) {
- Assert.assertEquals(serializableString, serializableType.asSerializableString());
+ assertEquals(serializableString, serializableType.asSerializableString());
+ }
+
+ private static void testInvalidStringSerializability(LogicalType nonSerializableType) {
+ try {
+ final String serializedString = nonSerializableType.asSerializableString();
+ fail("No serializablility expected: " + serializedString);
+ } catch (TableException e) {
+ // ok
+ }
}
private static void testStringSummary(LogicalType type, String summaryString) {
- Assert.assertEquals(summaryString, type.asSummaryString());
+ assertEquals(summaryString, type.asSummaryString());
}
private static void testConversions(LogicalType type, Class[] inputs, Class[] outputs) {