Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

types: Implement API functions for duration type #135

Merged
merged 9 commits into from
Aug 4, 2024
Merged
24 changes: 4 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,11 @@ The driver inherits almost all the features of C/C++ and Rust drivers, such as:
</tr>
<tr>
<td>cass_statement_bind_custom[by_name]</td>
<td rowspan="3">Binding is not implemented for custom types in the Rust driver. <br> Binding Decimal and Duration types requires encoding raw bytes into BigDecimal and CqlDuration types in the Rust driver. <br> <b>Note</b>: The driver does not validate the types of the values passed to queries.</td>
<td rowspan="2">Binding is not implemented for custom types in the Rust driver. <br> Binding Decimal type requires encoding raw bytes into BigDecimal type in the Rust driver. <br> <b>Note</b>: The driver does not validate the types of the values passed to queries.</td>
muzarski marked this conversation as resolved.
Show resolved Hide resolved
</tr>
<tr>
<td>cass_statement_bind_decimal[by_name]</td>
</tr>
<tr>
<td>cass_statement_bind_duration[by_name]</td>
</tr>
<tr>
<td colspan=2 align="center" style="font-weight:bold">Future</td>
</tr>
Expand All @@ -190,40 +187,27 @@ The driver inherits almost all the features of C/C++ and Rust drivers, such as:
</tr>
<tr>
<td>cass_collection_append_custom[_n]</td>
<td rowspan="3">Unimplemented because of the same reasons as binding for statements.<br> <b>Note</b>: The driver does not check whether the type of the appended value is compatible with the type of the collection items.</td>
<td rowspan="2">Unimplemented because of the same reasons as binding for statements.<br> <b>Note</b>: The driver does not check whether the type of the appended value is compatible with the type of the collection items.</td>
muzarski marked this conversation as resolved.
Show resolved Hide resolved
</tr>
<tr>
<td>cass_collection_append_decimal</td>
</tr>
<tr>
<td>cass_collection_append_duration</td>
</tr>
<tr>
<td colspan=2 align="center" style="font-weight:bold">User Defined Type</td>
</tr>
<tr>
<td>cass_user_type_set_custom[by_name]</td>
<td rowspan="3">Unimplemented because of the same reasons as binding for statements.<br> <b>Note</b>: The driver does not check whether the type of the value being set for a field of the UDT is compatible with the field's actual type.</td>
<td rowspan="2">Unimplemented because of the same reasons as binding for statements.<br> <b>Note</b>: The driver does not check whether the type of the value being set for a field of the UDT is compatible with the field's actual type.</td>
</tr>
<tr>
<td>cass_user_type_set_decimal[by_name]</td>
</tr>
<tr>
<td>cass_user_type_set_duration[by_name]</td>
</tr>
<tr>
<td colspan=2 align="center" style="font-weight:bold">Value</td>
</tr>
<tr>
<td>cass_value_is_duration</td>
<td>Unimplemented</td>
</tr>
<tr>
<td>cass_value_get_decimal</td>
<td rowspan="2">Getting raw bytes of Decimal and Duration values requires lazy deserialization feature in the Rust driver.</td>
</tr>
<tr>
<td>cass_value_get_duration</td>
<td>Getting raw bytes of Decimal values requires lazy deserialization feature in the Rust driver.</td>
</tr>
<tr>
<td>cass_value_get_bytes</td>
Expand Down
18 changes: 16 additions & 2 deletions scylla-rust-wrapper/src/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,8 @@ macro_rules! make_appender {
}

// TODO: Types for which binding is not implemented yet:
// custom - Not implemented in Rust driver?
// custom - Not implemented in Rust driver
// decimal
// duration - DURATION not implemented in Rust Driver

macro_rules! invoke_binder_maker_macro_with_type {
(null, $macro_name:ident, $this:ty, $consume_v:expr, $fn:ident) => {
Expand Down Expand Up @@ -277,6 +276,21 @@ macro_rules! invoke_binder_maker_macro_with_type {
[v @ crate::inet::CassInet]
);
};
(duration, $macro_name:ident, $this:ty, $consume_v:expr, $fn:ident) => {
$macro_name!(
$this,
$consume_v,
$fn,
|m, d, n| {
Ok(Some(Duration(scylla::frame::value::CqlDuration {
months: m,
days: d,
nanoseconds: n
})))
},
[m @ cass_int32_t, d @ cass_int32_t, n @ cass_int64_t]
);
};
(collection, $macro_name:ident, $this:ty, $consume_v:expr, $fn:ident) => {
$macro_name!(
$this,
Expand Down
1 change: 1 addition & 0 deletions scylla-rust-wrapper/src/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ make_binders!(string_n, cass_collection_append_string_n);
make_binders!(bytes, cass_collection_append_bytes);
make_binders!(uuid, cass_collection_append_uuid);
make_binders!(inet, cass_collection_append_inet);
make_binders!(duration, cass_collection_append_duration);
make_binders!(collection, cass_collection_append_collection);
make_binders!(tuple, cass_collection_append_tuple);
make_binders!(user_type, cass_collection_append_user_type);
92 changes: 56 additions & 36 deletions scylla-rust-wrapper/src/query_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -915,12 +915,21 @@ pub unsafe extern "C" fn cass_value_data_type(value: *const CassValue) -> *const
Arc::as_ptr(&value_from_raw.value_type)
}

macro_rules! val_ptr_to_ref_ensure_non_null {
($ptr:ident) => {{
if $ptr.is_null() {
return CassError::CASS_ERROR_LIB_NULL_VALUE;
}
ptr_to_ref($ptr)
}};
}

#[no_mangle]
pub unsafe extern "C" fn cass_value_get_float(
value: *const CassValue,
output: *mut cass_float_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::Float(f))) => std::ptr::write(output, f),
Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
Expand All @@ -935,7 +944,7 @@ pub unsafe extern "C" fn cass_value_get_double(
value: *const CassValue,
output: *mut cass_double_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::Double(d))) => std::ptr::write(output, d),
Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
Expand All @@ -950,7 +959,7 @@ pub unsafe extern "C" fn cass_value_get_bool(
value: *const CassValue,
output: *mut cass_bool_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::Boolean(b))) => {
std::ptr::write(output, b as cass_bool_t)
Expand All @@ -967,7 +976,7 @@ pub unsafe extern "C" fn cass_value_get_int8(
value: *const CassValue,
output: *mut cass_int8_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::TinyInt(i))) => std::ptr::write(output, i),
Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
Expand All @@ -982,7 +991,7 @@ pub unsafe extern "C" fn cass_value_get_int16(
value: *const CassValue,
output: *mut cass_int16_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::SmallInt(i))) => std::ptr::write(output, i),
Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
Expand All @@ -997,7 +1006,7 @@ pub unsafe extern "C" fn cass_value_get_uint32(
value: *const CassValue,
output: *mut cass_uint32_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::Date(u))) => std::ptr::write(output, u.0), // FIXME: hack
Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
Expand All @@ -1012,7 +1021,7 @@ pub unsafe extern "C" fn cass_value_get_int32(
value: *const CassValue,
output: *mut cass_int32_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::Int(i))) => std::ptr::write(output, i),
Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
Expand All @@ -1027,7 +1036,7 @@ pub unsafe extern "C" fn cass_value_get_int64(
value: *const CassValue,
output: *mut cass_int64_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::BigInt(i))) => std::ptr::write(output, i),
Some(Value::RegularValue(CqlValue::Counter(i))) => {
Expand All @@ -1049,7 +1058,7 @@ pub unsafe extern "C" fn cass_value_get_uuid(
value: *const CassValue,
output: *mut CassUuid,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::Uuid(uuid))) => std::ptr::write(output, uuid.into()),
Some(Value::RegularValue(CqlValue::Timeuuid(uuid))) => {
Expand All @@ -1067,7 +1076,7 @@ pub unsafe extern "C" fn cass_value_get_inet(
value: *const CassValue,
output: *mut CassInet,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match val.value {
Some(Value::RegularValue(CqlValue::Inet(inet))) => std::ptr::write(output, inet.into()),
Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
Expand All @@ -1083,7 +1092,7 @@ pub unsafe extern "C" fn cass_value_get_string(
output: *mut *const c_char,
output_size: *mut size_t,
) -> CassError {
let val: &CassValue = ptr_to_ref(value);
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);
match &val.value {
// It seems that cpp driver doesn't check the type - you can call _get_string
// on any type and get internal represenation. I don't see how to do it easily in
Expand All @@ -1102,17 +1111,35 @@ pub unsafe extern "C" fn cass_value_get_string(
CassError::CASS_OK
}

#[no_mangle]
pub unsafe extern "C" fn cass_value_get_duration(
value: *const CassValue,
months: *mut cass_int32_t,
days: *mut cass_int32_t,
nanos: *mut cass_int64_t,
) -> CassError {
let val: &CassValue = val_ptr_to_ref_ensure_non_null!(value);

match &val.value {
Some(Value::RegularValue(CqlValue::Duration(duration))) => {
std::ptr::write(months, duration.months);
std::ptr::write(days, duration.days);
std::ptr::write(nanos, duration.nanoseconds);
}
Some(_) => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
None => return CassError::CASS_ERROR_LIB_NULL_VALUE,
}

CassError::CASS_OK
}

#[no_mangle]
pub unsafe extern "C" fn cass_value_get_bytes(
value: *const CassValue,
output: *mut *const cass_byte_t,
output_size: *mut size_t,
) -> CassError {
if value.is_null() {
return CassError::CASS_ERROR_LIB_NULL_VALUE;
}

let value_from_raw: &CassValue = ptr_to_ref(value);
let value_from_raw: &CassValue = val_ptr_to_ref_ensure_non_null!(value);

// FIXME: This should be implemented for all CQL types
// Note: currently rust driver does not allow to get raw bytes of the CQL value.
Expand All @@ -1138,12 +1165,19 @@ pub unsafe extern "C" fn cass_value_is_null(value: *const CassValue) -> cass_boo
pub unsafe extern "C" fn cass_value_is_collection(value: *const CassValue) -> cass_bool_t {
let val = ptr_to_ref(value);

match val.value {
Some(Value::CollectionValue(Collection::List(_))) => true as cass_bool_t,
Some(Value::CollectionValue(Collection::Set(_))) => true as cass_bool_t,
Some(Value::CollectionValue(Collection::Map(_))) => true as cass_bool_t,
_ => false as cass_bool_t,
}
matches!(
val.value_type.get_value_type(),
CassValueType::CASS_VALUE_TYPE_LIST
| CassValueType::CASS_VALUE_TYPE_SET
| CassValueType::CASS_VALUE_TYPE_MAP
) as cass_bool_t
}

#[no_mangle]
pub unsafe extern "C" fn cass_value_is_duration(value: *const CassValue) -> cass_bool_t {
let val = ptr_to_ref(value);

(val.value_type.get_value_type() == CassValueType::CASS_VALUE_TYPE_DURATION) as cass_bool_t
}

#[no_mangle]
Expand Down Expand Up @@ -1505,26 +1539,12 @@ pub unsafe extern "C" fn cass_value_get_decimal(
scale: *mut cass_int32_t,
) -> CassError {
}
#[no_mangle]
pub unsafe extern "C" fn cass_value_get_duration(
value: *const CassValue,
months: *mut cass_int32_t,
days: *mut cass_int32_t,
nanos: *mut cass_int64_t,
) -> CassError {
}
extern "C" {
pub fn cass_value_data_type(value: *const CassValue) -> *const CassDataType;
}
extern "C" {
pub fn cass_value_type(value: *const CassValue) -> CassValueType;
}
extern "C" {
pub fn cass_value_is_collection(value: *const CassValue) -> cass_bool_t;
}
extern "C" {
pub fn cass_value_is_duration(value: *const CassValue) -> cass_bool_t;
}
extern "C" {
pub fn cass_value_item_count(collection: *const CassValue) -> size_t;
}
Expand Down
6 changes: 6 additions & 0 deletions scylla-rust-wrapper/src/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,12 @@ make_binders!(
cass_statement_bind_inet_by_name,
cass_statement_bind_inet_by_name_n
);
make_binders!(
duration,
cass_statement_bind_duration,
cass_statement_bind_duration_by_name,
cass_statement_bind_duration_by_name_n
);
make_binders!(
collection,
cass_statement_bind_collection,
Expand Down
1 change: 1 addition & 0 deletions scylla-rust-wrapper/src/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ make_binders!(string_n, cass_tuple_set_string_n);
make_binders!(bytes, cass_tuple_set_bytes);
make_binders!(uuid, cass_tuple_set_uuid);
make_binders!(inet, cass_tuple_set_inet);
make_binders!(duration, cass_tuple_set_duration);
make_binders!(collection, cass_tuple_set_collection);
make_binders!(tuple, cass_tuple_set_tuple);
make_binders!(user_type, cass_tuple_set_user_type);
6 changes: 6 additions & 0 deletions scylla-rust-wrapper/src/user_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ make_binders!(
cass_user_type_set_inet_by_name,
cass_user_type_set_inet_by_name_n
);
make_binders!(
duration,
cass_user_type_set_duration,
cass_user_type_set_duration_by_name,
cass_user_type_set_duration_by_name_n
);
make_binders!(
collection,
cass_user_type_set_collection,
Expand Down
9 changes: 8 additions & 1 deletion scylla-rust-wrapper/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::{convert::TryInto, net::IpAddr};

use scylla::{
frame::{response::result::ColumnType, value::CqlDate},
frame::{
response::result::ColumnType,
value::{CqlDate, CqlDuration},
},
serialize::{
value::{
BuiltinSerializationErrorKind, MapSerializationErrorKind, SerializeCql,
Expand Down Expand Up @@ -40,6 +43,7 @@ pub enum CassCqlValue {
Uuid(Uuid),
Date(CqlDate),
Inet(IpAddr),
Duration(CqlDuration),
Tuple(Vec<Option<CassCqlValue>>),
List(Vec<CassCqlValue>),
Map(Vec<(CassCqlValue, CassCqlValue)>),
Expand Down Expand Up @@ -117,6 +121,9 @@ impl CassCqlValue {
CassCqlValue::Inet(v) => {
<IpAddr as SerializeCql>::serialize(v, &ColumnType::Inet, writer)
}
CassCqlValue::Duration(v) => {
<CqlDuration as SerializeCql>::serialize(v, &ColumnType::Duration, writer)
}
CassCqlValue::Tuple(fields) => serialize_tuple_like(fields.iter(), writer),
CassCqlValue::List(l) => serialize_sequence(l.len(), l.iter(), writer),
CassCqlValue::Map(m) => {
Expand Down
Loading
Loading