Impetus/kundera

Bind parameters don't work when using native queries (CQL)(Cassandra)

ccarpenter04 opened this issue · 0 comments

Bind parameters seem to be broken when working with native queries/CQL on Kundera 3.13 in a way such as

em.createNativeQuery("SELECT * FROM table_foo WHERE bar_id = ?").setParameter(1, barId).getResultList()

Attempting to do so results in the following exception being thrown:

c.i.c.c.CassandraClientBase - Error while executing native CQL query Caused by {}.
javax.persistence.PersistenceException: com.impetus.kundera.KunderaException: InvalidRequestException(why:Invalid amount of bind variables)
	at com.impetus.client.cassandra.CassandraClientBase.executeCQLQuery(CassandraClientBase.java:1846)
	at com.impetus.client.cassandra.CassandraClientBase$CQLClient.executeQuery(CassandraClientBase.java:2034)
	at com.impetus.client.cassandra.CassandraClientBase.executeSelectQuery(CassandraClientBase.java:832)
	at com.impetus.client.cassandra.thrift.ThriftClient.executeQuery(ThriftClient.java:1062)
	at com.impetus.client.cassandra.query.CassQuery.recursivelyPopulateEntities(CassQuery.java:227)
	at com.impetus.kundera.query.QueryImpl.fetch(QueryImpl.java:1377)
	at com.impetus.kundera.query.QueryImpl.getResultList(QueryImpl.java:200)
Caused by: com.impetus.kundera.KunderaException: InvalidRequestException(why:Invalid amount of bind variables)
	at com.impetus.client.cassandra.CassandraClientBase.execute(CassandraClientBase.java:2345)
	at com.impetus.client.cassandra.CassandraClientBase.executeCQLQuery(CassandraClientBase.java:1835)
	at com.impetus.client.cassandra.CassandraClientBase$CQLClient.executeQuery(CassandraClientBase.java:2034)
	at com.impetus.client.cassandra.CassandraClientBase.executeSelectQuery(CassandraClientBase.java:832)
	at com.impetus.client.cassandra.thrift.ThriftClient.executeQuery(ThriftClient.java:1062)
	at com.impetus.client.cassandra.query.CassQuery.recursivelyPopulateEntities(CassQuery.java:227)
	at com.impetus.kundera.query.QueryImpl.fetch(QueryImpl.java:1377)
	at com.impetus.kundera.query.QueryImpl.getResultList(QueryImpl.java:200)
Caused by: org.apache.cassandra.thrift.InvalidRequestException: null
	at org.apache.cassandra.thrift.Cassandra$execute_cql3_query_result$execute_cql3_query_resultStandardScheme.read(Cassandra.java:50297)
	at org.apache.cassandra.thrift.Cassandra$execute_cql3_query_result$execute_cql3_query_resultStandardScheme.read(Cassandra.java:50274)
	at org.apache.cassandra.thrift.Cassandra$execute_cql3_query_result.read(Cassandra.java:50189)
	at org.apache.thrift.TServiceClient.receiveBase(TServiceClient.java:78)
	at org.apache.cassandra.thrift.Cassandra$Client.recv_execute_cql3_query(Cassandra.java:1734)
	at org.apache.cassandra.thrift.Cassandra$Client.execute_cql3_query(Cassandra.java:1719)
	at com.impetus.client.cassandra.CassandraClientBase.execute(CassandraClientBase.java:2341)
	at com.impetus.client.cassandra.CassandraClientBase.executeCQLQuery(CassandraClientBase.java:1835)
	at com.impetus.client.cassandra.CassandraClientBase$CQLClient.executeQuery(CassandraClientBase.java:2034)
	at com.impetus.client.cassandra.CassandraClientBase.executeSelectQuery(CassandraClientBase.java:832)

I see that pull request #983 was supposed to implement support for bind parameters in native queries but that functionality is either broken or incomplete.

The list bindParameters that is added to within KunderaQuery#setParameter(int, Object) is only ever referenced from the CassQuery#populateEntities(EntityMetadata, Client) method which is never reached from our code.

After evaluating expressions at various breakpoints, the issue appears to be caused by the fact that support for bind parameters in native queries is only implemented in the QueryImpl#populateEntities execution path called by QueryImpl#fetch, and not the QueryImpl#recursivelyPopulateEntities(EntityMetadata, Client) execution path that is followed when QueryImpl#isRelational(EntityMetadata) returns true.

This may be related to the fact that the column being accessed was created as a result of the modeled object having @ManyToOne and @JoinColumn(name = "bar_id) applied to the field being accessed, since that seems to be what makes QueryImpl#isRelational(EntityMetadata) return true according to its javadocs.

Regardless of the reason, this is extremely important functionality that seems to have been overlooked.