You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ri...@apache.org on 2021/09/14 12:10:23 UTC
[phoenix] branch 4.16 updated: PHOENIX-5072 Cursor Query Loops
Eternally with Local Index, Returns Fine Without It
This is an automated email from the ASF dual-hosted git repository.
richardantal pushed a commit to branch 4.16
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/4.16 by this push:
new a166b33 PHOENIX-5072 Cursor Query Loops Eternally with Local Index, Returns Fine Without It
a166b33 is described below
commit a166b33f698f45ba2d2ef873419effe93a3d0606
Author: Richard Antal <an...@gmail.com>
AuthorDate: Tue Aug 17 16:38:16 2021 +0200
PHOENIX-5072 Cursor Query Loops Eternally with Local Index, Returns Fine Without It
---
.../end2end/CursorWithRowValueConstructorIT.java | 92 ++++++++++++++++++++++
.../phoenix/compile/DeclareCursorCompiler.java | 8 +-
2 files changed, 98 insertions(+), 2 deletions(-)
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CursorWithRowValueConstructorIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CursorWithRowValueConstructorIT.java
index e5457d6..6e91d1f 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CursorWithRowValueConstructorIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CursorWithRowValueConstructorIT.java
@@ -40,10 +40,13 @@ import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
+import java.sql.Statement;
import java.sql.SQLException;
import java.sql.Timestamp;
+import java.text.DecimalFormat;
import java.util.Properties;
import java.util.Random;
+import java.util.UUID;
import org.apache.phoenix.util.CursorUtil;
import org.apache.phoenix.util.DateUtil;
@@ -669,4 +672,93 @@ public class CursorWithRowValueConstructorIT extends ParallelStatsDisabledIT {
conn.close();
}
}
+
+ @Test
+ public void testCursorWithIndex() throws Exception {
+ String cursorName = generateUniqueName();
+ String tableName = generateUniqueName();
+ String indexName = generateUniqueName();
+ Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+
+ Statement stmt = conn.createStatement();
+
+ String createTable = "CREATE TABLE IF NOT EXISTS " + tableName +"\n" +
+ "( \n" +
+ " ID VARCHAR NOT NULL,\n" +
+ " NAME VARCHAR ,\n" +
+ " ANOTHER_VALUE VARCHAR ,\n" +
+ " TRANSACTION_TIME TIMESTAMP ,\n" +
+ " CONSTRAINT pk PRIMARY KEY(ID)\n" +
+ ")";
+ stmt.execute(createTable);
+
+ //Creating an index
+ String createIndex = "CREATE LOCAL INDEX " + indexName + " ON " + tableName + "(NAME, TRANSACTION_TIME DESC) INCLUDE(ANOTHER_VALUE)";
+ stmt.execute(createIndex);
+
+ //Insert Some Items.
+ DecimalFormat dmf = new DecimalFormat("0000");
+ final String prefix = "ReferenceData.Country/";
+ for (int i = 0; i < 10; i++)
+ {
+ for (int j = 0; j < 10; j++)
+ {
+ PreparedStatement prstmt = conn.prepareStatement("UPSERT INTO " + tableName + " VALUES(?,?,?,?)");
+ prstmt.setString(1, UUID.randomUUID().toString());
+ prstmt.setString(2,prefix + dmf.format(i+j*1000));
+ prstmt.setString(3,UUID.randomUUID().toString());
+ prstmt.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
+ prstmt.execute();
+ conn.commit();
+ prstmt.close();
+ }
+ }
+
+ String countSQL = "SELECT COUNT(1) AS TOTAL_ITEMS FROM " + tableName + " where NAME like 'ReferenceData.Country/2%' ";
+ ResultSet rs = stmt.executeQuery(countSQL);
+ rs.next();
+ final int totalCount = rs.getInt("TOTAL_ITEMS");
+ rs.close();
+
+ //Now a Cursor
+ String cursorSQL = "DECLARE " + cursorName + " CURSOR FOR SELECT NAME,ANOTHER_VALUE FROM "
+ + tableName + " where NAME like 'ReferenceData.Country/2%' ORDER BY TRANSACTION_TIME DESC";
+ PreparedStatement cursorStatement = conn.prepareStatement(cursorSQL);
+ cursorStatement.execute();
+ PreparedStatement openCursorStatement = conn.prepareStatement("OPEN " + cursorName);
+ openCursorStatement.execute();
+
+ rs = stmt.executeQuery("EXPLAIN FETCH NEXT 10 ROWS FROM " + cursorName);
+ rs.next();
+ assertTrue(rs.getString(1)
+ .contains("CLIENT PARALLEL 1-WAY RANGE SCAN"));
+ PreparedStatement next10Rows = conn.prepareStatement("FETCH NEXT 10 ROWS FROM " + cursorName);
+ int itemsReturnedByCursor = 0;
+ while(true)
+ {
+ ResultSet cursorRS = next10Rows.executeQuery();
+ int rowsReadBeforeEmpty = 0;
+ while(cursorRS.next())
+ {
+ itemsReturnedByCursor++;
+ rowsReadBeforeEmpty++;
+ }
+ if(rowsReadBeforeEmpty > 0 )
+ {
+ cursorRS.close();
+ }
+ else
+ {
+ conn.prepareStatement("CLOSE " + cursorName).executeUpdate();
+ break;
+ }
+
+ if(itemsReturnedByCursor > (totalCount * 3))
+ {
+ break;
+ }
+ }
+ assertEquals(totalCount, itemsReturnedByCursor);
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/DeclareCursorCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/DeclareCursorCompiler.java
index 5280291..89acfe1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/DeclareCursorCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/DeclareCursorCompiler.java
@@ -45,10 +45,14 @@ public class DeclareCursorCompiler {
private final Operation operation;
private QueryPlan queryPlan;
- public DeclareCursorCompiler(PhoenixStatement statement, Operation operation, QueryPlan queryPlan) {
+ public DeclareCursorCompiler(PhoenixStatement statement, Operation operation, QueryPlan queryPlan) throws SQLException {
this.statement = statement;
this.operation = operation;
- this.queryPlan = queryPlan;
+ // See PHOENIX-5072
+ // We optimize the plan inside the CursorFetchPlan here at the first place.
+ // Later when the next optimize is called, the original CursorFetchPlan will be selected as there won't be any better plans.
+ this.queryPlan = statement.getConnection().getQueryServices().getOptimizer()
+ .optimize(statement, queryPlan);
}
public MutationPlan compile(final DeclareCursorStatement declare) throws SQLException {