This is an automated email from the ASF dual-hosted git repository.
stoty pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/master by this push:
new 622abbd488 PHOENIX-7424 Support toStringBinary/toBytesBinary
conversion (#2020)
622abbd488 is described below
commit 622abbd488366ea63a0a819a7711259c662dc3da
Author: szucsvillo <[email protected]>
AuthorDate: Mon Nov 25 09:10:17 2024 +0100
PHOENIX-7424 Support toStringBinary/toBytesBinary conversion (#2020)
---
.../apache/phoenix/expression/ExpressionType.java | 4 +-
.../expression/function/DecodeBinaryFunction.java | 44 +++++
.../expression/function/DecodeFunction.java | 13 +-
.../expression/function/EncodeBinaryFunction.java | 123 ++++++++++++
.../phoenix/expression/function/EncodeFormat.java | 3 +-
.../phoenix/end2end/DecodeBinaryFunctionIT.java | 179 ++++++++++++++++++
.../apache/phoenix/end2end/DecodeFunctionIT.java | 23 +++
.../phoenix/end2end/EncodeBinaryFunctionIT.java | 207 +++++++++++++++++++++
8 files changed, 591 insertions(+), 5 deletions(-)
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/ExpressionType.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/ExpressionType.java
index bc059d9642..1fb68d81ae 100644
---
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/ExpressionType.java
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/ExpressionType.java
@@ -200,7 +200,9 @@ public enum ExpressionType {
BsonConditionExpressionFunction(BsonConditionExpressionFunction.class),
BsonUpdateExpressionFunction(BsonUpdateExpressionFunction.class),
BsonValueFunction(BsonValueFunction.class),
- PartitionIdFunction(PartitionIdFunction.class);
+ PartitionIdFunction(PartitionIdFunction.class),
+ DecodeBinaryFunction(DecodeBinaryFunction.class),
+ EncodeBinaryFunction(EncodeBinaryFunction.class);
ExpressionType(Class<? extends Expression> clazz) {
this.clazz = clazz;
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/DecodeBinaryFunction.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/DecodeBinaryFunction.java
new file mode 100644
index 0000000000..2e1469c7b6
--- /dev/null
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/DecodeBinaryFunction.java
@@ -0,0 +1,44 @@
+/*
+ * 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.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode;
+import org.apache.phoenix.schema.types.PVarchar;
+
+/**
+ * Decodes binary data in various formats (Hex, Base64, HBase) by extending
the DecodeFunction.
+ */
[email protected](name = DecodeBinaryFunction.NAME, args = {
+ @FunctionParseNode.Argument(allowedTypes = {PVarchar.class}),
+ @FunctionParseNode.Argument(enumeration = "EncodeFormat")})
+public class DecodeBinaryFunction extends DecodeFunction {
+
+ public static final String NAME = "DECODE_BINARY";
+
+ public DecodeBinaryFunction() {
+ super();
+ }
+
+ public DecodeBinaryFunction(List<Expression> children) throws SQLException
{
+ super(children);
+ }
+
+}
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/DecodeFunction.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/DecodeFunction.java
index 7b6ef38246..f42c25050e 100644
---
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/DecodeFunction.java
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/DecodeFunction.java
@@ -18,9 +18,11 @@
package org.apache.phoenix.expression.function;
import java.sql.SQLException;
+import java.util.Base64;
import java.util.List;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.exception.SQLExceptionInfo;
import org.apache.phoenix.expression.Expression;
@@ -58,8 +60,7 @@ public class DecodeFunction extends ScalarFunction {
return true; // expression was evaluated, but evaluated
to null
}
- PDataType type = expression.getDataType();
- String stringToDecode = (String) type.toObject(ptr);
+ String stringToDecode = (String)
PVarchar.INSTANCE.toObject(ptr);
Expression encodingExpression = getEncodingExpression();
if (!encodingExpression.evaluate(tuple, ptr)) {
@@ -71,7 +72,7 @@ public class DecodeFunction extends ScalarFunction {
.setMessage("Missing bytes encoding").build().buildException());
}
- type = encodingExpression.getDataType();
+ PDataType type = encodingExpression.getDataType();
String encoding = ((String) type.toObject(ptr)).toUpperCase();
byte out[];
@@ -81,6 +82,12 @@ public class DecodeFunction extends ScalarFunction {
case HEX:
out = decodeHex(stringToDecode);
break;
+ case BASE64:
+ out =
Base64.getDecoder().decode(stringToDecode);
+ break;
+ case HBASE:
+ out = Bytes.toBytesBinary(stringToDecode);
+ break;
default:
throw new IllegalDataException("Unsupported
encoding \"" + encoding + "\"");
}
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/EncodeBinaryFunction.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/EncodeBinaryFunction.java
new file mode 100644
index 0000000000..7db5b968df
--- /dev/null
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/EncodeBinaryFunction.java
@@ -0,0 +1,123 @@
+/*
+ * 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.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.Base64;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode;
+import org.apache.phoenix.schema.IllegalDataException;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.apache.phoenix.schema.types.PVarbinary;
+
+import static org.apache.hadoop.hbase.util.Bytes.toHex;
+
+/**
+ * Encodes binary data into a string to various formats such as Hex, Base64,
or HBase binary.
+ */
[email protected](name = EncodeBinaryFunction.NAME, args = {
+ @FunctionParseNode.Argument(allowedTypes = {PVarbinary.class}),
+ @FunctionParseNode.Argument(enumeration = "EncodeFormat")})
+public class EncodeBinaryFunction extends ScalarFunction {
+
+ public static final String NAME = "ENCODE_BINARY";
+
+ public EncodeBinaryFunction() {
+ }
+
+ public EncodeBinaryFunction(List<Expression> children) throws SQLException
{
+ super(children);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ Expression expression = getExpression();
+ if (!expression.evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ return true;
+ }
+
+ byte[] bytesToEncode = ptr.copyBytes();
+ Expression encodingExpression = getEncodingExpression();
+
+ if (!encodingExpression.evaluate(tuple, ptr)) {
+ return false;
+ }
+
+ if (ptr.getLength() == 0) {
+ throw new IllegalDataException(getMissingEncodeFormatMsg());
+ }
+
+ PDataType type = encodingExpression.getDataType();
+ String encodingFormat = ((String) type.toObject(ptr)).toUpperCase();
+ EncodeFormat format = EncodeFormat.valueOf(encodingFormat);
+ String encodedString;
+
+ switch (format) {
+ case HEX:
+ encodedString = toHex(bytesToEncode);
+ break;
+ case BASE64:
+ encodedString = Base64.getEncoder().encodeToString(bytesToEncode);
+ break;
+ case HBASE:
+ encodedString = Bytes.toStringBinary(bytesToEncode);
+ break;
+ default:
+ throw new
IllegalDataException(getUnsupportedEncodeFormatMsg(encodingFormat));
+ }
+
+ ptr.set(PVarchar.INSTANCE.toBytes(encodedString));
+ return true;
+ }
+
+ public static String getMissingEncodeFormatMsg() {
+ return "Missing Encode Format";
+ }
+
+ public static String getUnsupportedEncodeFormatMsg(String encodeFormat) {
+ return "Unsupported Encode Format : " + encodeFormat;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PVarchar.INSTANCE;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ private Expression getExpression() {
+ return children.get(0);
+ }
+
+ private Expression getEncodingExpression() {
+ return children.get(1);
+ }
+
+}
+
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/EncodeFormat.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/EncodeFormat.java
index 8130228baa..664f331efd 100644
---
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/EncodeFormat.java
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/EncodeFormat.java
@@ -22,5 +22,6 @@ public enum EncodeFormat {
HEX, //format for encoding HEX value to bytes
BASE62, //format for encoding a base 10 long value to base 62 string
BASE64, //format for encoding a base 10 long value to base 64 string
- ASCII // Plain Text
+ ASCII, //Plain Text
+ HBASE //HBase-specific escaping format
};
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DecodeBinaryFunctionIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DecodeBinaryFunctionIT.java
new file mode 100644
index 0000000000..5f1067be7a
--- /dev/null
+++
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DecodeBinaryFunctionIT.java
@@ -0,0 +1,179 @@
+/*
+ * 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.phoenix.end2end;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Arrays;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(ParallelStatsDisabledTest.class)
+public class DecodeBinaryFunctionIT extends ParallelStatsDisabledIT {
+
+ private static String testTable;
+ private static final String helloPhoenixString = "HelloPhoenix";
+ private static final byte[] helloPhoenixBytes = "HelloPhoenix".getBytes();
+ private static final String base64Chunk = "SGVsbG9QaG9lbml4";
+ private static final String hex48String = "48656c6c6f";
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ testTable = generateUniqueName();
+ String ddl = "CREATE TABLE " + testTable + " (id INTEGER PRIMARY KEY,
data VARCHAR)";
+ conn.createStatement().execute(ddl);
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (1, ?)");
+ ps.setString(1, helloPhoenixString);
+ ps.execute();
+ conn.commit();
+ conn.close();
+ }
+
+ @Test
+ public void testDecodeHBaseFromHexLiteral() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement().executeQuery(
+ "SELECT
DECODE_BINARY('\\x48\\x65\\x6C\\x6C\\x6F\\x50\\x68\\x6F\\x65\\x6E\\x69\\x78', "
+
+ "'HBASE') FROM " + testTable);
+ assertTrue(rs.next());
+ byte[] actualBytes = rs.getBytes(1);
+ assertTrue(Arrays.equals(helloPhoenixBytes, actualBytes));
+ }
+
+ @Test
+ public void testNullAndEmptyStringDecoding() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT DECODE_BINARY(data, 'HBASE') FROM " +
testTable + " WHERE ID=-10");
+ assertFalse(rs.next());
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (6, ?)");
+ ps.setString(1, StringUtils.EMPTY);
+ ps.execute();
+ conn.commit();
+
+ ResultSet rs2 = conn.createStatement()
+ .executeQuery("SELECT DECODE_BINARY(data, 'HEX') FROM " +
testTable + " WHERE ID=6");
+ assertTrue(rs2.next());
+ assertEquals(null, rs2.getString(1));
+ }
+
+ @Test
+ public void testLongBase64Decoding() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ StringBuilder base64String = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ base64String.append(base64Chunk);
+ }
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (3, ?)");
+ ps.setString(1, base64String.toString());
+ ps.execute();
+ conn.commit();
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT DECODE_BINARY(data, 'BASE64') FROM " +
testTable + " WHERE ID=3");
+ assertTrue(rs.next());
+
+ StringBuilder expectedString = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ expectedString.append(helloPhoenixString);
+ }
+
+ byte[] actualBytes = rs.getBytes(1);
+ assertTrue(Arrays.equals(expectedString.toString().getBytes(),
actualBytes));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testDecodeBase64WithPadding() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (7, ?)");
+ ps.setString(1, "SQ==");
+ ps.execute();
+ conn.commit();
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT DECODE_BINARY(data, 'BASE64') FROM " +
testTable + " WHERE ID=7");
+ assertTrue(rs.next());
+
+ byte[] actualBytes = rs.getBytes(1);
+ assertTrue(Arrays.equals("I".getBytes(), actualBytes));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testDecodeEncodeRoundHex() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (4, ?)");
+ ps.setString(1, hex48String);
+ ps.execute();
+ conn.commit();
+
+ ResultSet rs = conn.createStatement().executeQuery(
+ "SELECT ENCODE_BINARY(DECODE_BINARY(data, 'HEX'), 'HEX') FROM
" + testTable + " WHERE ID=4");
+ assertTrue(rs.next());
+ String actualString = rs.getString(1);
+ assertEquals(hex48String, actualString);
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testDecodeEncodeRoundBase64() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (5, ?)");
+ ps.setString(1, base64Chunk);
+ ps.execute();
+ conn.commit();
+
+ ResultSet rs = conn.createStatement().executeQuery(
+ "SELECT ENCODE_BINARY(DECODE_BINARY(data, 'BASE64'), 'BASE64')
FROM " + testTable + " WHERE ID=5");
+ assertTrue(rs.next());
+ String actualString = rs.getString(1);
+ assertEquals(base64Chunk, actualString);
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testDecodeEncodeRoundHbase() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement().executeQuery(
+ "SELECT ENCODE_BINARY(DECODE_BINARY(data, 'HBASE'), 'HBASE')
FROM " + testTable + " WHERE ID=1");
+ assertTrue(rs.next());
+ String actualString = rs.getString(1);
+ assertEquals(helloPhoenixString, actualString);
+ assertFalse(rs.next());
+ }
+}
\ No newline at end of file
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DecodeFunctionIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DecodeFunctionIT.java
index c3cbe0ddae..f4e949958c 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DecodeFunctionIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DecodeFunctionIT.java
@@ -27,6 +27,7 @@ import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.Arrays;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.exception.SQLExceptionCode;
@@ -151,4 +152,26 @@ public class DecodeFunctionIT extends
ParallelStatsDisabledIT {
assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(),
e.getErrorCode());
}
}
+
+ @Test
+ public void testDecodeBase642() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ String testTable = generateUniqueName();
+ String ddl = "CREATE TABLE " + testTable + " (id INTEGER PRIMARY KEY,
data VARCHAR)";
+
+ conn.createStatement().execute(ddl);
+
+ PreparedStatement ps =
+ conn.prepareStatement("UPSERT INTO " + testTable + " (id,
data) VALUES (1, 'SGVsbG9QaG9lbml4')");
+ ps.execute();
+ conn.commit();
+
+ ResultSet rs = conn.createStatement().executeQuery("SELECT
DECODE(data, 'BASE64') FROM " + testTable);
+ assertTrue(rs.next());
+ byte[] actualBytes = rs.getBytes(1);
+ assertTrue(Arrays.equals("HelloPhoenix".getBytes(), actualBytes));
+ assertFalse(rs.next());
+ }
+
}
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/EncodeBinaryFunctionIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/EncodeBinaryFunctionIT.java
new file mode 100644
index 0000000000..010ec12635
--- /dev/null
+++
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/EncodeBinaryFunctionIT.java
@@ -0,0 +1,207 @@
+/*
+ * 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.phoenix.end2end;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+
+@Category(ParallelStatsDisabledTest.class)
+public class EncodeBinaryFunctionIT extends ParallelStatsDisabledIT {
+
+ private static String testTable;
+ private static final byte[] originalBytes = "HelloPhoenix".getBytes();
+ private static final String encoded48String = "48656c6c6f50686f656e6978";
+ private static final String helloPhoenixString = "HelloPhoenix";
+ private static final String expectedBase64Chunk = "SGVsbG9QaG9lbml4";
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ testTable = generateUniqueName();
+ String ddl = "CREATE TABLE " + testTable + " (id INTEGER PRIMARY KEY,
data VARBINARY)";
+ conn.createStatement().execute(ddl);
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (1, ?)");
+ ps.setBytes(1, originalBytes);
+ ps.execute();
+
+ PreparedStatement ps2 = conn.prepareStatement(
+ "UPSERT INTO " + testTable + " (id, data) VALUES (2,
X'48656c6c6f50686f656e6978')");
+ ps2.execute();
+ conn.commit();
+ conn.close();
+ }
+
+ @Test
+ public void testEncodeHex() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT ENCODE_BINARY(data, 'HEX') FROM " +
testTable + " WHERE ID=2");
+ assertTrue(rs.next());
+ String actualString = rs.getString(1);
+ assertEquals(encoded48String, actualString);
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testMixedCaseHexDecoding() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT ENCODE_BINARY(data, 'HEX') FROM " +
testTable + " WHERE ID=2");
+ assertTrue(rs.next());
+ String actualString = rs.getString(1);
+ assertEquals(encoded48String, actualString);
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testEncodeBase64() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT ENCODE_BINARY(data, 'BASE64') FROM " +
testTable + " WHERE ID=1");
+ assertTrue(rs.next());
+ String actualString = rs.getString(1);
+ assertEquals(expectedBase64Chunk, actualString);
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testLongBase64Decoding() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ StringBuilder base64String = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ base64String.append(helloPhoenixString);
+ }
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (3, ?)");
+ ps.setBytes(1, base64String.toString().getBytes());
+ ps.execute();
+ conn.commit();
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT ENCODE_BINARY(data, 'BASE64') FROM " +
testTable + " WHERE ID=3");
+ assertTrue(rs.next());
+
+ StringBuilder expectedString = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ expectedString.append(expectedBase64Chunk);
+ }
+
+ String actualString = rs.getString(1);
+ assertEquals(expectedString.toString(), actualString);
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testEncodeHBase() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT ENCODE_BINARY(data, 'HBASE') FROM " +
testTable + " WHERE ID=1");
+ assertTrue(rs.next());
+ String actualString = rs.getString(1);
+ assertEquals(helloPhoenixString, actualString);
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testInvalidDecodingFormat() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ try {
+ conn.createStatement().executeQuery("SELECT ENCODE_BINARY(data,
'INVALIDFORMAT') FROM " + testTable);
+ fail("Expected an exception for invalid encoding format");
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(),
e.getErrorCode());
+ }
+ }
+
+ @Test
+ public void testNullAndEmptyStringDecoding() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement()
+ .executeQuery("SELECT ENCODE_BINARY(data, 'HEX') FROM " +
testTable + " WHERE ID=-10");
+ assertFalse(rs.next());
+
+ PreparedStatement ps = conn.prepareStatement("UPSERT INTO " +
testTable + " (id, data) VALUES (4, ?)");
+ ps.setBytes(1, new byte[0]);
+ ps.execute();
+ conn.commit();
+
+ ResultSet rs2 = conn.createStatement()
+ .executeQuery("SELECT ENCODE_BINARY(data, 'HEX') FROM " +
testTable + " WHERE ID=4");
+ assertTrue(rs2.next());
+ String actualString = rs2.getString(1);
+ assertEquals(null, actualString);
+ assertFalse(rs2.next());
+ }
+
+ @Test
+ public void testEncodeDecodeRoundHex() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement().executeQuery(
+ "SELECT DECODE_BINARY(ENCODE_BINARY(data, 'HEX'), 'HEX') FROM
" + testTable + " WHERE ID=1");
+ assertTrue(rs.next());
+ byte[] roundTripEncoded = rs.getBytes(1);
+ assertTrue(Arrays.equals(originalBytes, roundTripEncoded));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testEncodeDecodeRoundBase64() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement().executeQuery(
+ "SELECT DECODE_BINARY(ENCODE_BINARY(data, 'BASE64'), 'BASE64')
FROM " + testTable + " WHERE ID=1");
+ assertTrue(rs.next());
+ byte[] roundTripEncoded = rs.getBytes(1);
+ assertTrue(Arrays.equals(originalBytes, roundTripEncoded));
+ }
+
+ @Test
+ public void testEncodeDecodeRoundHbase() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ResultSet rs = conn.createStatement().executeQuery(
+ "SELECT DECODE_BINARY(ENCODE_BINARY(data, 'HBASE'), 'HBASE')
FROM " + testTable + " WHERE ID=1");
+ assertTrue(rs.next());
+ byte[] roundTripEncoded = rs.getBytes(1);
+ assertTrue(Arrays.equals(originalBytes, roundTripEncoded));
+ assertFalse(rs.next());
+ }
+}
\ No newline at end of file