This is an automated email from the ASF dual-hosted git repository. danny0405 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push: new 468f019 [CALCITE-3647] MySQL COMPRESS function support (ritesh-kapoor) 468f019 is described below commit 468f0190bbd1777671916c0adc57c7c6bd23a7a0 Author: Ritesh Kapoor <riteshkapoor.opensou...@gmail.com> AuthorDate: Fri Mar 6 11:44:48 2020 +0530 [CALCITE-3647] MySQL COMPRESS function support (ritesh-kapoor) close apache/calcite#1847 --- .../calcite/adapter/enumerable/RexImpTable.java | 4 ++ .../calcite/runtime/CompressionFunctions.java | 65 ++++++++++++++++++++++ .../calcite/sql/fun/SqlLibraryOperators.java | 6 ++ .../org/apache/calcite/util/BuiltInMethod.java | 2 + .../calcite/sql/test/SqlOperatorBaseTest.java | 17 ++++++ core/src/test/resources/sql/functions.iq | 13 +++++ site/_docs/reference.md | 1 + 7 files changed, 108 insertions(+) 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 dc2a6d2..2d713da 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 @@ -97,6 +97,7 @@ import static org.apache.calcite.linq4j.tree.ExpressionType.OrElse; import static org.apache.calcite.linq4j.tree.ExpressionType.Subtract; import static org.apache.calcite.linq4j.tree.ExpressionType.UnaryPlus; import static org.apache.calcite.sql.fun.SqlLibraryOperators.CHR; +import static org.apache.calcite.sql.fun.SqlLibraryOperators.COMPRESS; import static org.apache.calcite.sql.fun.SqlLibraryOperators.COSH; import static org.apache.calcite.sql.fun.SqlLibraryOperators.DAYNAME; import static org.apache.calcite.sql.fun.SqlLibraryOperators.DIFFERENCE; @@ -546,6 +547,9 @@ public class RexImpTable { defineMethod(CURRENT_VALUE, BuiltInMethod.SEQUENCE_CURRENT_VALUE.method, NullPolicy.STRICT); defineMethod(NEXT_VALUE, BuiltInMethod.SEQUENCE_NEXT_VALUE.method, NullPolicy.STRICT); + // Compression Operators + defineMethod(COMPRESS, BuiltInMethod.COMPRESS.method, NullPolicy.ARG0); + // Xml Operators defineMethod(EXTRACT_VALUE, BuiltInMethod.EXTRACT_VALUE.method, NullPolicy.ARG0); defineMethod(XML_TRANSFORM, BuiltInMethod.XML_TRANSFORM.method, NullPolicy.ARG0); diff --git a/core/src/main/java/org/apache/calcite/runtime/CompressionFunctions.java b/core/src/main/java/org/apache/calcite/runtime/CompressionFunctions.java new file mode 100644 index 0000000..d16c434 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/runtime/CompressionFunctions.java @@ -0,0 +1,65 @@ +/* + * 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.calcite.runtime; + +import org.apache.calcite.avatica.util.ByteString; + +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; +import java.util.zip.DeflaterOutputStream; + +/** + * A collection of functions used in compression and decompression. + */ +public class CompressionFunctions { + + private CompressionFunctions() { + } + + /** + * MySql Compression is based on zlib. + * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/zip/Deflater.html">Deflater</a> + * is used to implement compression. + */ + public static ByteString compress(String data) { + try { + if (data == null) { + return null; + } + if (StringUtils.isEmpty(data)) { + return new ByteString(new byte[0]); + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ByteBuffer dataLength = ByteBuffer.allocate(4); + dataLength.order(ByteOrder.LITTLE_ENDIAN); + dataLength.putInt(data.length()); + outputStream.write(dataLength.array()); + DeflaterOutputStream inflaterStream = new DeflaterOutputStream(outputStream); + inflaterStream.write(data.getBytes(Charset.defaultCharset())); + inflaterStream.close(); + return new ByteString(outputStream.toByteArray()); + } catch (IOException e) { + return null; + } + } + +} 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 3768323..b5a83bb 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 @@ -173,6 +173,12 @@ public abstract class SqlLibraryOperators { public static final SqlFunction REGEXP_REPLACE = new SqlRegexpReplaceFunction(); @LibraryOperator(libraries = {MYSQL}) + public static final SqlFunction COMPRESS = new SqlFunction("COMPRESS", SqlKind.OTHER_FUNCTION, + ReturnTypes.cascade(ReturnTypes.explicit(SqlTypeName.VARBINARY), + SqlTypeTransforms.TO_NULLABLE), null, OperandTypes.STRING, SqlFunctionCategory.STRING); + + + @LibraryOperator(libraries = {MYSQL}) public static final SqlFunction EXTRACT_VALUE = new SqlFunction( "EXTRACTVALUE", SqlKind.OTHER_FUNCTION, ReturnTypes.cascade(ReturnTypes.VARCHAR_2000, SqlTypeTransforms.FORCE_NULLABLE), 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 bb226a0..d2e2499 100644 --- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java +++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java @@ -79,6 +79,7 @@ import org.apache.calcite.runtime.ArrayBindable; import org.apache.calcite.runtime.Automaton; import org.apache.calcite.runtime.BinarySearch; import org.apache.calcite.runtime.Bindable; +import org.apache.calcite.runtime.CompressionFunctions; import org.apache.calcite.runtime.Enumerables; import org.apache.calcite.runtime.FlatLists; import org.apache.calcite.runtime.JsonFunctions; @@ -324,6 +325,7 @@ public enum BuiltInMethod { FROM_BASE64(SqlFunctions.class, "fromBase64", String.class), MD5(SqlFunctions.class, "md5", String.class), SHA1(SqlFunctions.class, "sha1", String.class), + COMPRESS(CompressionFunctions.class, "compress", String.class), EXTRACT_VALUE(XmlFunctions.class, "extractValue", String.class, String.class), XML_TRANSFORM(XmlFunctions.class, "xmlTransform", String.class, String.class), EXTRACT_XML(XmlFunctions.class, "extractXml", String.class, String.class, String.class), diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java index 8ad9f30..436aab8 100644 --- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java +++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java @@ -5175,6 +5175,23 @@ public abstract class SqlOperatorBaseTest { tester.checkBoolean("'[]' is not json scalar", true); } + @Test public void testCompress() { + SqlTester sqlTester = tester(SqlLibrary.MYSQL); + sqlTester.checkNull("COMPRESS(NULL)"); + sqlTester.checkString("COMPRESS('')", "", + "VARBINARY NOT NULL"); + + sqlTester.checkString("COMPRESS(REPEAT('a',1000))", + "e8030000789c4b4c1c05a360140c770000f9d87af8", "VARBINARY NOT NULL"); + sqlTester.checkString("COMPRESS(REPEAT('a',16))", + "10000000789c4b4c44050033980611", "VARBINARY NOT NULL"); + + sqlTester.checkString("COMPRESS('sample')", + "06000000789c2b4ecc2dc849050008de0283", "VARBINARY NOT NULL"); + sqlTester.checkString("COMPRESS('example')", + "07000000789c4bad48cc2dc84905000bc002ed", "VARBINARY NOT NULL"); + } + @Test public void testExtractValue() { SqlTester mySqlTester = tester(SqlLibrary.MYSQL); mySqlTester.checkNull("ExtractValue(NULL, '//b')"); diff --git a/core/src/test/resources/sql/functions.iq b/core/src/test/resources/sql/functions.iq index 2f16e14..c9a14b8 100644 --- a/core/src/test/resources/sql/functions.iq +++ b/core/src/test/resources/sql/functions.iq @@ -54,6 +54,19 @@ SELECT ExtractValue('<a>c</a>', '//a'); !ok +# Compression Functions + +SELECT COMPRESS('sample'); ++--------------------------------------+ +| EXPR$0 | ++--------------------------------------+ +| 06000000789c2b4ecc2dc849050008de0283 | ++--------------------------------------+ +(1 row) + +!ok + + !use oraclefunc # COSH diff --git a/site/_docs/reference.md b/site/_docs/reference.md index b0dbace..efeda04 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -2323,6 +2323,7 @@ semantics. | o | CHR(integer) | Returns the character having the binary equivalent to *integer* as a CHAR value | o | COSH(numeric) | Returns the hyperbolic cosine of *numeric* | m o p | CONCAT(string [, string ]*) | Concatenates two or more strings +| m | COMPRESS(string) | Compresses a string using zlib compression and returns the result as a binary string. | p | CONVERT_TIMEZONE(tz1, tz2, datetime) | Converts the timezone of *datetime* from *tz1* to *tz2* | m | DAYNAME(datetime) | Returns the name, in the connection's locale, of the weekday in *datetime*; for example, it returns '星期日' for both DATE '2020-02-10' and TIMESTAMP '2020-02-10 10:10:10' | o | DECODE(value, value1, result1 [, valueN, resultN ]* [, default ]) | Compares *value* to each *valueN* value one by one; if *value* is equal to a *valueN*, returns the corresponding *resultN*, else returns *default*, or NULL if *default* is not specified