This is an automated email from the ASF dual-hosted git repository. vjasani pushed a commit to branch 5.2 in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/5.2 by this push: new f1a169a5b0 PHOENIX-7610 Using CAST() on pk columns always result in full table scan (#2150) f1a169a5b0 is described below commit f1a169a5b059aea386028bfd5289b67e20414ea9 Author: Viraj Jasani <vjas...@apache.org> AuthorDate: Sat May 17 18:50:55 2025 -0700 PHOENIX-7610 Using CAST() on pk columns always result in full table scan (#2150) --- .../phoenix/expression/CoerceExpression.java | 12 ++++++ .../apache/phoenix/end2end/CastAndCoerceIT.java | 45 ++++++++++++++++++---- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/CoerceExpression.java b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/CoerceExpression.java index fc8fe39b79..27460d6f5d 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/CoerceExpression.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/CoerceExpression.java @@ -143,6 +143,18 @@ public class CoerceExpression extends BaseSingleExpression { WritableUtils.writeVInt(output, maxLength == null ? -1 : maxLength); } + @Override + public boolean isStateless() { + // It is important to associate the stateless-ness of the CoerceExpression + // child with the CoerceExpression. Without this, ComparisonExpression and + // KeyExpressionVisitor will not be evaluated on the client side, and + // thus WhereOptimizer will always select Full table scan + // even for the query that is supposed to use Range scan or Point lookup + // on the single row. + // Jira: PHOENIX-7610. + return getChild().isStateless(); + } + @Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (getChild().evaluate(tuple, ptr)) { diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CastAndCoerceIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CastAndCoerceIT.java index d5183c36da..66931a1b30 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CastAndCoerceIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CastAndCoerceIT.java @@ -33,6 +33,9 @@ import java.sql.ResultSet; import java.util.Collection; import java.util.Properties; +import org.apache.phoenix.compile.ExplainPlan; +import org.apache.phoenix.compile.ExplainPlanAttributes; +import org.apache.phoenix.jdbc.PhoenixPreparedStatement; import org.apache.phoenix.util.PropertiesUtil; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -142,26 +145,54 @@ public class CastAndCoerceIT extends BaseQueryIT { conn.close(); } } - + @Test public void testCoerceTinyIntToSmallInt() throws Exception { - String query = "SELECT entity_id FROM " + tableName + " WHERE organization_id=? AND a_byte >= a_short"; + String query = "SELECT entity_id FROM " + tableName + + " WHERE organization_id=? AND a_byte >= a_short"; String url = getUrl(); Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); - Connection conn = DriverManager.getConnection(url, props); - try { + try (Connection conn = DriverManager.getConnection(url, props)) { PreparedStatement statement = conn.prepareStatement(query); statement.setString(1, tenantId); ResultSet rs = statement.executeQuery(); assertTrue(rs.next()); assertEquals(ROW9, rs.getString(1)); assertFalse(rs.next()); - } finally { - conn.close(); + + ExplainPlan plan = statement.unwrap(PhoenixPreparedStatement.class).optimizeQuery(query) + .getExplainPlan(); + ExplainPlanAttributes explainPlanAttributes = plan.getPlanStepsAsAttributes(); + assertEquals(tableName, explainPlanAttributes.getTableName()); + assertEquals("PARALLEL 1-WAY", explainPlanAttributes.getIteratorTypeAndScanSize()); + assertEquals("RANGE SCAN ", explainPlanAttributes.getExplainScanType()); + } + } + + @Test + public void testCoerceWithRangeScan() throws Exception { + String query = "SELECT entity_id FROM " + tableName + + " WHERE organization_id = cast(? as varchar) AND " + + "cast(a_byte as smallint) >= a_short"; + String url = getUrl(); + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + try (Connection conn = DriverManager.getConnection(url, props)) { + PreparedStatement statement = conn.prepareStatement(query); + statement.setString(1, tenantId); + ResultSet rs = statement.executeQuery(); + assertTrue(rs.next()); + assertEquals(ROW9, rs.getString(1)); + assertFalse(rs.next()); + + ExplainPlan plan = statement.unwrap(PhoenixPreparedStatement.class).optimizeQuery(query) + .getExplainPlan(); + ExplainPlanAttributes explainPlanAttributes = plan.getPlanStepsAsAttributes(); + assertEquals(tableName, explainPlanAttributes.getTableName()); + assertEquals("PARALLEL 1-WAY", explainPlanAttributes.getIteratorTypeAndScanSize()); + assertEquals("RANGE SCAN ", explainPlanAttributes.getExplainScanType()); } } - @Test public void testCoerceDateToBigInt() throws Exception { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);