How do we pass a number to the mintimeuuid() cql function

I am testing out migrating some code from go to rust. It’s been mostly productive and painless, I haven’t become stuck at any point except for this one. I was wondering if someone could point me in the right direction.

We are selecting for a subset of records in certain timeblock partitions using the mintimeuuid, like this:

cqlsh:tt> select recorded, level, event from system_log where timeblock in (19744, 19745) and recorded < mintimeuuid(5000000000000);

 recorded                             | level | event
--------------------------------------+-------+--------
 07b7f471-ba45-11ee-af7b-6b8953004c3e |     4 | loaded
 bf179401-ba44-11ee-af7b-6b8953004c3e |     4 | loaded
 a6dabe81-ba44-11ee-af7b-6b8953004c3e |     4 | loaded

However, when we try to pass an i64 into mintimeuuid() in the same way we can in clash (and in gocql), we get an error, and I can’t work out the appropriate solution, how do we do this with the ScyllaDB driver?

Here is the error:

failed: BadQuery(SerializationError(SerializationError(BuiltinSerializationError { rust_name: “(i64, i64, i64)”, kind: ColumnSerializationFailed { name: “arg0(system.mintimeuuid)”, err: SerializationError(BuiltinTypeCheckError { rust_name: “i64”, got: Timestamp, kind: MismatchedType { expected: [BigInt] } }) } })))

Here is the code:

    match c.session.query(format!("select recorded, level, ip, person, event, fields
from system_log
where timeblock in (?, ?) and recorded < mintimeuuid(?)
order by recorded desc
limit {}", limit), (now, previous, before)).await
    {
        Ok(q) => {
            let mut items = Vec::new();
            if let Some(rows) = q.rows {
                for row in rows
                    .into_typed::<(Uuid, i8, String, String, String, Vec<LogField>)>()
                {
                    match row {
                        Ok(r) => {
                            println!("log: {}, {}, {}, {:?}", r.0, r.1, r.2, r.3);
                            items.push(Log {
                                recorded: r.0,
                                level: i8_to_level(r.1),
                                ip: r.2,
                                person: r.3,
                                event: r.4,
                                fields: r.5,
                            });
                        }
                        Err(e) => {
                            println!("failed: {:?}", e);
                            return Err(DatabaseFailure);
                        }
                    }
                }
            }
            return Ok(items);
        }
        Err(e) => {
            println!("failed: {:?}", e);
            return Err(errors::Error::DatabaseFailure);
        }
    };
}

I am testing out different ways to build a query that might hint that an i64 parameter is expected.

cqlsh:tt> select recorded, level, event from system_log where timeblock in (19744, 19745) and recorded < mintimeuuid(totimestamp(5000000000000));
cqlsh:tt> select recorded, level, event from system_log where timeblock in (19744, 19745) and recorded < mintimeuuid(totimestamp(5000000000000));
NoHostAvailable: ('Unable to complete the operation against any hosts', {<Host: 172.17.0.2:9042 datacenter1>: <Error from server: code=0000 [Server error] message="441649527166861: timestamp is out of range. Must be in milliseconds since epoch">})

Interestingly, this query (below) seems to make my docker instance restart, which seems odd. Although I might be on a slightly old version (Scylla version 5.4.0~dev-0.20230801.37b548f46365)

cqlsh:tt> select recorded, level, event from system_log where timeblock in (19744, 19745) and recorded < mintimeuuid(totimestamp(50000000000));  
NoHostAvailable: ('Unable to complete the operation against any hosts', {<Host: 172.17.0.2:9042 datacenter1>: ConnectionShutdown('Connection to 172.17.0.2:19042 was closed')})
cqlsh:tt>

After updating to the latest 5.4.1, this cal query doesn’t crash ScyllaDB, but it still fails:

failed: BadQuery(SerializationError(SerializationError(BuiltinSerializationError { rust_name: "(i64, i64, i64)", kind: ColumnSerializationFailed { name: "arg0(system.mintimeuuid)", err: SerializationError(BuiltinTypeCheckError { rust_name: "i64", got: Timestamp, kind: MismatchedType { expected: [BigInt] } }) } })))

Wait, nope, I can still crash the ScyllaDB:lastest (refreshed a few days ago) by simply typing this query inside the docker terminal:

And for completeness, it’s still possible to do this query inside the docker terminal but not inside the rust driver. The rust driver seems not able to pass a bigint through to the scylladb instance:

For now the only workaround I can find is to pass the i32/int values inside the query string rather than as a query parameter:

@Jay please open an issue in the ScyllaDB bug tracker, with the reproducer for the crash. We will want to look into this and fix it.

Regarding Rust driver aspect:
The error would be more readable if you used normal print, not debug print.
The error says that you passed an i64 Rust values to a place that serializes to Timestamp CQL type.
This is not possible, you must pass one of supported types:

  • scylla::frame::value::CqlTimestamp which is a wrapper over i64 - so you can just use CqlTimestamp(before) instead of before.
  • chrono::DateTime<Utc> (serialization support requires enabling chrono feature in the driver)
  • time::OffsetDateTime (serialization support requires enabling time feature in the driver)

You can find this information in documentation: