You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by an...@apache.org on 2020/07/21 00:15:08 UTC

[phoenix] branch 4.x updated: PHOENIX-6023 Wrong result when issuing query for an immutable table with multiple column families (#833)

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

ankit pushed a commit to branch 4.x
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/4.x by this push:
     new eb3875a  PHOENIX-6023 Wrong result when issuing query for an immutable table with multiple column families (#833)
eb3875a is described below

commit eb3875a5d0e559a96ef126a36751a9e226316d98
Author: Toshihiro Suzuki <br...@gmail.com>
AuthorDate: Mon Jul 20 17:14:56 2020 -0700

    PHOENIX-6023 Wrong result when issuing query for an immutable table with multiple column families (#833)
    
    Signed-off-by: Ankit Singhal <an...@apache.org>
---
 .../apache/phoenix/end2end/ImmutableTableIT.java   | 101 +++++++++++++++++++++
 .../org/apache/phoenix/compile/WhereCompiler.java  |  33 +++++--
 2 files changed, 128 insertions(+), 6 deletions(-)

diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ImmutableTableIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ImmutableTableIT.java
new file mode 100644
index 0000000..9ae505d
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ImmutableTableIT.java
@@ -0,0 +1,101 @@
+/*
+ * 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 maynot 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 applicablelaw 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 org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertEquals;
+
+public class ImmutableTableIT extends ParallelStatsDisabledIT {
+
+    @Test
+    public void testQueryWithMultipleColumnFamiliesAndSingleConditionForImmutableTable()
+        throws Exception {
+        final String tn = generateUniqueName();
+        final String url = getUrl();
+        try (Connection conn = DriverManager.getConnection(url);
+            Statement stmt = conn.createStatement()) {
+            stmt.execute(String.format("CREATE TABLE %s (" +
+                "ID VARCHAR PRIMARY KEY," +
+                "COL1 VARCHAR," +
+                "COL2 VARCHAR" +
+                ") IMMUTABLE_ROWS = TRUE", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id0', '0', 'a')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id1', '1', NULL)", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id2', '2', 'b')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id3', '3', NULL)", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id4', '4', 'c')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id5', '5', NULL)", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id6', '6', 'd')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id7', '7', NULL)", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id8', '8', 'e')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id9', '9', NULL)", tn));
+            conn.commit();
+
+            try (ResultSet rs = stmt.executeQuery(String.format(
+                "SELECT COL1 FROM %s WHERE COL2 IS NOT NULL", tn))) {
+                int count = 0;
+                while (rs.next()) {
+                  count++;
+                }
+                assertEquals(5, count);
+            }
+        }
+    }
+
+    @Test
+    public void testQueryWithMultipleColumnFamiliesAndMultipleConditionsForImmutableTable()
+        throws Exception {
+        final String tn = generateUniqueName();
+        final String url = getUrl();
+        try (Connection conn = DriverManager.getConnection(url);
+            Statement stmt = conn.createStatement()) {
+            stmt.execute(String.format("CREATE TABLE %s (" +
+                "ID VARCHAR PRIMARY KEY," +
+                "COL1 VARCHAR," +
+                "COL2 VARCHAR," +
+                "COL3 VARCHAR" +
+                ") IMMUTABLE_ROWS = TRUE", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id0', '0', '0', 'a')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id1', '1', '0', NULL)", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id2', '2', '0', 'b')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id3', '3', '0', NULL)", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id4', '4', '0', 'c')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id5', '5', '0', NULL)", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id6', '6', '0', 'd')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id7', '7', '0', NULL)", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id8', '8', '0', 'e')", tn));
+            stmt.execute(String.format("UPSERT INTO %s VALUES ('id9', '9', '0', NULL)", tn));
+            conn.commit();
+
+            try (ResultSet rs = stmt.executeQuery(String.format(
+                "SELECT COL1 FROM %s WHERE COL3 IS NOT NULL AND COL2='0'", tn))) {
+                int count = 0;
+                while (rs.next()) {
+                  count++;
+                }
+                assertEquals(5, count);
+            }
+        }
+    }
+}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
index fb294c0..62b2ed5 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
@@ -56,9 +56,9 @@ import org.apache.phoenix.query.QueryConstants;
 import org.apache.phoenix.schema.AmbiguousColumnException;
 import org.apache.phoenix.schema.ColumnNotFoundException;
 import org.apache.phoenix.schema.ColumnRef;
+import org.apache.phoenix.schema.PColumnFamily;
 import org.apache.phoenix.schema.PTable;
 import org.apache.phoenix.schema.PTable.ImmutableStorageScheme;
-import org.apache.phoenix.schema.PTable.IndexType;
 import org.apache.phoenix.schema.PTable.QualifierEncodingScheme;
 import org.apache.phoenix.schema.PTable.ViewType;
 import org.apache.phoenix.schema.PTableType;
@@ -66,6 +66,7 @@ import org.apache.phoenix.schema.TableRef;
 import org.apache.phoenix.schema.TypeMismatchException;
 import org.apache.phoenix.schema.types.PBoolean;
 import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.EncodedColumnsUtil;
 import org.apache.phoenix.util.ExpressionUtil;
 import org.apache.phoenix.util.ScanUtil;
 import org.apache.phoenix.util.SchemaUtil;
@@ -195,16 +196,36 @@ public class WhereCompiler {
         @Override
         protected ColumnRef resolveColumn(ColumnParseNode node) throws SQLException {
             ColumnRef ref = super.resolveColumn(node);
+            if (disambiguateWithFamily) {
+                return ref;
+            }
             PTable table = ref.getTable();
             // Track if we need to compare KeyValue during filter evaluation
             // using column family. If the column qualifier is enough, we
             // just use that.
-            try {
-                if (!SchemaUtil.isPKColumn(ref.getColumn())) {
-                    table.getColumnForColumnName(ref.getColumn().getName().getString());
+            if (!SchemaUtil.isPKColumn(ref.getColumn())) {
+                if (!EncodedColumnsUtil.usesEncodedColumnNames(table)) {
+                    try {
+                        table.getColumnForColumnName(ref.getColumn().getName().getString());
+                    } catch (AmbiguousColumnException e) {
+                        disambiguateWithFamily = true;
+                    }
+                } else {
+                    for (PColumnFamily columnFamily : table.getColumnFamilies()) {
+                        if (columnFamily.getName().equals(ref.getColumn().getFamilyName())) {
+                            continue;
+                        }
+                        try {
+                            table.getColumnForColumnQualifier(columnFamily.getName().getBytes(),
+                                ref.getColumn().getColumnQualifierBytes());
+                            // If we find the same qualifier name with different columnFamily,
+                            // then set disambiguateWithFamily to true
+                            disambiguateWithFamily = true;
+                            break;
+                        } catch (ColumnNotFoundException ignore) {
+                        }
+                    }
                 }
-            } catch (AmbiguousColumnException e) {
-                disambiguateWithFamily = true;
             }
             return ref;
          }