Repository: phoenix Updated Branches: refs/heads/4.x-HBase-1.1 6fbcc9b2a -> 30e4c27fd
PHOENIX-4658 IllegalStateException: requestSeek cannot be called on ReversedKeyValueHeap (Toshihiro Suzuki) Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/478edfcd Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/478edfcd Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/478edfcd Branch: refs/heads/4.x-HBase-1.1 Commit: 478edfcd946318d6b019145e78f486cbb9dd628f Parents: 6fbcc9b Author: James Taylor <jtay...@salesforce.com> Authored: Wed Apr 11 13:31:38 2018 -0700 Committer: James Taylor <jtay...@salesforce.com> Committed: Wed Apr 11 13:48:51 2018 -0700 ---------------------------------------------------------------------- .../phoenix/end2end/MultiCfQueryExecIT.java | 47 ++++++++++++++++++++ .../apache/phoenix/compile/OrderByCompiler.java | 11 +++-- .../apache/phoenix/compile/QueryCompiler.java | 12 +---- .../java/org/apache/phoenix/parse/HintNode.java | 4 ++ .../java/org/apache/phoenix/util/ScanUtil.java | 2 + 5 files changed, 62 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/478edfcd/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java index d94df6c..01da2d8 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java @@ -31,11 +31,13 @@ import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.util.List; import java.util.Properties; import org.apache.phoenix.query.KeyRange; import org.apache.phoenix.util.PropertiesUtil; +import org.apache.phoenix.util.QueryUtil; import org.apache.phoenix.util.SchemaUtil; import org.apache.phoenix.util.TestUtil; import org.junit.Before; @@ -406,4 +408,49 @@ public class MultiCfQueryExecIT extends ParallelStatsEnabledIT { assertFalse(rs.next()); } } + + @Test + public void testBug4658() throws Exception { + try (Connection conn = DriverManager.getConnection(getUrl()); + Statement stmt = conn.createStatement()) { + String tableName = generateUniqueName(); + + stmt.execute("CREATE TABLE " + tableName + " (" + + "COL1 VARCHAR NOT NULL," + + "COL2 VARCHAR NOT NULL," + + "COL3 VARCHAR," + + "FAM.COL4 VARCHAR," + + "CONSTRAINT TRADE_EVENT_PK PRIMARY KEY (COL1, COL2))"); + stmt.execute("UPSERT INTO " + tableName + " (COL1, COL2) values ('111', 'AAA')"); + stmt.execute("UPSERT INTO " + tableName + " (COL1, COL2) values ('222', 'AAA')"); + conn.commit(); + + try (ResultSet rs = stmt.executeQuery( + "SELECT * FROM " + tableName + " WHERE COL2 = 'AAA' ORDER BY COL1 DESC")) { + assertTrue(rs.next()); + assertEquals(rs.getString("COL1"), "222"); + assertEquals(rs.getString("COL2"), "AAA"); + assertTrue(rs.next()); + assertEquals(rs.getString("COL1"), "111"); + assertEquals(rs.getString("COL2"), "AAA"); + assertFalse(rs.next()); + } + + // Tests for FORWARD_SCAN hint + String query = "SELECT /*+ FORWARD_SCAN */ * FROM " + tableName + " WHERE COL2 = 'AAA' ORDER BY COL1 DESC"; + try (ResultSet rs = stmt.executeQuery("EXPLAIN " + query)) { + String explainPlan = QueryUtil.getExplainPlan(rs); + assertFalse(explainPlan.contains("REVERSE")); + } + try (ResultSet rs = stmt.executeQuery(query)) { + assertTrue(rs.next()); + assertEquals(rs.getString("COL1"), "222"); + assertEquals(rs.getString("COL2"), "AAA"); + assertTrue(rs.next()); + assertEquals(rs.getString("COL1"), "111"); + assertEquals(rs.getString("COL2"), "AAA"); + assertFalse(rs.next()); + } + } + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/478edfcd/phoenix-core/src/main/java/org/apache/phoenix/compile/OrderByCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/OrderByCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/OrderByCompiler.java index 1097f70..b83c7a8 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/OrderByCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/OrderByCompiler.java @@ -30,6 +30,7 @@ import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.execute.TupleProjector; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.OrderByExpression; +import org.apache.phoenix.parse.HintNode.Hint; import org.apache.phoenix.parse.LiteralParseNode; import org.apache.phoenix.parse.OrderByNode; import org.apache.phoenix.parse.ParseNode; @@ -154,12 +155,16 @@ public class OrderByCompiler { // If we're ordering by the order returned by the scan, we don't need an order by if (isInRowKeyOrder && tracker.isOrderPreserving()) { if (tracker.isReverse()) { - // Don't use reverse scan if we're using a skip scan, as our skip scan doesn't support this yet. + // Don't use reverse scan if: + // 1) we're using a skip scan, as our skip scan doesn't support this yet. + // 2) we have the FORWARD_SCAN hint set to choose to keep loading of column + // families on demand versus doing a reverse scan // REV_ROW_KEY_ORDER_BY scan would not take effect for a projected table, so don't return it for such table types. if (context.getConnection().getQueryServices().getProps().getBoolean(QueryServices.USE_REVERSE_SCAN_ATTRIB, QueryServicesOptions.DEFAULT_USE_REVERSE_SCAN) && !context.getScanRanges().useSkipScanFilter() && context.getCurrentTable().getTable().getType() != PTableType.PROJECTED - && context.getCurrentTable().getTable().getType() != PTableType.SUBQUERY) { + && context.getCurrentTable().getTable().getType() != PTableType.SUBQUERY + && !statement.getHint().hasHint(Hint.FORWARD_SCAN)) { return OrderBy.REV_ROW_KEY_ORDER_BY; } } else { @@ -172,4 +177,4 @@ public class OrderByCompiler { private OrderByCompiler() { } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/478edfcd/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java index 9568ad8..3e5f5ee 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java @@ -66,7 +66,6 @@ import org.apache.phoenix.parse.SelectStatement; import org.apache.phoenix.parse.SubqueryParseNode; import org.apache.phoenix.parse.TableNode; import org.apache.phoenix.query.ConnectionQueryServices; -import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.query.QueryServicesOptions; import org.apache.phoenix.schema.AmbiguousColumnException; @@ -91,13 +90,6 @@ import com.google.common.collect.Sets; */ public class QueryCompiler { private static final ParseNodeFactory NODE_FACTORY = new ParseNodeFactory(); - /* - * Not using Scan.setLoadColumnFamiliesOnDemand(true) because we don't - * want to introduce a dependency on 0.94.5 (where this feature was - * introduced). This will do the same thing. Once we do have a - * dependency on 0.94.5 or above, switch this around. - */ - private static final String LOAD_COLUMN_FAMILIES_ON_DEMAND_ATTR = "_ondemand_"; private final PhoenixStatement statement; private final Scan scan; private final Scan originalScan; @@ -128,9 +120,7 @@ public class QueryCompiler { this.noChildParentJoinOptimization = select.getHint().hasHint(Hint.NO_CHILD_PARENT_JOIN_OPTIMIZATION); ConnectionQueryServices services = statement.getConnection().getQueryServices(); this.costBased = services.getProps().getBoolean(QueryServices.COST_BASED_OPTIMIZER_ENABLED, QueryServicesOptions.DEFAULT_COST_BASED_OPTIMIZER_ENABLED); - if (services.getLowestClusterHBaseVersion() >= PhoenixDatabaseMetaData.ESSENTIAL_FAMILY_VERSION_THRESHOLD) { - this.scan.setAttribute(LOAD_COLUMN_FAMILIES_ON_DEMAND_ATTR, QueryConstants.TRUE); - } + scan.setLoadColumnFamiliesOnDemand(true); if (select.getHint().hasHint(Hint.NO_CACHE)) { scan.setCacheBlocks(false); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/478edfcd/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java index 6d8451b..39e9b05 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java @@ -104,6 +104,10 @@ public class HintNode { * Enforces a serial scan. */ SERIAL, + /** + * Enforces a forward scan. + */ + FORWARD_SCAN, }; private final Map<Hint,String> hints; http://git-wip-us.apache.org/repos/asf/phoenix/blob/478edfcd/phoenix-core/src/main/java/org/apache/phoenix/util/ScanUtil.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/ScanUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/ScanUtil.java index 9c710c1..dd885fd 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/ScanUtil.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/ScanUtil.java @@ -612,10 +612,12 @@ public class ScanUtil { public static void setReversed(Scan scan) { scan.setAttribute(BaseScannerRegionObserver.REVERSE_SCAN, PDataType.TRUE_BYTES); + scan.setLoadColumnFamiliesOnDemand(false); } public static void unsetReversed(Scan scan) { scan.setAttribute(BaseScannerRegionObserver.REVERSE_SCAN, PDataType.FALSE_BYTES); + scan.setLoadColumnFamiliesOnDemand(true); } private static byte[] getReversedRow(byte[] startRow) {