This is an automated email from the ASF dual-hosted git repository.
tanner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 4e6c403842 [CALCITE-5935] Add CODE_POINTS_TO_BYTES function (enabled
in BigQuery library)
4e6c403842 is described below
commit 4e6c403842bebc519b1a1ededc9c2311059d7cb2
Author: macroguo <[email protected]>
AuthorDate: Tue Aug 22 17:59:02 2023 +0800
[CALCITE-5935] Add CODE_POINTS_TO_BYTES function (enabled in BigQuery
library)
---
babel/src/test/resources/sql/big-query.iq | 58 ++++++++++++++++++++++
.../calcite/adapter/enumerable/RexImpTable.java | 3 ++
.../apache/calcite/runtime/CalciteResource.java | 3 ++
.../org/apache/calcite/runtime/SqlFunctions.java | 22 ++++++++
.../calcite/sql/fun/SqlLibraryOperators.java | 7 +++
.../org/apache/calcite/sql/type/OperandTypes.java | 32 ++++++++++++
.../org/apache/calcite/util/BuiltInMethod.java | 1 +
.../calcite/runtime/CalciteResource.properties | 1 +
site/_docs/reference.md | 1 +
.../org/apache/calcite/test/SqlOperatorTest.java | 31 ++++++++++++
10 files changed, 159 insertions(+)
diff --git a/babel/src/test/resources/sql/big-query.iq
b/babel/src/test/resources/sql/big-query.iq
index d50969b81a..2479eb3663 100755
--- a/babel/src/test/resources/sql/big-query.iq
+++ b/babel/src/test/resources/sql/big-query.iq
@@ -1971,6 +1971,64 @@ SELECT CONTAINS_SUBSTR('{"lunch":"soup"}', "lunch",
json_scope=>"JSON_KEYS_AND_V
!ok
+#####################################################################
+# CODE_POINTS_TO_BYTES(array<integer>)
+#
+# Takes an array of extended ASCII code points as ARRAY<INT64>
+# and returns BYTES.
+#
+SELECT CODE_POINTS_TO_BYTES(array[65, 66, 67, 68]) as result;
++----------+
+| result |
++----------+
+| 41424344 |
++----------+
+(1 row)
+
+!ok
+
+SELECT CODE_POINTS_TO_BYTES(array[255, 254, 65, 64]) as result;
++----------+
+| result |
++----------+
+| fffe4140 |
++----------+
+(1 row)
+
+!ok
+
+SELECT CODE_POINTS_TO_BYTES(null) as result;
++--------+
+| result |
++--------+
+| |
++--------+
+(1 row)
+
+!ok
+
+SELECT CODE_POINTS_TO_BYTES(array[65, null]) as result;
++--------+
+| result |
++--------+
+| |
++--------+
+(1 row)
+
+!ok
+
+SELECT CODE_POINTS_TO_BYTES('abc') as result;
+Cannot apply 'CODE_POINTS_TO_BYTES' to arguments of type
'CODE_POINTS_TO_BYTES(<CHAR(3)>)'. Supported form(s):
CODE_POINTS_TO_BYTES(<INTEGER ARRAY>)
+!error
+
+SELECT CODE_POINTS_TO_BYTES(array[-1]) as result;
+Input arguments of CODE_POINTS_TO_BYTES out of range: -1
+!error
+
+SELECT CODE_POINTS_TO_BYTES(array[2147483648, 1]);
+Input arguments of CODE_POINTS_TO_BYTES out of range: 2147483648
+!error
+
#####################################################################
# DATE
#
diff --git
a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 91a7aed9b0..03d7a07c0f 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -150,6 +150,7 @@ import static
org.apache.calcite.sql.fun.SqlLibraryOperators.BOOL_OR;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.CEIL_BIG_QUERY;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.CHAR;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.CHR;
+import static
org.apache.calcite.sql.fun.SqlLibraryOperators.CODE_POINTS_TO_BYTES;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.COMPRESS;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.CONCAT2;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.CONCAT_FUNCTION;
@@ -564,6 +565,8 @@ public class RexImpTable {
defineMethod(ASCII, BuiltInMethod.ASCII.method, NullPolicy.STRICT);
defineMethod(CHAR, BuiltInMethod.CHAR_FROM_ASCII.method,
NullPolicy.SEMI_STRICT);
+ defineMethod(CODE_POINTS_TO_BYTES,
BuiltInMethod.CODE_POINTS_TO_BYTES.method,
+ NullPolicy.STRICT);
defineMethod(REPEAT, BuiltInMethod.REPEAT.method, NullPolicy.STRICT);
defineMethod(SPACE, BuiltInMethod.SPACE.method, NullPolicy.STRICT);
defineMethod(STRCMP, BuiltInMethod.STRCMP.method, NullPolicy.STRICT);
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index 230f2ea0ca..832e3715d4 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -298,6 +298,9 @@ public interface CalciteResource {
@BaseMessage("Date literal ''{0}'' out of range")
ExInst<SqlValidatorException> dateLiteralOutOfRange(String a0);
+ @BaseMessage("Input arguments of CODE_POINTS_TO_BYTES out of range:
{0,number,#}")
+ ExInst<CalciteException> inputArgumentsOfCodePointsToBytesOutOfRange(long
a0);
+
@BaseMessage("String literal continued on same line")
ExInst<SqlValidatorException> stringFragsOnSameLine();
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index efeac7d0ef..835eb068b4 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -1116,6 +1116,28 @@ public class SqlFunctions {
return String.valueOf(Character.toChars(n));
}
+ /**
+ * SQL CODE_POINTS_TO_BYTES function.
+ */
+ public static @Nullable ByteString codePointsToBytes(List codePoints) {
+ int length = codePoints.size();
+ byte[] bytes = new byte[length];
+ for (int i = 0; i < length; i++) {
+ Object codePoint = codePoints.get(i);
+ if (codePoint == null) {
+ return null;
+ }
+ assert codePoint instanceof Number;
+ long cp = ((Number) codePoint).longValue();
+ if (cp < 0 || cp > 255) {
+ throw RESOURCE.inputArgumentsOfCodePointsToBytesOutOfRange(cp).ex();
+ }
+ bytes[i] = (byte) cp;
+ }
+
+ return new ByteString(bytes);
+ }
+
/** SQL OCTET_LENGTH(binary) function. */
public static int octetLength(ByteString s) {
return s.length();
diff --git
a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
index 42492d97e7..98ecf893c2 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
@@ -1786,6 +1786,13 @@ public abstract class SqlLibraryOperators {
OperandTypes.INTEGER,
SqlFunctionCategory.STRING);
+ @LibraryOperator(libraries = {BIG_QUERY})
+ public static final SqlFunction CODE_POINTS_TO_BYTES =
+ SqlBasicFunction.create("CODE_POINTS_TO_BYTES",
+ ReturnTypes.VARBINARY_NULLABLE,
+ OperandTypes.ARRAY_OF_INTEGER,
+ SqlFunctionCategory.STRING);
+
@LibraryOperator(libraries = {ALL})
public static final SqlFunction TANH =
SqlBasicFunction.create("TANH",
diff --git a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
index d60c6fa72c..8f77ddedd9 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
@@ -513,6 +513,38 @@ public abstract class OperandTypes {
}
};
+ public static final SqlSingleOperandTypeChecker ARRAY_OF_INTEGER =
+ new FamilyOperandTypeChecker(ImmutableList.of(SqlTypeFamily.ARRAY), i ->
false) {
+ @Override public boolean checkSingleOperandType(SqlCallBinding
callBinding, SqlNode operand,
+ int iFormalOperand, SqlTypeFamily family, boolean throwOnFailure) {
+ if (!super.checkSingleOperandType(
+ callBinding,
+ operand,
+ iFormalOperand,
+ family,
+ throwOnFailure)) {
+ return false;
+ }
+ RelDataType type = SqlTypeUtil.deriveType(callBinding, operand);
+ if (SqlTypeUtil.isNull(type)) {
+ return true;
+ }
+ RelDataType componentType =
+ requireNonNull(type.getComponentType(), "componentType");
+ if (SqlTypeUtil.isIntType(componentType) ||
SqlTypeUtil.isNull(componentType)) {
+ return true;
+ }
+
+ if (throwOnFailure) {
+ throw callBinding.newValidationSignatureError();
+ }
+ return false;
+ }
+
+ @Override public String getAllowedSignatures(SqlOperator op, String
opName) {
+ return opName + "(<INTEGER ARRAY>)";
+ }
+ };
/** Checks that returns whether a value is a multiset or an array.
* Cf Java, where list and set are collections but a map is not. */
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index 3b8b3f4910..6d7eedd10f 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -356,6 +356,7 @@ public enum BuiltInMethod {
ASCII(SqlFunctions.class, "ascii", String.class),
CHAR_FROM_ASCII(SqlFunctions.class, "charFromAscii", int.class),
CHAR_FROM_UTF8(SqlFunctions.class, "charFromUtf8", int.class),
+ CODE_POINTS_TO_BYTES(SqlFunctions.class, "codePointsToBytes", List.class),
CONVERT(SqlFunctions.class, "convertWithCharset", String.class, String.class,
String.class),
EXP(SqlFunctions.class, "exp", double.class),
diff --git
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
index 1033899a30..a1ed50de6d 100644
---
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -102,6 +102,7 @@ OperandNotComparable=Operands {0} not comparable to each
other
TypeNotComparableEachOther=Types {0} not comparable to each other
NumberLiteralOutOfRange=Numeric literal ''{0}'' out of range
DateLiteralOutOfRange=Date literal ''{0}'' out of range
+InputArgumentsOfCodePointsToBytesOutOfRange=Input arguments of
CODE_POINTS_TO_BYTES out of range: {0,number,#}
StringFragsOnSameLine=String literal continued on same line
AliasMustBeSimpleIdentifier=Table or column alias must be a simple identifier
CharLiteralAliasNotValid=Expecting alias, found character literal
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index ccb79bc1f4..6c0b9c2a63 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2685,6 +2685,7 @@ BigQuery's type system uses confusingly different names
for types and functions:
| b | CEIL(value) | Similar to standard
`CEIL(value)` except if *value* is an integer type, the return type is a double
| m s | CHAR(integer) | Returns the character
whose ASCII code is *integer* % 256, or null if *integer* < 0
| b o p | CHR(integer) | Returns the character
whose UTF-8 code is *integer*
+| b | CODE_POINTS_TO_BYTES(integers) | Converts *integers*, an
array of integers between 0 and 255 inclusive, into bytes; throws error if any
element is out of range
| o | CONCAT(string, string) | Concatenates two
strings, returns null only when both string arguments are null, otherwise
treats null as empty string
| b m | CONCAT(string [, string ]*) | Concatenates one or
more strings, returns null if any of the arguments is null
| p q | CONCAT(string [, string ]*) | Concatenates one or
more strings, null is treated as empty string
diff --git a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
index 5352779c16..f2ad858e95 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -1804,6 +1804,37 @@ public class SqlOperatorTest {
consumer);
}
+ @Test void testCodePointsToBytes() {
+ final SqlOperatorFixture f = fixture()
+ .setFor(SqlLibraryOperators.CODE_POINTS_TO_BYTES, VM_FENNEL, VM_JAVA)
+ .withLibrary(SqlLibrary.BIG_QUERY);
+ f.checkFails("^code_points_to_bytes('abc')^",
+ "Cannot apply 'CODE_POINTS_TO_BYTES' to arguments of type "
+ + "'CODE_POINTS_TO_BYTES\\(<CHAR\\(3\\)>\\)'\\. "
+ + "Supported form\\(s\\): CODE_POINTS_TO_BYTES\\(<INTEGER
ARRAY>\\)",
+ false);
+ f.checkFails("^code_points_to_bytes(array['abc'])^",
+ "Cannot apply 'CODE_POINTS_TO_BYTES' to arguments of type "
+ + "'CODE_POINTS_TO_BYTES\\(<CHAR\\(3\\) ARRAY>\\)'\\. "
+ + "Supported form\\(s\\): CODE_POINTS_TO_BYTES\\(<INTEGER
ARRAY>\\)",
+ false);
+
+ f.checkFails("code_points_to_bytes(array[-1])",
+ "Input arguments of CODE_POINTS_TO_BYTES out of range: -1", true);
+ f.checkFails("code_points_to_bytes(array[2147483648, 1])",
+ "Input arguments of CODE_POINTS_TO_BYTES out of range: 2147483648",
true);
+
+ f.checkString("code_points_to_bytes(array[65, 66, 67, 68])", "41424344",
"VARBINARY NOT NULL");
+ f.checkString("code_points_to_bytes(array[255, 254, 65, 64])", "fffe4140",
+ "VARBINARY NOT NULL");
+ f.checkString("code_points_to_bytes(array[1+2, 3, 4])", "030304",
+ "VARBINARY NOT NULL");
+
+ f.checkNull("code_points_to_bytes(null)");
+ f.checkNull("code_points_to_bytes(array[null])");
+ f.checkNull("code_points_to_bytes(array[65, null])");
+ }
+
@Test void testSelect() {
final SqlOperatorFixture f = fixture();
f.check("select * from (values(1))", SqlTests.INTEGER_TYPE_CHECKER, 1);