Prepared Statement with collection in IN clause in Datastax Cassandra CQL driver - cassandra

I am trying to run the following query
SELECT edge_id, b_id FROM booking_by_edge WHERE edge_id IN ?
I bind Java list of Long's as a parameter and I get an exception
SyntaxError: line 0:-1 mismatched input '<EOF>' expecting ')' (ResultSetFuture.java:242)
If I try to use (?) it expects single Long item to be bound, but I need a collection
Is there an error in my syntax?

Tested in Cassandra 2.1.3, the following code snippet works:
PreparedStatement prepared = session.prepare("SELECT edge_id, b_id FROM booking_by_edge WHERE edge_id IN ?;");
List<Long> edgeIds = Arrays.asList(1L, 2L, 3L);
session.execute(prepared.bind(edgeIds));

Got response on Datastax bugzilla, it is currently not supported, but planned
https://issues.apache.org/jira/browse/CASSANDRA-4210
Update: Supported in Cassandra 2.0.1

It's a bit hard to find in the documentation but it is described in the tuples section of the manual.
If you want to use named parameters you should use the setList() method.
BoundStatement bs = session.prepare("select col from table where col in :values").bind();
bs.setList("values", Arrays.asList(v1, v2, v3));

Related

Cassandra Statement set KeySpace

Using Cassandra 2.2.8 with 3.0 Connector.
I am trying to create a Statement with QueryBuilder. When I execute Statement it complains no keyspace defined. The only way I know to set keyspace is as below (There is no setKeyspace method in Statement). When I do a getKeySpace - I actually get null
Statement s = QueryBuilder.select().all()
.from("test.tests")
System.out.println("getKeyspace:"+ s.getKeyspace()); >> null
Am I doing something wrong, Is there any other (more reliable) way to setKeyspace?
Thanks
from(String) expects a table name. While what you are doing is technically valid and cassandra will interpret it correctly, the driver is not able to derive the keyspace name in this way.
Instead you could use from(String, String) which takes the first parameter as the keyspace.
Statement s = QueryBuilder.select().all()
.from("test", "tests");
System.out.println("getKeyspace:" + s.getKeyspace()); // >> test

Cassandra Prepared Statement - Binding Parameters Twice

I have a cql query I want to preform. The cql string looks like this:
SELECT * FROM :columnFamilyName WHERE <some_column_name> = :name AND <some_id> = :id;
My application has two layers of abstraction above the datastax driver. In one layer I want to bind the first two parameters and in another layer I'd like to bind the last parameter.
The problem is, if I bind the first two parameters, I get a BoundStatement to which I cannot bind another parameter. Am I missing something? Can it be done?
We're using datastax driver version 2.0.3.
Thanks,
Anatoly.
You should be able to bind any number of parameters to your BoundStatement using boundStatement.setXXXX(index,value) as follows :
BoundStatement statement = new BoundStatement(query);
statement.setString(0, "value");
statement.setInt(1, 1);
statement.setDate(2, new Date());
ResultSet results = session.execute(statement);
The problem though is that you're trying to use a dynamic column family whose value changes with the value you want to bind.
As far as I know, this is not allowed so you should instead prepare one statement per table and then use the right bound statement.

Paging through Cassandra using QueryBuilder

The DataStax documentation says that to page through all data, the following CQL query is useful:
SELECT * FROM test WHERE token(k) > token(42);
Is it possible to build this query using the QueryBuilder? It provides a token method, but that seems to work only on column names, not on values.
Ideally, the value (in the example: 42) is of type Object, just like in the eq/gte/lte functions.
Try using automatic paging with the .fetchSize method. It uses token under the hood:
Automatic paging is introduced Cassandra 2.0. Automatic paging allows the developer to iterate on an entire ResultSet without having to care about its size: some extra rows are fetched as the client code iterate over the results while the old ones are dropped. The amount of rows that must be retrieved can be parameterized at query time. In the Java Driver this will looks like:
Statement stmt = new SimpleStatement("SELECT * FROM images");
stmt.setFetchSize(100);
ResultSet rs = session.execute(stmt);
Source: http://www.datastax.com/dev/blog/client-side-improvements-in-cassandra-2-0
QueryBuilder.fcall("token", value) ;
can solve the problem!

How to check if a Cassandra table exists

Is there an easy way to check if table (column family) is defined in Cassandra using CQL (or API perhaps, using com.datastax.driver)?
Right now I am leaning towards executing SELECT 1 FROM table and checking for exception but maybe there is a better way?
As of 1.1 you should be able to query the system keyspace, schema_columnfamilies column family. If you know which keyspace you want to check, this CQL should list all column families in a keyspace:
SELECT columnfamily_name
FROM schema_columnfamilies WHERE keyspace_name='myKeyspaceName';
The report describing this functionality is here: https://issues.apache.org/jira/browse/CASSANDRA-2477
Although, they do note that some of the system column names have changed between 1.1 and 1.2. So you might have to mess around with it a little to get your desired results.
Edit 20160523 - Cassandra 3.x Update:
Note that for Cassandra 3.0 and up, you'll need to make a few adjustments to the above query:
SELECT table_name
FROM system_schema.tables WHERE keyspace_name='myKeyspaceName';
The Java driver (since you mentioned it in your question) also maintains a local representation of the schema.
Driver 3.x and below:
KeyspaceMetadata ks = cluster.getMetadata().getKeyspace("myKeyspace");
TableMetadata table = ks.getTable("myTable");
boolean tableExists = (table != null);
Driver 4.x and above:
Metadata metadata = session.getMetadata();
boolean tableExists =
metadata.getKeyspace("myKeyspace")
.flatMap(ks -> ks.getTable("myTable"))
.isPresent();
I just needed to manually check for the existence of a table using cqlsh.
Possibly useful general info.
describe keyspace_name.table_name
If it doesn't exist you'll get 'table_name' not found in keyspace 'keyspace'
If it does exist you'll get a description of the table.
For the .NET driver CassandraCSharpDriver version 3.17.1 the following code creates a table if it doesn't exist yet:
var ks = _cassandraSession.Cluster.Metadata.GetKeyspace(keyspaceName);
var tableNames = ks.GetTablesNames();
if(!tableNames.Contains(tableName.ToLowerInvariant()))
{
var stmt = new SimpleStatement($"CREATE TABLE {tableName} (id text PRIMARY KEY, name text, price decimal, volume int, time timestamp)");
_cassandraSession.Execute(stmt);
}
You will need to adapt the list of table columns to your needs. This can also be awaited by using await _cassandraSession.ExecuteAsync(stmt).ConfigureAwait(false) in an async method.
Also, I want to mention that I'm using Cassandra version 4.0.1.

cassandra cql query substitution

Explanation with an example:
import cql
cql connect to CF/Keyspace
last_key = XYZ (say it's getting fetched from else where)
cursor.execute(select * from domain_dimension where key=:key", key="last_key")
The CQL documentation says it can be done, but on console it says execute() got unexpected keyword argument.
Does Cassandra CQL really support query substitution?
It looks like you need to pass the substitutions in a dict as a single arg, not as keyword args.
cursor.execute("select * from domain_dimension where key=:key", {'key': last_key})
That is how it specified in the example on the project homepage: http://code.google.com/a/apache-extras.org/p/cassandra-dbapi2/

Resources