This is an automated email from the ASF dual-hosted git repository.

vjasani 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 6972a4f8c5 PHOENIX-7631 BSON_VALUE() to support returning binary value 
with VARBINARY_ENCODED data type (#2175)
6972a4f8c5 is described below

commit 6972a4f8c5e4e2d884417ff227c00bac4507a8a4
Author: Viraj Jasani <[email protected]>
AuthorDate: Wed Jun 4 22:59:30 2025 -0700

    PHOENIX-7631 BSON_VALUE() to support returning binary value with 
VARBINARY_ENCODED data type (#2175)
---
 .gitignore                                         |   1 +
 .../expression/function/BsonValueFunction.java     |   8 +-
 .../java/org/apache/phoenix/end2end/Bson4IT.java   | 246 +++++++++++++++++++++
 3 files changed, 251 insertions(+), 4 deletions(-)

diff --git a/.gitignore b/.gitignore
index 313e6d9881..0851a687cb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,4 @@ phoenix-hbase-compat-1.5.0/
 
 # Code generators
 .codegenie
+/.vscode/
diff --git 
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/BsonValueFunction.java
 
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/BsonValueFunction.java
index b7ff1088c4..d0f7de4a57 100644
--- 
a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/BsonValueFunction.java
+++ 
b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/function/BsonValueFunction.java
@@ -20,6 +20,7 @@ package org.apache.phoenix.expression.function;
 import java.util.Date;
 import java.util.List;
 
+import org.apache.phoenix.schema.types.PVarbinaryEncoded;
 import org.bson.BsonBinary;
 import org.bson.BsonBoolean;
 import org.bson.BsonDateTime;
@@ -153,10 +154,9 @@ public class BsonValueFunction extends ScalarFunction {
             ptr.set(PBoolean.INSTANCE.toBytes(((BsonBoolean) 
bsonValue).getValue()));
         } else if (bsonValueDataType == PVarbinary.INSTANCE && bsonValue 
instanceof BsonBinary) {
             ptr.set(PVarbinary.INSTANCE.toBytes(((BsonBinary) 
bsonValue).getData()));
-//        TODO : uncomment after PHOENIX-7357
-//        } else if (bsonValueDataType == PVarbinaryEncoded.INSTANCE
-//            && bsonValue instanceof BsonBinary) {
-//            ptr.set(PVarbinaryEncoded.INSTANCE.toBytes(((BsonBinary) 
bsonValue).getData()));
+        } else if (bsonValueDataType == PVarbinaryEncoded.INSTANCE
+            && bsonValue instanceof BsonBinary) {
+            ptr.set(PVarbinaryEncoded.INSTANCE.toBytes(((BsonBinary) 
bsonValue).getData()));
         } else if (bsonValueDataType == PDate.INSTANCE && bsonValue instanceof 
BsonDateTime) {
             ptr.set(PDate.INSTANCE.toBytes(new Date(((BsonDateTime) 
bsonValue).getValue())));
         } else {
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/Bson4IT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/Bson4IT.java
index 4084561623..1d75ad6bb9 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/Bson4IT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/Bson4IT.java
@@ -56,6 +56,7 @@ import 
org.apache.phoenix.thirdparty.com.google.common.base.Preconditions;
 import org.apache.phoenix.util.PropertiesUtil;
 
 import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -245,6 +246,251 @@ public class Bson4IT extends ParallelStatsDisabledIT {
     }
   }
 
+  @Test
+  public void testBsonValueWithBinaryEncoded() throws Exception {
+
+    byte[] doc1Field1 = {
+            0, 1, 2, 3, 0, 1, 5, 6, 7, 8, 0,
+            10, 11, 12, 13, 0, 0, -1, 15, 16, 17, 18, 19};
+    byte[] doc1Field2 = {
+            1, 0, 2, 3, 4, 0, 6, 7, 8, 9,
+            0, 11, 12, 13, 14, 0, 16, 17, 18, 19, 20};
+    byte[] doc1Field3 = {
+            1, 2, 0, 3, 4, 5, 0, 7, 8, 9,
+            10, 0, 12, 13, 14, 15, 0, 17, 18, 19, 20, 21};
+    byte[] doc1Field4 = {
+            1, 2, 3, 0, 4, 5, 6, 0, 8, 9,
+            10, 11, 0, 13, 14, 15, 16, 0, 18, 19, 20, 21, 22};
+    byte[] doc1Field5 = {
+            1, 2, 3, 4, 0, 5, 6, 7, 0, 9,
+            10, 11, 12, 0, 14, 15, 16, 17, 0, 19, 20, 21, 22, 23};
+
+    byte[] doc2Field1 = {
+            0, 25, 35, 45, 0, 55, 65, 75, 85, 0,
+            95, 105, 115, 125, 0, 15, 25, 35, 45, 55};
+    byte[] doc2Field2 = {
+            25, 0, 35, 45, 55, 0, 65, 75, 85, 95,
+            0, 105, 115, 125, -125, 0, 15, 25, 35, 45, 55};
+    byte[] doc2Field3 = {
+            25, 35, 0, 45, 55, 65, 0, 75, 85, 95,
+            105, 0, 115, 125, -125, -115, 0, 15, 25, 35, 45, 55};
+    byte[] doc2Field4 = {
+            25, 35, 45, 0, 55, 65, 75, 0, 85, 95,
+            105, 115, 0, 125, -125, -115, -105, 0, 15, 25, 35, 45, 55};
+    byte[] doc2Field5 = {
+            25, 35, 45, 55, 0, 65, 75, 85, 0, 95,
+            105, 115, 125, 0, -125, -115, -105, -95, 0, 15, 25, 35, 45, 55};
+
+    byte[] doc3Field1 = {
+            0, -1, -2, -3, 0, -5, -6, -7, -8, 0,
+            -10, -11, -12, -13, 0, -15, -16, -17, -18, -19};
+    byte[] doc3Field2 = {
+            -1, 0, -2, -3, -4, 0, -6, -7, -8, -9,
+            0, -11, -12, -13, -14, 0, -16, -17, -18, -19, -20};
+    byte[] doc3Field3 = {
+            -1, -2, 0, -3, -4, -5, 0, -7, -8, -9,
+            -10, 0, -12, -13, -14, -15, 0, -17, -18, -19, -20, -21};
+    byte[] doc3Field4 = {
+            -1, -2, -3, 0, -4, -5, -6, 0, -8, -9,
+            -10, -11, 0, -13, -14, -15, -16, 0, -18, -19, -20, -21, -22};
+    byte[] doc3Field5 = {
+            -1, -2, -3, -4, 0, -5, -6, -7, 0, -9,
+            -10, -11, -12, 0, -14, -15, -16, -17, 0, -19, -20, -21, -22, -23};
+
+    byte[] doc4Field1 = {
+            0, -1, -2, -3, 0, 0, 1 - 5, -6, -7, -8, 0,
+            -10, -11, -12, -13, 0, -15, -16, -17, -18, -19};
+    byte[] doc4Field2 = {
+            -1, 0, -2, -3, -4, 0, 6, -7, -8, -9,
+            0, -11, -12, -13, -14, 0, -16, -17, -18, -19, -20};
+    byte[] doc4Field30 = {
+            -1, -2, 0, -3, -4, -5, 0, 0, -7, 8, -9,
+            -10, -1, 0, -1, -12, -13, -14, -15, 0, -17, -18, -19, -20, -21};
+    byte[] doc4Field4 = {
+            -1, -2, -3, 0, -4, -5, -6, 0, -8, -9,
+            -10, -11, -1, 0, 1, -13, -14, -15, -16, 0, -18, -19, -20, -21, 
-22};
+    byte[] doc4Field5 = {
+            -1, -1, 0, -2, -3, -4, 0, -5, -6, -7, 0, -9,
+            -10, -11, -12, 0, -14, -15, -16, -17, 0, -19, -20, -21, -22, -23};
+
+    Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+    String tableName = generateUniqueName();
+    String indexName1 = "IDX1_" + tableName;
+    String indexName2 = "IDX2_" + tableName;
+
+    try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
+
+      String ddl = "CREATE TABLE " + tableName
+              + " (PK1 VARCHAR NOT NULL, C1 VARCHAR, COL BSON"
+              + " CONSTRAINT pk PRIMARY KEY(PK1))";
+
+      final String indexDdl1;
+      if (!this.coveredIndex) {
+        indexDdl1 = "CREATE UNCOVERED INDEX " + indexName1 + " ON " + tableName
+                + "(BSON_VALUE(COL, 'binary_field1', 'VARBINARY_ENCODED')) 
WHERE "
+                + "BSON_VALUE(COL, 'binary_field1', 'VARBINARY_ENCODED') IS 
NOT NULL";
+      } else {
+        indexDdl1 = "CREATE INDEX " + indexName1 + " ON " + tableName
+                + "(BSON_VALUE(COL, 'binary_field1', 'VARBINARY_ENCODED')) 
INCLUDE(COL, C1) WHERE "
+                + "BSON_VALUE(COL, 'binary_field1', 'VARBINARY_ENCODED') IS 
NOT NULL";
+      }
+
+      final String indexDdl2;
+      if (!this.coveredIndex) {
+        indexDdl2 = "CREATE UNCOVERED INDEX " + indexName2 + " ON " + tableName
+                + "(BSON_VALUE(COL, 'binary_field3', 'VARBINARY_ENCODED')) 
WHERE "
+                + "BSON_VALUE(COL, 'binary_field3', 'VARBINARY_ENCODED') IS 
NOT NULL";
+      } else {
+        indexDdl2 = "CREATE INDEX " + indexName2 + " ON " + tableName
+                + "(BSON_VALUE(COL, 'binary_field3', 'VARBINARY_ENCODED')) 
INCLUDE(COL, C1) WHERE "
+                + "BSON_VALUE(COL, 'binary_field3', 'VARBINARY_ENCODED') IS 
NOT NULL";
+      }
+
+      conn.createStatement().execute(ddl);
+      conn.createStatement().execute(indexDdl1);
+      conn.createStatement().execute(indexDdl2);
+
+      BsonDocument doc1 = new BsonDocument()
+              .append("binary_field1", new BsonBinary(doc1Field1))
+              .append("binary_field2", new BsonBinary(doc1Field2))
+              .append("binary_field3", new BsonBinary(doc1Field3))
+              .append("binary_field4", new BsonBinary(doc1Field4))
+              .append("binary_field5", new BsonBinary(doc1Field5));
+
+      BsonDocument doc2 = new BsonDocument()
+              .append("binary_field1", new BsonBinary(doc2Field1))
+              .append("binary_field2", new BsonBinary(doc2Field2))
+              .append("binary_field3", new BsonBinary(doc2Field3))
+              .append("binary_field4", new BsonBinary(doc2Field4))
+              .append("binary_field5", new BsonBinary(doc2Field5));
+
+      BsonDocument doc3 = new BsonDocument()
+              .append("binary_field1", new BsonBinary(doc3Field1))
+              .append("binary_field2", new BsonBinary(doc3Field2))
+              .append("binary_field3", new BsonBinary(doc3Field3))
+              .append("binary_field4", new BsonBinary(doc3Field4))
+              .append("binary_field5", new BsonBinary(doc3Field5));
+
+      BsonDocument doc4 = new BsonDocument()
+              .append("binary_field1", new BsonBinary(doc4Field1))
+              .append("binary_field2", new BsonBinary(doc4Field2))
+              .append("binary_field30", new BsonBinary(doc4Field30))
+              .append("binary_field4", new BsonBinary(doc4Field4))
+              .append("binary_field5", new BsonBinary(doc4Field5));
+
+      PreparedStatement stmt =
+              conn.prepareStatement("UPSERT INTO " + tableName + " VALUES 
(?,?,?)");
+
+      stmt.setString(1, "pk1");
+      stmt.setString(2, "c1_value1");
+      stmt.setObject(3, doc1);
+      stmt.executeUpdate();
+
+      stmt.setString(1, "pk2");
+      stmt.setString(2, "c1_value2");
+      stmt.setObject(3, doc2);
+      stmt.executeUpdate();
+
+      stmt.setString(1, "pk3");
+      stmt.setString(2, "c1_value3");
+      stmt.setObject(3, doc3);
+      stmt.executeUpdate();
+
+      stmt.setString(1, "pk4");
+      stmt.setString(2, "c1_value4");
+      stmt.setObject(3, doc4);
+      stmt.executeUpdate();
+
+      conn.commit();
+
+      ResultSet rs = conn.createStatement().executeQuery("SELECT count(*) FROM 
" + tableName);
+      assertTrue(rs.next());
+      assertEquals(4, rs.getInt(1));
+
+      rs = conn.createStatement().executeQuery("SELECT count(*) FROM " + 
indexName1);
+      assertTrue(rs.next());
+      assertEquals(4, rs.getInt(1));
+
+      rs = conn.createStatement().executeQuery("SELECT count(*) FROM " + 
indexName2);
+      assertTrue(rs.next());
+      assertEquals(3, rs.getInt(1));
+
+      PreparedStatement ps = conn.prepareStatement(
+              "SELECT PK1, C1, COL, BSON_VALUE(COL, 'binary_field2', 
'VARBINARY_ENCODED') FROM "
+                      + tableName
+                      + " WHERE BSON_VALUE(COL, 'binary_field1', 
'VARBINARY_ENCODED') = ?");
+      ps.setBytes(1, doc1Field1);
+
+      rs = ps.executeQuery();
+      assertTrue(rs.next());
+      assertEquals("pk1", rs.getString(1));
+      assertEquals("c1_value1", rs.getString(2));
+      BsonDocument actualDoc = (BsonDocument) rs.getObject(3);
+      assertEquals(doc1, actualDoc);
+      assertArrayEquals(doc1Field2, rs.getBytes(4));
+      assertFalse(rs.next());
+
+      validateExplainPlan(ps, indexName1, "RANGE SCAN ");
+
+      ps = conn.prepareStatement("SELECT PK1, C1, COL FROM " + tableName
+              + " WHERE BSON_VALUE(COL, 'binary_field3', 'VARBINARY_ENCODED') 
= ?");
+      ps.setBytes(1, doc2Field3);
+
+      rs = ps.executeQuery();
+      assertTrue(rs.next());
+      assertEquals("pk2", rs.getString(1));
+      assertEquals("c1_value2", rs.getString(2));
+      actualDoc = (BsonDocument) rs.getObject(3);
+      assertEquals(doc2, actualDoc);
+      assertFalse(rs.next());
+
+      validateExplainPlan(ps, indexName2, "RANGE SCAN ");
+
+      ps = conn.prepareStatement("SELECT PK1, C1, COL FROM " + tableName
+              + " WHERE BSON_VALUE(COL, 'binary_field1', 'VARBINARY_ENCODED') 
= ?");
+      ps.setBytes(1, new byte[]{
+              0, 1, 2, 3, 0, 0, 1, 5, 6, 7, 8, 0,
+              10, 11, 12, 13, 0, 0, -1, 15, 16, 17, 18, 19});
+
+      rs = ps.executeQuery();
+      assertFalse(rs.next());
+
+      validateExplainPlan(ps, indexName1, "RANGE SCAN ");
+
+      ps = conn.prepareStatement(
+              "SELECT PK1, C1, COL, BSON_VALUE(COL, 'binary_field5', 
'VARBINARY_ENCODED') FROM "
+                      + tableName + " WHERE C1 = ? AND "
+                      + "BSON_VALUE(COL, 'binary_field1', 'VARBINARY_ENCODED') 
= ?");
+      ps.setString(1, "c1_value2");
+      ps.setBytes(2, doc2Field1);
+
+      rs = ps.executeQuery();
+      assertTrue(rs.next());
+      assertEquals("pk2", rs.getString(1));
+      assertEquals("c1_value2", rs.getString(2));
+      actualDoc = (BsonDocument) rs.getObject(3);
+      assertEquals(doc2, actualDoc);
+      assertArrayEquals(doc2Field5, rs.getBytes(4));
+      assertFalse(rs.next());
+
+      validateExplainPlan(ps, indexName1, "RANGE SCAN ");
+
+      ps = conn.prepareStatement("SELECT PK1, C1, COL FROM " + tableName
+              + " WHERE C1 = ?");
+      ps.setString(1, "c1_value3");
+
+      rs = ps.executeQuery();
+      assertTrue(rs.next());
+      assertEquals("pk3", rs.getString(1));
+      assertEquals("c1_value3", rs.getString(2));
+      actualDoc = (BsonDocument) rs.getObject(3);
+      assertEquals(doc3, actualDoc);
+      assertFalse(rs.next());
+
+      validateExplainPlan(ps, tableName, "FULL SCAN ");
+    }
+  }
+
   @Test
   public void testConditionalUpsertReturnRow() throws Exception {
     Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);

Reply via email to