Hi All,

Using Phoenix 4.14.1, I have come across an inner join query in my
application that fails with the NullPointerException if executed as part of
a Cursor, but executes fine if done without it.

To reproduce this issue, you can run the attached program (assuming you
update the JDBC_URL to point to an instance you have running) or you can
follow the steps below:

Create the Table:

CREATE TABLE IF NOT EXISTS MY_STATS
(
   ID                  VARCHAR    NOT NULL,
   ENTRY_NAME                     VARCHAR    ,
   ENTRY_VALUE           DOUBLE     ,
   TRANSACTION_TIME               TIMESTAMP  ,
   CONSTRAINT pk PRIMARY KEY(ID)
)
IMMUTABLE_STORAGE_SCHEME=ONE_CELL_PER_COLUMN,
UPDATE_CACHE_FREQUENCY=900000,
COLUMN_ENCODED_BYTES=NONE,
IMMUTABLE_ROWS=true

Execute a normal query (this works fine):

SELECT * FROM MY_STATS
   INNER JOIN
   (
    SELECT ENTRY_NAME, MAX(TRANSACTION_TIME) AS TRANSACTION_TIME
FROM MY_STATS
     GROUP BY ENTRY_NAME
   ) sub
   ON MY_STATS.ENTRY_NAME = sub.ENTRY_NAME AND MY_STATS.TRANSACTION_TIME =
sub.TRANSACTION_TIME
ORDER BY MY_STATS.TRANSACTION_TIME DESC

Now if you execute the same query, but with the cursor declaration at the
top -

DECLARE MyCursor CURSOR FOR

It produces the following exception:

Exception in thread "main" java.lang.NullPointerException
at
org.apache.phoenix.compile.JoinCompiler$JoinTableConstructor.resolveTable(JoinCompiler.java:187)
at
org.apache.phoenix.compile.JoinCompiler$JoinTableConstructor.visit(JoinCompiler.java:224)
at
org.apache.phoenix.compile.JoinCompiler$JoinTableConstructor.visit(JoinCompiler.java:181)
at
org.apache.phoenix.parse.DerivedTableNode.accept(DerivedTableNode.java:49)
at
org.apache.phoenix.compile.JoinCompiler$JoinTableConstructor.visit(JoinCompiler.java:201)
at
org.apache.phoenix.compile.JoinCompiler$JoinTableConstructor.visit(JoinCompiler.java:181)
at org.apache.phoenix.parse.JoinTableNode.accept(JoinTableNode.java:81)
at org.apache.phoenix.compile.JoinCompiler.compile(JoinCompiler.java:138)
at
org.apache.phoenix.compile.QueryCompiler.compileSelect(QueryCompiler.java:190)
at org.apache.phoenix.compile.QueryCompiler.compile(QueryCompiler.java:153)
at
org.apache.phoenix.jdbc.PhoenixStatement$ExecutableSelectStatement.compilePlan(PhoenixStatement.java:490)
at
org.apache.phoenix.jdbc.PhoenixStatement$ExecutableDeclareCursorStatement.compilePlan(PhoenixStatement.java:950)
at
org.apache.phoenix.jdbc.PhoenixStatement$ExecutableDeclareCursorStatement.compilePlan(PhoenixStatement.java:941)
at
org.apache.phoenix.jdbc.PhoenixStatement$2.call(PhoenixStatement.java:401)
at
org.apache.phoenix.jdbc.PhoenixStatement$2.call(PhoenixStatement.java:391)
at org.apache.phoenix.call.CallRunner.run(CallRunner.java:53)
at
org.apache.phoenix.jdbc.PhoenixStatement.executeMutation(PhoenixStatement.java:390)
at
org.apache.phoenix.jdbc.PhoenixStatement.executeMutation(PhoenixStatement.java:378)
at
org.apache.phoenix.jdbc.PhoenixStatement.execute(PhoenixStatement.java:1825)
at
com.jsteenkamp.phoenix.PhoenixInnerJoinCursorTest.testCursorQuery(PhoenixInnerJoinCursorTest.java:68)
at
com.jsteenkamp.phoenix.PhoenixInnerJoinCursorTest.main(PhoenixInnerJoinCursorTest.java:20)

I think this may be a bug  - though perhaps this is something you might
have come across before?

Thanks,
package com.jsteenkamp.phoenix;

import java.sql.DriverManager;
import java.sql.Statement;

/**
 *  Reproducing the inner join cursor issue
 */
public class PhoenixInnerJoinCursorTest
{
	private final boolean RUN_WITH_CURSOR = true; //With false this works, with true it doesn't
	private final String JDBC_URL = "jdbc:phoenix:localhost:63214";
	
	private final java.sql.Connection conn;
	private final Statement stmt;
	
	public static void main(String... args) throws Exception 
	{
		PhoenixInnerJoinCursorTest innerJoinTest = new PhoenixInnerJoinCursorTest();
		innerJoinTest.testCursorQuery();
		System.out.println("ALL GOOD - No Exception");
	}
	
	public PhoenixInnerJoinCursorTest() throws Exception
	{
		System.out.println("Connecting To : " + JDBC_URL);
		conn = DriverManager.getConnection(JDBC_URL, "sa", "");
		stmt = conn.createStatement();
	}
	
	public void testCursorQuery() throws Exception
	{
		stmt.execute("DROP TABLE IF EXISTS MY_STATS");
		String createTable = "CREATE TABLE IF NOT EXISTS MY_STATS\n" + 
				"(	\n" + 
				"   ID        		                     VARCHAR    NOT NULL,\n" + 
				"   ENTRY_NAME                           VARCHAR    ,\n" +
				"   ENTRY_VALUE		                     DOUBLE     ,\n" + 
				"   TRANSACTION_TIME               TIMESTAMP  ,\n" +
				"   CONSTRAINT pk PRIMARY KEY(ID)\n" + 
			    ") " +
				"IMMUTABLE_STORAGE_SCHEME=ONE_CELL_PER_COLUMN,\n" + 
				"UPDATE_CACHE_FREQUENCY=900000,\n" + 
				"COLUMN_ENCODED_BYTES=NONE,\n" + 
				"IMMUTABLE_ROWS=true";
		
		System.out.println(createTable);
	
		stmt.execute(createTable);
 
		StringBuilder sql = new StringBuilder();
		if(RUN_WITH_CURSOR == true)
		{
			sql.append(" DECLARE MyCursor CURSOR FOR \n");
		}
		sql.append("SELECT * FROM MY_STATS\n" + 
				"   INNER JOIN \n" + 
				"   (\n" + 
				"   	SELECT ENTRY_NAME, MAX(TRANSACTION_TIME) AS TRANSACTION_TIME \n" + 
				"			 FROM MY_STATS \n" + 
				"     GROUP BY ENTRY_NAME\n" + 
				"   ) sub\n" + 
				"   ON MY_STATS.ENTRY_NAME = sub.ENTRY_NAME AND MY_STATS.TRANSACTION_TIME = sub.TRANSACTION_TIME \n" + 
				"ORDER BY MY_STATS.TRANSACTION_TIME DESC ");
		
		System.out.println("Executing: \n" + sql);
		
		stmt.execute(sql.toString());
	}
	
}

















Reply via email to