Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ public Void visit(KeyValueColumnExpression expression) {
break;
case MULTIPLE:
filter = isPossibleToUseEncodedCQFilter(encodingScheme, storageScheme)
&& !ScanUtil.hasDynamicColumns(table)
? new MultiEncodedCQKeyValueComparisonFilter(whereClause, encodingScheme, allCFs,
essentialCF)
: (disambiguateWithFamily
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,138 @@ public void testDynamicColumnOnNewTable() throws Exception {
}
}

/**
* Test that multiple dynamic columns in a WHERE clause work correctly on a table
* with column encoding enabled (the default). Regression test for PHOENIX-5236.
*/
@Test
public void testMultipleDynamicColumnsInWhere() throws Exception {
String tableName = generateUniqueName();
String ddl = "create table " + tableName
+ " (id VARCHAR PRIMARY KEY, name VARCHAR)";
try (Connection conn = DriverManager.getConnection(getUrl())) {
conn.createStatement().execute(ddl);

// Upsert rows with dynamic columns
String dml = "UPSERT INTO " + tableName
+ "(id, name, city VARCHAR, department VARCHAR, age INTEGER)"
+ " VALUES (?, ?, ?, ?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(dml)) {
stmt.setString(1, "1");
stmt.setString(2, "John");
stmt.setString(3, "Chennai");
stmt.setString(4, "Engineering");
stmt.setInt(5, 30);
stmt.executeUpdate();

stmt.setString(1, "2");
stmt.setString(2, "Jane");
stmt.setString(3, "Mumbai");
stmt.setString(4, "Marketing");
stmt.setInt(5, 28);
stmt.executeUpdate();

stmt.setString(1, "3");
stmt.setString(2, "Bob");
stmt.setString(3, "Chennai");
stmt.setString(4, "Marketing");
stmt.setInt(5, 35);
stmt.executeUpdate();

conn.commit();
}

// Single dynamic column in WHERE - baseline
String query = "SELECT id, name FROM " + tableName
+ " (city VARCHAR) WHERE city = ?";
try (PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, "Chennai");
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
assertEquals("1", rs.getString(1));
assertEquals("John", rs.getString(2));
assertTrue(rs.next());
assertEquals("3", rs.getString(1));
assertEquals("Bob", rs.getString(2));
assertFalse(rs.next());
}

// Multiple dynamic columns in WHERE - PHOENIX-5236 bug
query = "SELECT id, name FROM " + tableName
+ " (city VARCHAR, department VARCHAR, age INTEGER)"
+ " WHERE city = ? AND department = ?";
try (PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, "Chennai");
stmt.setString(2, "Engineering");
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
assertEquals("1", rs.getString(1));
assertEquals("John", rs.getString(2));
assertFalse(rs.next());
}

// Dynamic columns compared to each other
query = "SELECT id, name FROM " + tableName
+ " (city VARCHAR, department VARCHAR)"
+ " WHERE city = department";
try (PreparedStatement stmt = conn.prepareStatement(query)) {
ResultSet rs = stmt.executeQuery();
assertFalse(rs.next());
}

// 3 dynamic columns in WHERE
query = "SELECT id, name FROM " + tableName
+ " (city VARCHAR, department VARCHAR, age INTEGER)"
+ " WHERE city = ? AND department = ? AND age > ?";
try (PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, "Chennai");
stmt.setString(2, "Engineering");
stmt.setInt(3, 25);
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
assertEquals("1", rs.getString(1));
assertEquals("John", rs.getString(2));
assertFalse(rs.next());
}

// 1 schema column + 2 dynamic columns in WHERE (mixed)
query = "SELECT id FROM " + tableName
+ " (city VARCHAR, department VARCHAR)"
+ " WHERE name = ? AND city = ? AND department = ?";
try (PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, "John");
stmt.setString(2, "Chennai");
stmt.setString(3, "Engineering");
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
assertEquals("1", rs.getString(1));
assertFalse(rs.next());
}

// 2 dynamic + 1 schema column in WHERE (mixed, different order)
query = "SELECT id FROM " + tableName
+ " (city VARCHAR, age INTEGER)"
+ " WHERE city = ? AND age > ? AND name = ?";
try (PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, "Chennai");
stmt.setInt(2, 30);
stmt.setString(3, "Bob");
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
assertEquals("3", rs.getString(1));
assertFalse(rs.next());
}

// No dynamic columns in WHERE (schema-only, baseline - no regression)
query = "SELECT id FROM " + tableName + " WHERE name = ?";
try (PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, "Jane");
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
assertEquals("2", rs.getString(1));
assertFalse(rs.next());
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@
import org.apache.phoenix.expression.LiteralExpression;
import org.apache.phoenix.expression.RowKeyColumnExpression;
import org.apache.phoenix.expression.function.SubstrFunction;
import org.apache.phoenix.filter.MultiCQKeyValueComparisonFilter;
import org.apache.phoenix.filter.MultiEncodedCQKeyValueComparisonFilter;
import org.apache.phoenix.filter.RowKeyComparisonFilter;
import org.apache.phoenix.filter.SingleCQKeyValueComparisonFilter;
import org.apache.phoenix.filter.SkipScanFilter;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
Expand Down Expand Up @@ -1181,4 +1184,130 @@ public void testWhereInclusion() throws SQLException {
}
}

// ===== PHOENIX-5236: Filter selection tests for dynamic columns =====

/**
* Test that a single dynamic column in WHERE uses SingleCQKeyValueComparisonFilter.
*/
@Test
public void testSingleDynamicColumnFilterSelection() throws SQLException {
PhoenixConnection pconn =
DriverManager.getConnection(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES))
.unwrap(PhoenixConnection.class);
String tableName = "T_" + generateUniqueName();
pconn.createStatement().execute(
"CREATE TABLE " + tableName + " (id VARCHAR PRIMARY KEY, name VARCHAR)");

String query = "SELECT id FROM " + tableName
+ " (city VARCHAR) WHERE city = 'Chennai'";
PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
QueryPlan plan = pstmt.optimizeQuery();
Scan scan = plan.getContext().getScan();
Filter filter = scan.getFilter();
assertTrue("Expected SingleCQKeyValueComparisonFilter for single dynamic column in WHERE, got: "
+ (filter == null ? "null" : filter.getClass().getSimpleName()),
filter instanceof SingleCQKeyValueComparisonFilter);
}

/**
* Test that multiple dynamic columns in WHERE uses MultiCQKeyValueComparisonFilter
* (not MultiEncodedCQKeyValueComparisonFilter) on a table with encoding enabled.
* This is the regression test for PHOENIX-5236.
*/
@Test
public void testMultipleDynamicColumnsFilterSelection() throws SQLException {
PhoenixConnection pconn =
DriverManager.getConnection(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES))
.unwrap(PhoenixConnection.class);
String tableName = "T_" + generateUniqueName();
pconn.createStatement().execute(
"CREATE TABLE " + tableName + " (id VARCHAR PRIMARY KEY, name VARCHAR)");

String query = "SELECT id FROM " + tableName
+ " (city VARCHAR, department VARCHAR) WHERE city = 'Chennai' AND department = 'Engineering'";
PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
QueryPlan plan = pstmt.optimizeQuery();
Scan scan = plan.getContext().getScan();
Filter filter = scan.getFilter();
assertTrue(
"Expected MultiCQKeyValueComparisonFilter for multiple dynamic columns in WHERE, got: "
+ (filter == null ? "null" : filter.getClass().getSimpleName()),
filter instanceof MultiCQKeyValueComparisonFilter);
}

/**
* Test that multiple schema-defined columns in WHERE still uses
* MultiEncodedCQKeyValueComparisonFilter on a table with encoding enabled.
*/
@Test
public void testMultipleSchemaColumnsStillUsesEncodedFilter() throws SQLException {
PhoenixConnection pconn =
DriverManager.getConnection(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES))
.unwrap(PhoenixConnection.class);
String tableName = "T_" + generateUniqueName();
pconn.createStatement().execute(
"CREATE TABLE " + tableName
+ " (id VARCHAR PRIMARY KEY, city VARCHAR, department VARCHAR)");

String query = "SELECT id FROM " + tableName
+ " WHERE city = 'Chennai' AND department = 'Engineering'";
PhoenixPreparedStatement pstmt = newPreparedStatement(pconn, query);
QueryPlan plan = pstmt.optimizeQuery();
Scan scan = plan.getContext().getScan();
Filter filter = scan.getFilter();
assertTrue(
"Expected MultiEncodedCQKeyValueComparisonFilter for schema columns in WHERE, got: "
+ (filter == null ? "null" : filter.getClass().getSimpleName()),
filter instanceof MultiEncodedCQKeyValueComparisonFilter);
}

/**
* Test that a table with COLUMN_ENCODED_BYTES=NONE uses MultiCQKeyValueComparisonFilter
* for multiple columns (regardless of whether they are dynamic).
*/
@Test
public void testNonEncodedTableUsesMultiCQFilter() throws SQLException {
PhoenixConnection pconn =
DriverManager.getConnection(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES))
.unwrap(PhoenixConnection.class);
String tableName = "T_" + generateUniqueName();
pconn.createStatement().execute(
"CREATE TABLE " + tableName
+ " (id VARCHAR PRIMARY KEY, city VARCHAR, department VARCHAR) COLUMN_ENCODED_BYTES=NONE");

String query = "SELECT id FROM " + tableName
+ " WHERE city = 'Chennai' AND department = 'Engineering'";
PhoenixPreparedStatement pstmt = newPreparedStatement(pconn, query);
QueryPlan plan = pstmt.optimizeQuery();
Scan scan = plan.getContext().getScan();
Filter filter = scan.getFilter();
assertTrue(
"Expected MultiCQKeyValueComparisonFilter for non-encoded table, got: "
+ (filter == null ? "null" : filter.getClass().getSimpleName()),
filter instanceof MultiCQKeyValueComparisonFilter);
}

/**
* Test that a single schema column in WHERE uses SingleCQKeyValueComparisonFilter
* (baseline behavior unchanged).
*/
@Test
public void testSingleSchemaColumnFilterSelection() throws SQLException {
PhoenixConnection pconn =
DriverManager.getConnection(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES))
.unwrap(PhoenixConnection.class);
String tableName = "T_" + generateUniqueName();
pconn.createStatement().execute(
"CREATE TABLE " + tableName + " (id VARCHAR PRIMARY KEY, city VARCHAR)");

String query = "SELECT id FROM " + tableName + " WHERE city = 'Chennai'";
PhoenixPreparedStatement pstmt = newPreparedStatement(pconn, query);
QueryPlan plan = pstmt.optimizeQuery();
Scan scan = plan.getContext().getScan();
Filter filter = scan.getFilter();
assertTrue("Expected SingleCQKeyValueComparisonFilter for single schema column in WHERE, got: "
+ (filter == null ? "null" : filter.getClass().getSimpleName()),
filter instanceof SingleCQKeyValueComparisonFilter);
}

}