Updating a set of udt results with cluster error
krojew opened this issue · comments
If a table contains a set of frozen UDT and we execute update table set column = column + ? where ...
and pass a UDT using query_values, the cluster responds with Server error: CString { string: "java.lang.IllegalArgumentException" }
. Executing the same query using text, results in a success.
The stack trace in Cassandra is:
java.lang.IllegalArgumentException: null
cassandra_1 | at java.nio.Buffer.limit(Buffer.java:275) ~[na:1.8.0_222]
cassandra_1 | at org.apache.cassandra.utils.ByteBufferUtil.readBytes(ByteBufferUtil.java:651) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.serializers.CollectionSerializer.readValue(CollectionSerializer.java:105) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.serializers.SetSerializer.deserializeForNativeProtocol(SetSerializer.java:101) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.Sets$Value.fromSerialized(Sets.java:158) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.Sets$Marker.bind(Sets.java:251) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.Sets$Adder.execute(Sets.java:285) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.statements.UpdateStatement.addUpdateForKey(UpdateStatement.java:94) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.statements.ModificationStatement.addUpdates(ModificationStatement.java:694) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.statements.ModificationStatement.getMutations(ModificationStatement.java:635) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.statements.ModificationStatement.executeWithoutCondition(ModificationStatement.java:437) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.statements.ModificationStatement.execute(ModificationStatement.java:425) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.QueryProcessor.processStatement(QueryProcessor.java:225) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.QueryProcessor.processPrepared(QueryProcessor.java:532) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.cql3.QueryProcessor.processPrepared(QueryProcessor.java:509) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.transport.messages.ExecuteMessage.execute(ExecuteMessage.java:146) ~[apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.transport.Message$Dispatcher.channelRead0(Message.java:566) [apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.transport.Message$Dispatcher.channelRead0(Message.java:410) [apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) [netty-all-4.0.44.Final.jar:4.0.44.Final]
cassandra_1 | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.0.44.Final.jar:4.0.44.Final]
cassandra_1 | at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:35) [netty-all-4.0.44.Final.jar:4.0.44.Final]
cassandra_1 | at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:348) [netty-all-4.0.44.Final.jar:4.0.44.Final]
cassandra_1 | at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_222]
cassandra_1 | at org.apache.cassandra.concurrent.AbstractLocalAwareExecutorService$FutureTask.run(AbstractLocalAwareExecutorService.java:162) [apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at org.apache.cassandra.concurrent.SEPWorker.run(SEPWorker.java:114) [apache-cassandra-3.11.4.jar:3.11.4]
cassandra_1 | at java.lang.Thread.run(Thread.java:748) [na:1.8.0_222]
Hello @krojew
Would you be able to provide a full code snippet including table schemas that may help to reproduce the issue?
Thanks
DB preparation:
CREATE TYPE udt1 (
id uuid,
col1 text,
col2 tinyint,
col3 tinyint
);
CREATE TABLE table1 (
id uuid PRIMARY KEY,
udts set<frozen<udt1>>
);
INSERT INTO table1 (id, udts) VALUES (5bd8877a-e2b2-4d6f-aafd-c3f72a6964cf, {{
id: 08f49fa5-934b-4aff-8a87-f3a3287296ba,
col1: 'text',
col2: 1,
col3: 2
}});
Rust:
use cdrs::authenticators::StaticPasswordAuthenticator;
use cdrs::cluster::session::{new as new_session};
use cdrs::cluster::{ClusterTcpConfig, NodeTcpConfigBuilder};
use cdrs::consistency::Consistency;
use cdrs::frame::traits::IntoBytes;
use cdrs::load_balancing::RoundRobin;
use cdrs::query::*;
use cdrs::query_values;
use cdrs::types::prelude::*;
use cdrs_helpers_derive::*;
use uuid::Uuid;
#[derive(IntoCDRSValue)]
struct Model {
id: Uuid,
col1: String,
col2: i8,
col3: i8,
}
fn main() {
log4rs::init_file("log4rs.yml", Default::default()).expect("Error initializing log4rs");
let node = NodeTcpConfigBuilder::new(
"localhost:9042",
StaticPasswordAuthenticator::new("cassandra", "cassandra")
).build();
let cluster_config = ClusterTcpConfig(vec![node]);
let session = new_session(&cluster_config, RoundRobin::new()).expect("session should be created");
let query = session.prepare("UPDATE bug_284.table1 SET udts = udts + ? WHERE id = ?").unwrap();
let row = Model {
id: Uuid::parse_str("68f49fa5-934b-4aff-8a87-f3a32872a6ba").unwrap(),
col1: "abc".into(),
col2: 1,
col3: 2,
};
let params = QueryParamsBuilder::new().consistency(Consistency::Quorum).values(query_values!(row, Uuid::parse_str("5bd8877a-e2b2-4d6f-aafd-c3f72a6964cf").unwrap()));
session.exec_with_params(&query, params.finalize()).unwrap();
}
Hi @krojew,
Looks like the problem is with values you pass for execution.
The query that was prepared is UPDATE bug_284.table1 SET udts = udts + ? WHERE id = ?
. When we do some_set = some_set + X
, X
is an another set of the values of the same type as some_set
, not a single item. It allows to "push" few values in the same query.
So, what you need to do in order to get your issues fixed is to change
let params = QueryParamsBuilder::new().consistency(Consistency::Quorum).values(query_values!(row, Uuid::parse_str("5bd8877a-e2b2-4d6f-aafd-c3f72a6964cf").unwrap()));
with
let params = QueryParamsBuilder::new().consistency(Consistency::Quorum).values(query_values!(vec![row], Uuid::parse_str("5bd8877a-e2b2-4d6f-aafd-c3f72a6964cf").unwrap()));
In other words, wrap a value/values that should be added by a vec![]
See, for instance #285. It has an 2e2 test that does such push in similar way.
That might be it. It would be good to add such example to the documentation.
I've created an issue to provide examples for set, list and map (#286)