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

deniskuzZ pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new e5ec0c9e28c HIVE-28503: Vectorization: Concat (||) on string columns 
returns NULL for non-null inputs (#6607)
e5ec0c9e28c is described below

commit e5ec0c9e28c0244b46bae91fa3c1b16d7fa2d03e
Author: Mahesh Raju Somalaraju <[email protected]>
AuthorDate: Mon Jul 27 16:33:12 2026 +0530

    HIVE-28503: Vectorization: Concat (||) on string columns returns NULL for 
non-null inputs (#6607)
---
 .../expressions/StringGroupConcatColCol.java       |  14 +++
 .../vector/expressions/TestVectorStringConcat.java | 121 +++++++++++++++++++++
 2 files changed, 135 insertions(+)

diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/StringGroupConcatColCol.java
 
b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/StringGroupConcatColCol.java
index 19be05691db..c89ee4c0c61 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/StringGroupConcatColCol.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/StringGroupConcatColCol.java
@@ -319,7 +319,21 @@ public void evaluate(VectorizedRowBatch batch) throws 
HiveException {
 
       /*
        * Do careful maintenance of the outputColVector.noNulls flag.
+       *
+       * when both inputs have noNulls=true the output vector(outV) must set 
true.
+       * The output BytesColumnVector is reused across batches, so if a prior 
batch
+       * left noNulls=false we have to reset it here — otherwise downstream
+       * consumers that utilizing noNulls will treat these rows as NULL
+       * even though every setConcat below succeeded. This matches what the
+       * sibling scalar variants (StringGroupColConcatStringScalar and
+       * StringScalarConcatStringGroupCol) already do on their no-nulls paths.
        */
+      if (!outV.noNulls) {
+        // Assume it is almost always a performance win to fill all of isNull 
so we can
+        // safely reset noNulls.
+        Arrays.fill(outV.isNull, false);
+        outV.noNulls = true;
+      }
 
       // perform data operation
       if (inV1.isRepeating && inV2.isRepeating) {
diff --git 
a/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/expressions/TestVectorStringConcat.java
 
b/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/expressions/TestVectorStringConcat.java
index a5ede57200e..c0cd4cdaae8 100644
--- 
a/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/expressions/TestVectorStringConcat.java
+++ 
b/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/expressions/TestVectorStringConcat.java
@@ -32,6 +32,7 @@
 import org.apache.hadoop.hive.ql.exec.ExprNodeEvaluatorFactory;
 import org.apache.hadoop.hive.ql.exec.FunctionInfo;
 import org.apache.hadoop.hive.ql.exec.FunctionRegistry;
+import org.apache.hadoop.hive.ql.exec.vector.BytesColumnVector;
 import org.apache.hadoop.hive.ql.exec.vector.VectorExtractRow;
 import org.apache.hadoop.hive.ql.exec.vector.VectorRandomBatchSource;
 import org.apache.hadoop.hive.ql.exec.vector.VectorRandomRowSource;
@@ -100,6 +101,126 @@ public void testVarchar() throws Exception {
     doStringConcatTests(random, "string", "varchar(10)");
   }
 
+  /**
+   * The vectorized string concatenation operator (col || col) reuses the 
output vector across batches.
+   * However, if a prior batch produced NULLs, the output vector's noNulls 
flag is mistakenly left as false
+   * instead of being reset to true.
+   */
+  @Test
+  public void testColColConcatMaintainsNoNullsInvariant() throws Exception {
+    // Two-column input batch plus one output column.
+    VectorizedRowBatch batch = new VectorizedRowBatch(3, 
VectorizedRowBatch.DEFAULT_SIZE);
+
+    BytesColumnVector inV1 = new 
BytesColumnVector(VectorizedRowBatch.DEFAULT_SIZE);
+    BytesColumnVector inV2 = new 
BytesColumnVector(VectorizedRowBatch.DEFAULT_SIZE);
+    BytesColumnVector outV = new 
BytesColumnVector(VectorizedRowBatch.DEFAULT_SIZE);
+    outV.initBuffer();
+
+    batch.cols[0] = inV1;
+    batch.cols[1] = inV2;
+    batch.cols[2] = outV;
+
+    byte[] a = "foo".getBytes(StandardCharsets.UTF_8);
+    byte[] b = "bar".getBytes(StandardCharsets.UTF_8);
+    byte[] c = "baz".getBytes(StandardCharsets.UTF_8);
+    byte[] d = "qux".getBytes(StandardCharsets.UTF_8);
+    byte[] e = "quux".getBytes(StandardCharsets.UTF_8);
+    byte[] f = "corge".getBytes(StandardCharsets.UTF_8);
+
+    inV1.setRef(0, a, 0, a.length);
+    inV1.setRef(1, b, 0, b.length);
+    inV1.setRef(2, c, 0, c.length);
+    inV1.noNulls = true;
+    inV1.isRepeating = false;
+    inV1.isNull[0] = false;
+    inV1.isNull[1] = false;
+    inV1.isNull[2] = false;
+
+    inV2.setRef(0, d, 0, d.length);
+    inV2.setRef(1, e, 0, e.length);
+    inV2.setRef(2, f, 0, f.length);
+    inV2.noNulls = true;
+    inV2.isRepeating = false;
+    inV2.isNull[0] = false;
+    inV2.isNull[1] = false;
+    inV2.isNull[2] = false;
+
+    // Simulate the state left behind by a *prior* batch that had NULLs. The 
output
+    // vector object is reused across batches (VectorizedRowBatch does not 
allocate
+    // a new one), so noNulls stays false until the next evaluate() explicitly
+    // resets it.
+    outV.noNulls = false;
+
+    batch.size = 3;
+    batch.selectedInUse = false;
+
+    new StringGroupConcatColCol(0, 1, 2).evaluate(batch);
+
+    // if both inputs had noNulls=true, the output must too. This is
+    // what every sibling concat class in this package already does.
+    Assert.assertTrue(
+        "HIVE-28503: outV.noNulls must be true after col||col concat when both 
"
+            + "inputs are non-null; leaving it false lets downstream consumers 
"
+            + "that short-circuit on noNulls treat non-null rows as NULL.",
+        outV.noNulls);
+
+    // check for concatenated bytes.
+    Assert.assertEquals("fooqux",
+        new String(outV.vector[0], outV.start[0], outV.length[0], 
StandardCharsets.UTF_8));
+    Assert.assertEquals("barquux",
+        new String(outV.vector[1], outV.start[1], outV.length[1], 
StandardCharsets.UTF_8));
+    Assert.assertEquals("bazcorge",
+        new String(outV.vector[2], outV.start[2], outV.length[2], 
StandardCharsets.UTF_8));
+  }
+
+  /**
+   * This test covers input vectors that have the isRepeating flag set.
+   * Specifically, it tests the sub-case where both input vectors contain 
non-null values for the
+   * string concatenation operator (col || col).
+   */
+  @Test
+  public void testColColConcatMaintainsNoNullsInvariantRepeating() throws 
Exception {
+    VectorizedRowBatch batch = new VectorizedRowBatch(3, 
VectorizedRowBatch.DEFAULT_SIZE);
+
+    BytesColumnVector inV1 = new 
BytesColumnVector(VectorizedRowBatch.DEFAULT_SIZE);
+    BytesColumnVector inV2 = new 
BytesColumnVector(VectorizedRowBatch.DEFAULT_SIZE);
+    BytesColumnVector outV = new 
BytesColumnVector(VectorizedRowBatch.DEFAULT_SIZE);
+    outV.initBuffer();
+
+    batch.cols[0] = inV1;
+    batch.cols[1] = inV2;
+    batch.cols[2] = outV;
+
+    byte[] a = "hello".getBytes(StandardCharsets.UTF_8);
+    byte[] b = "world".getBytes(StandardCharsets.UTF_8);
+
+    inV1.setRef(0, a, 0, a.length);
+    inV1.noNulls = true;
+    inV1.isRepeating = true;
+    inV1.isNull[0] = false;
+
+    inV2.setRef(0, b, 0, b.length);
+    inV2.noNulls = true;
+    inV2.isRepeating = true;
+    inV2.isNull[0] = false;
+
+    outV.noNulls = false;
+
+    batch.size = 5;
+    batch.selectedInUse = false;
+
+    new StringGroupConcatColCol(0, 1, 2).evaluate(batch);
+
+    Assert.assertTrue("HIVE-28503: repeating output should keep 
isRepeating=true",
+        outV.isRepeating);
+    Assert.assertTrue(
+        "HIVE-28503: outV.noNulls must be true after col||col concat when both 
"
+            + "repeating inputs are non-null.",
+        outV.noNulls);
+    Assert.assertEquals("helloworld",
+        new String(outV.vector[0], outV.start[0], outV.length[0], 
StandardCharsets.UTF_8));
+  }
+
   public enum StringConcatTestMode {
     ROW_MODE,
     ADAPTOR,

Reply via email to