Cassandra BoundStatement with multiple parameters and a partitioned query

After reading the article Asynchronous Queries with Java Driver on the datastax blog, I was trying to implement a solution similar to Example: Multi-Segment Query, aka Client Side SELECT ... IN.

I currently have some code that looks something like this:

public Future<List<ResultSet>> executeMultipleAsync(final BoundStatement statement, final Object... partitionKeys) {
    List<Future<ResultSet>> futures = Lists.newArrayListWithExpectedSize(partitionKeys.length);
    for (Object partitionKey : partitionKeys) {
      Statement bs = statement.bind(partitionKey);
      futures.add(executeWithRetry(bs));
    }
    return Futures.successfulAsList(futures);
}

      

But I would like to improve this. In the cql request this BoundStatement takes place, I would like to have something similar to this:

SELECT * FROM <column_family_name> WHERE <param1> = :p1_name AND param2 = :p2_name AND <partiotion_key_name> = ?;

      

I would like clients of this method to give me a BoundStatement with parameters already bound (in this case two parameters) and a list of section keys. In this case, all I have to do is bind the section keys and execute queries. Unfortunately, when I bind a key to this statement, I fail with the error - com.datastax.driver.core.exceptions.InvalidTypeException: Invalid type for value 0 of CQL type varchar, expecting class java.lang.String but class java.lang.Long provided

. The problem is I am trying to bind the key to the first parameter and not the last one. This is not a long line.

I can solve this by specifying the section parameter name, but then I would need to get the name through the method parameters or by specifying its index, which again will require an additional method parameter. Anyway, if I use a name or an index, I have to bind it to a specific type. For example: bs.setLong("<key_name>", partitionKey);

. For some reason, I cannot leave it in the BoundStatement to interpret the type of the last parameter.

I would like me to explicitly not omit the parameter name and work around the type issue. Is there something that can be done?

Thank!

+3


source to share


1 answer


I posted the same question in "Java DataStax Driver for Apache Cassandra User Mailing List" and got a response stating functionality that I am missing may be added in the next version (2.2) of the java datastax driver.

In JAVA-721 (which will be introduced in 2.2) we are tentatively planning to add the following signature methods to the BoundStatement:

public BoundStatement setObject (int i, V v) public BoundStatement setObject (string name, V v)

and



You can emulate setObject in 2.1:

void setObject(BoundStatement bs, int position, Object object,
               ProtocolVersion protocolVersion) {
     DataType type =  bs.preparedStatement().getVariables().getType(position);
     ByteBuffer buffer = type.serialize(object, protocolVersion);
     bs.setBytesUnsafe(position, buffer);
 }

      

To avoid passing the parameter name, one thing you could do is look for a position that is not already constrained:

int findUnsetPosition(BoundStatement bs) {
    int size = bs.preparedStatement().getVariables().size();
    for (int i = 0; i < size; i++)
        if (!bs.isSet(i))
            return i;
    throw new IllegalArgumentException("found no unset position");
}

      

I don't recommend it because it is ugly and unpredictable if the user forgot to bind one of the non-PK variables.

The way I would do it requires the user to pass in a callback that sets the PK:

interface PKBinder<T> {
    void bind(BoundStatement bs, T pk);
}
public <T> Future<List<ResultSet>> executeMultipleAsync(final BoundStatement statement, PKBinder<T> pkBinder, final T...

      

partitionKeys)

As a bonus, this will also work with compound partition keys.

+3


source







All Articles