Reputation: 91
everybody,
I have a problem inserting data into a tuple-valued field on a Cassandra table through the python-driver
provided by DataStax.
Either I don't get how to properly pass the tuple argument to the Session.execute
command or the driver is transforming the tuple, internally, in the wrong way when dispatching it to Cassandra - because the same insertion works fine when performed in a cqlsh
session.
An equivalent insertion involving not a tuple, rather a list, works fine both in-code and in cqlsh
.
I am using Python 2.7.10 and cassandra-driver 3.7.1. The error which gets raised in the Python execution is InvalidRequest: Error from server: code=2200 [Invalid query] message="Invalid list literal for tuplefield of type frozen<tuple<int, int, int>>"
.
I paste below a minimal working code that reproduces the issue I am seeing. Could someone help me figure out whether am I doing something wrong?
(Note: I have tried already to pass an ordinary List to Session.execute
in place of the tuple argument, with no luck either.)
Thank you very much.
'''
Run with:
python 2.7.10
cassandra-driver==3.7.1 installed
'''
from cassandra.cluster import Cluster
if __name__=='__main__':
serverAddress='SERVER_ADDRESS'
keyspacename='tupletests'
tablecreation='''create table tabletest (
rowid int,
tuplefield tuple < int, int, int >,
listfield list < int >,
primary key (rowid)
);'''
# connect and create keyspace
clu=Cluster([serverAddress])
session=clu.connect()
session.execute("create keyspace %s with replication = \
{'class': 'SimpleStrategy', 'replication_factor': 1};" % keyspacename)
# use keyspace; create a sample table
session.set_keyspace(keyspacename)
session.execute(tablecreation)
# insert a row with rowid,listfield
session.execute('insert into tabletest (rowid, listfield) values (%s,%s)', \
[999, [10,11,12]])
# succeeds
# insert a row with rowid,tuplefield
session.execute('insert into tabletest (rowid, tuplefield) values (%s,%s)', \
[111, tuple([6,5,4])])
# raises: *** InvalidRequest: Error from server: code=2200 [Invalid query]
# message="Invalid list literal for tuplefield of type frozen<tuple<int, int, int>>"
# Compare with analogous statements in cqlsh, which *both* succeed:
# List: insert into tabletest (rowid, listfield) values (999, [21,22,23]);
# Tuple: insert into tabletest (rowid, tuplefield) values (765, (121,122,123));
# delete test keyspace
session.execute("drop keyspace %s;" % keyspacename)
print "Test Finished."
Upvotes: 4
Views: 1239
Reputation: 91
Ok, I just solved the issue. Posting solution here for everybody. In order to let the driver know how the tuple should be formatted when passing it to Cassandra, if insisting on using a non-prepared statement for the insert, one must specify the encoder to use when parsing tuples before invoking the insert:
session.encoder.mapping[tuple] = session.encoder.cql_encode_tuple
After this statement, tuples appearing in Session.execute
insert statements are automatically cast in the right way for Cassandra, which does not complain anymore.
(as far as I understand, it is even better to resort to a Prepared statement, which contains enough information to make it superfluous to specify the encoder separately).
Upvotes: 5