You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Added a ScanUtil.hasDynamicColumns(table) check in WhereCompiler.setScanFilter() so that when the WHERE clause references multiple columns and the table has dynamic columns, Phoenix falls back to MultiCQKeyValueComparisonFilter (HashMap-based, raw byte comparison) instead of MultiEncodedCQKeyValueComparisonFilter (array-based, expects encoded integer qualifiers).
Why are the changes needed?
When a table uses column encoding (the default) and the WHERE clause filters on multiple dynamic columns, Phoenix selects MultiEncodedCQKeyValueComparisonFilter. This filter calls encodingScheme.decode() on each column qualifier, expecting a 2-4 byte encoded integer.
Dynamic columns use the actual column name as the qualifier (e.g., "POPULATION" = 10 bytes), causing InvalidQualifierBytesException: Expected length: 2. Actual: 10.
Single dynamic column in WHERE works fine because SingleCQKeyValueComparisonFilter uses raw byte comparison. The workaround was COLUMN_ENCODED_BYTES=NONE on table creation, which defeats the purpose of encoding.
Does this PR introduce any user-facing change?
Yes. Queries with multiple dynamic columns in the WHERE clause now work correctly on tables with column encoding enabled (the default). Previously these queries threw InvalidQualifierBytesException. No workaround (COLUMN_ENCODED_BYTES=NONE) is needed anymore
How was this patch tested?
5 new unit tests in WhereCompilerTest verifying correct filter selection:
Single dynamic column → SingleCQKeyValueComparisonFilter
EARLIER BEHAVIOUR:
1 row selected (0.012 seconds)
0: jdbc:phoenix:> DROP TABLE IF EXISTS test_no_workaround CASCADE;
No rows affected (0.948 seconds)
0: jdbc:phoenix:> CREATE TABLE test_no_workaround (
. . . . . . . .)> id VARCHAR PRIMARY KEY,
. . . . . . . .)> name VARCHAR
. . . . . . . .)> );
No rows affected (0.63 seconds)
0: jdbc:phoenix:> UPSERT INTO test_no_workaround(id, name, city VARCHAR, department VARCHAR, age INTEGER)
. . . .semicolon> VALUES ('1', 'John Doe', 'Chennai', 'Engineering', 30);
. . . . . . . . >
. . . . . . . . > UPSERT INTO test_no_workaround(id, name, city VARCHAR, department VARCHAR, age INTEGER)
. . . .semicolon> VALUES ('2', 'Jane Smith', 'Mumbai', 'Marketing', 28);
. . . . . . . . >
. . . . . . . . > UPSERT INTO test_no_workaround(id, name, city VARCHAR, department VARCHAR, age INTEGER)
. . . .semicolon> VALUES ('3', 'Bob Wilson', 'Bangalore', 'Engineering', 35);
1 row affected (0.006 seconds)
1 row affected (0.004 seconds)
1 row affected (0.003 seconds)
0: jdbc:phoenix:> SELECT id, name, city, department
. . . .semicolon> FROM test_no_workaround(city VARCHAR, department VARCHAR)
. . . .semicolon> WHERE city = 'Chennai' AND department = 'Engineering';
org.apache.phoenix.schema.PTable$QualifierEncodingScheme$InvalidQualifierBytesException: Invalid number of qualifier bytes. Expected length: 4. Actual: 4
at org.apache.phoenix.schema.PTable$QualifierEncodingScheme.getReservedQualifier(PTable.java:549)
at org.apache.phoenix.schema.PTable$QualifierEncodingScheme.access$400(PTable.java:318)
at org.apache.phoenix.schema.PTable$QualifierEncodingScheme$3.decode(PTable.java:398)
at org.apache.phoenix.filter.MultiEncodedCQKeyValueComparisonFilter$1.visit(MultiEncodedCQKeyValueComparisonFilter.java:182)
at
CURRENT BEHAVIOUR :
0: jdbc:phoenix:> DROP TABLE IF EXISTS test_no_workaround CASCADE;
. . . . . . . . > CREATE TABLE test_no_workaround (id VARCHAR PRIMARY KEY, name VARCHAR);
. . . . . . . . > UPSERT INTO test_no_workaround(id, name, city VARCHAR, department VARCHAR, age INTEGER) VALUES ('1', 'John Doe', '
Chennai', 'Engineering', 30);
. . . . . . . . > UPSERT INTO test_no_workaround(id, name, city VARCHAR, department VARCHAR, age INTEGER) VALUES ('2', 'Jane Smith',
'Mumbai', 'Marketing', 28);
. . . . . . . . > UPSERT INTO test_no_workaround(id, name, city VARCHAR, department VARCHAR, age INTEGER) VALUES ('3', 'Bob Wilson',
'Bangalore', 'Engineering', 35);
. . . . . . . . > SELECT id, name, city, department FROM test_no_workaround(city VARCHAR, department VARCHAR) WHERE city = 'Chennai'
AND department = 'Engineering';
No rows affected (0.071 seconds)
No rows affected (0.734 seconds)
1 row affected (0.021 seconds)
1 row affected (0.004 seconds)
1 row affected (0.002 seconds)
+----+----------+---------+-------------+
| ID | NAME | CITY | DEPARTMENT |
+----+----------+---------+-------------+
| 1 | John Doe | Chennai | Engineering |
+----+----------+---------+-------------+
1 row selected (0.026 seconds)
0: jdbc:phoenix:> SELECT id, name, city, department FROM test_no_workaround(city VARCHAR, department VARCHAR) WHERE city = 'Chennai'
AND department = 'Engineering';
+----+----------+---------+-------------+
| ID | NAME | CITY | DEPARTMENT |
+----+----------+---------+-------------+
| 1 | John Doe | Chennai | Engineering |
+----+----------+---------+-------------+
1 row selected (0.015 seconds)
0: jdbc:phoenix:>
The reason will be displayed to describe this comment to others. Learn more.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
Added a ScanUtil.hasDynamicColumns(table) check in WhereCompiler.setScanFilter() so that when the WHERE clause references multiple columns and the table has dynamic columns, Phoenix falls back to MultiCQKeyValueComparisonFilter (HashMap-based, raw byte comparison) instead of MultiEncodedCQKeyValueComparisonFilter (array-based, expects encoded integer qualifiers).
Why are the changes needed?
When a table uses column encoding (the default) and the WHERE clause filters on multiple dynamic columns, Phoenix selects MultiEncodedCQKeyValueComparisonFilter. This filter calls encodingScheme.decode() on each column qualifier, expecting a 2-4 byte encoded integer.
Dynamic columns use the actual column name as the qualifier (e.g., "POPULATION" = 10 bytes), causing InvalidQualifierBytesException: Expected length: 2. Actual: 10.
Single dynamic column in WHERE works fine because SingleCQKeyValueComparisonFilter uses raw byte comparison. The workaround was COLUMN_ENCODED_BYTES=NONE on table creation, which defeats the purpose of encoding.
Does this PR introduce any user-facing change?
Yes. Queries with multiple dynamic columns in the WHERE clause now work correctly on tables with column encoding enabled (the default). Previously these queries threw InvalidQualifierBytesException. No workaround (COLUMN_ENCODED_BYTES=NONE) is needed anymore
How was this patch tested?
5 new unit tests in WhereCompilerTest verifying correct filter selection:
1 new integration test in DynamicColumnIT covering 7 scenarios:
Was this patch authored or co-authored using generative AI tooling?
Yes. This patch was co-authored with Claude Code opus-4.6.