datastax/cpp-driver — pull request #17 by jnidzwetzki (2014-03-02 21:52:00+00:00)
Title: Ensure set_prepare_statement is called once only per query_id

The function set_prepare_statement(...) is called with the same query_id and different values for query_text. As a result, the mapping between query_id and query_text will become inconsistent and setup_prepared_statements(...) is preparing wrong (or empty) statements on a new connection.

You can reproduce this issue by executing the prepared statement from the demo (demo/cql_query) repeated in a multi-node environment. set_prepare_statement(...) will be called with the same query_id and these values:

-+-
Query text is: SELECT * FROM schema_keyspaces WHERE keyspace_name=?
Query text is:
Query text is: USE system;
Query text is: SELECT * from schema_keyspaces;
-+-

The output of the demo is:

-+-
[...]
LOG: sending message: 0x01007e0700000013 {version: 0x01, flags: 0x00, stream: 0x7e, opcode: 0x07, length: 19} USE "system"; CQL_CONSISTENCY_ONE
LOG: wrote to socket 27 bytes
LOG: received header for message 0x81007e080000000c {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 12}
LOG: received body for message 0x81007e080000000c {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 12}
LOG: received result message 0x81007e080000000c {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 12}
LOG: sending message: 0x01007e0900000039 {version: 0x01, flags: 0x00, stream: 0x7e, opcode: 0x09, length: 57} SELECT * FROM schema_keyspaces WHERE keyspace_name=?;
LOG: wrote to socket 65 bytes
LOG: received header for message 0x81007e0800000049 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 73}
LOG: received body for message 0x81007e0800000049 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 73}
LOG: received result message 0x81007e0800000049 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 73}
LOG: sending message: 0x01007e0a00000025 {version: 0x01, flags: 0x00, stream: 0x7e, opcode: 0x0a, length: 37} EXECUTE 0x9523a7ae8218a43a294345fa7aebb109 CQL_CONSISTENCY_ONE
LOG: wrote to socket 45 bytes
LOG: received header for message 0x81007e0800000073 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 115}
LOG: received body for message 0x81007e0800000073 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 115}
LOG: received result message 0x81007e0800000073 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x08, length: 115}
execute successful? true

#####################################################
# The mapping between query_id and query_text is now inconsistent
# the driver is trying to prepare the statement "" (empty statement)
# instead of preparing:
# SELECT * FROM schema_keyspaces WHERE keyspace_name=?;
#####################################################
LOG: sending message: 0x01007e0900000004 {version: 0x01, flags: 0x00, stream: 0x7e, opcode: 0x09, length: 4}
LOG: wrote to socket 12 bytes
LOG: received header for message 0x81007e0000000036 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x00, length: 54}
LOG: received body for message 0x81007e0000000036 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x00, length: 54}
execute successful? false
Error is: could not obtain viable client from the pool.
LOG: sending message: 0x01007e0900000004 {version: 0x01, flags: 0x00, stream: 0x7e, opcode: 0x09, length: 4}
LOG: wrote to socket 12 bytes
LOG: received header for message 0x81007e0000000036 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x00, length: 54}
LOG: received body for message 0x81007e0000000036 {version: 0x81, flags: 0x00, stream: 0x7e, opcode: 0x00, length: 54}
execute successful? false
Error is: could not obtain viable client from the pool.
[...]
-+-

I'm not sure if this is a real bugfix or only a workaround for this issue.