Skip to content

Commit 4d006df

Browse files
authored
Merge pull request #136 from muzarski/cass_result_missing_functions
cass_result: implement missing functions
2 parents 4d056ed + 538ffaf commit 4d006df

File tree

4 files changed

+343
-36
lines changed

4 files changed

+343
-36
lines changed

scylla-rust-wrapper/src/cass_types.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ include!(concat!(env!("OUT_DIR"), "/cppdriver_data_types.rs"));
1515
include!(concat!(env!("OUT_DIR"), "/cppdriver_data_query_error.rs"));
1616
include!(concat!(env!("OUT_DIR"), "/cppdriver_batch_types.rs"));
1717

18-
#[derive(Clone, Debug, PartialEq)]
18+
#[derive(Clone, Debug, PartialEq, Eq)]
1919
pub struct UDTDataType {
2020
// Vec to preserve the order of types
2121
pub field_types: Vec<(String, Arc<CassDataType>)>,
@@ -131,14 +131,14 @@ impl Default for UDTDataType {
131131
}
132132
}
133133

134-
#[derive(Clone, Debug, PartialEq)]
134+
#[derive(Clone, Debug, PartialEq, Eq)]
135135
pub enum MapDataType {
136136
Untyped,
137137
Key(Arc<CassDataType>),
138138
KeyAndValue(Arc<CassDataType>, Arc<CassDataType>),
139139
}
140140

141-
#[derive(Clone, Debug, PartialEq)]
141+
#[derive(Clone, Debug, PartialEq, Eq)]
142142
pub enum CassDataType {
143143
Value(CassValueType),
144144
UDT(UDTDataType),

scylla-rust-wrapper/src/prepared.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ use scylla::prepared_statement::PreparedStatement;
1414
pub struct CassPrepared {
1515
// Data types of columns from PreparedMetadata.
1616
pub variable_col_data_types: Vec<Arc<CassDataType>>,
17+
// Data types of columns from ResultMetadata.
18+
//
19+
// Arc<CassDataType> -> to share each data type with other structs such as `CassValue`
20+
// Arc<Vec<...>> -> to share the whole vector with `CassResultData`.
21+
pub result_col_data_types: Arc<Vec<Arc<CassDataType>>>,
1722
pub statement: PreparedStatement,
1823
}
1924

@@ -25,8 +30,17 @@ impl CassPrepared {
2530
.map(|col_spec| Arc::new(get_column_type(&col_spec.typ)))
2631
.collect();
2732

33+
let result_col_data_types: Arc<Vec<Arc<CassDataType>>> = Arc::new(
34+
statement
35+
.get_result_set_col_specs()
36+
.iter()
37+
.map(|col_spec| Arc::new(get_column_type(&col_spec.typ)))
38+
.collect(),
39+
);
40+
2841
Self {
2942
variable_col_data_types,
43+
result_col_data_types,
3044
statement,
3145
}
3246
}

scylla-rust-wrapper/src/query_result.rs

Lines changed: 263 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::argconv::*;
22
use crate::cass_error::CassError;
3-
use crate::cass_types::{cass_data_type_type, CassDataType, CassValueType, MapDataType};
3+
use crate::cass_types::{
4+
cass_data_type_type, get_column_type, CassDataType, CassValueType, MapDataType,
5+
};
46
use crate::inet::CassInet;
57
use crate::metadata::{
68
CassColumnMeta, CassKeyspaceMeta, CassMaterializedViewMeta, CassSchemaMeta, CassTableMeta,
@@ -22,9 +24,39 @@ pub struct CassResult {
2224
pub struct CassResultData {
2325
pub paging_state_response: PagingStateResponse,
2426
pub col_specs: Vec<ColumnSpec>,
27+
pub col_data_types: Arc<Vec<Arc<CassDataType>>>,
2528
pub tracing_id: Option<Uuid>,
2629
}
2730

31+
impl CassResultData {
32+
pub fn from_result_payload(
33+
paging_state_response: PagingStateResponse,
34+
col_specs: Vec<ColumnSpec>,
35+
maybe_col_data_types: Option<Arc<Vec<Arc<CassDataType>>>>,
36+
tracing_id: Option<Uuid>,
37+
) -> CassResultData {
38+
// `maybe_col_data_types` is:
39+
// - Some(_) for prepared statements executions
40+
// - None for unprepared (simple) queries executions
41+
let col_data_types = maybe_col_data_types.unwrap_or_else(|| {
42+
// This allocation is unfortunately necessary, because of the type of CassResultData::col_data_types.
43+
Arc::new(
44+
col_specs
45+
.iter()
46+
.map(|col_spec| Arc::new(get_column_type(&col_spec.typ)))
47+
.collect(),
48+
)
49+
});
50+
51+
CassResultData {
52+
paging_state_response,
53+
col_specs,
54+
col_data_types,
55+
tracing_id,
56+
}
57+
}
58+
}
59+
2860
/// The lifetime of CassRow is bound to CassResult.
2961
/// It will be freed, when CassResult is freed.(see #[cass_result_free])
3062
pub struct CassRow {
@@ -905,6 +937,36 @@ pub unsafe extern "C" fn cass_result_column_name(
905937
CassError::CASS_OK
906938
}
907939

940+
#[no_mangle]
941+
pub unsafe extern "C" fn cass_result_column_type(
942+
result: *const CassResult,
943+
index: size_t,
944+
) -> CassValueType {
945+
let data_type_ptr = cass_result_column_data_type(result, index);
946+
if data_type_ptr.is_null() {
947+
return CassValueType::CASS_VALUE_TYPE_UNKNOWN;
948+
}
949+
cass_data_type_type(data_type_ptr)
950+
}
951+
952+
#[no_mangle]
953+
pub unsafe extern "C" fn cass_result_column_data_type(
954+
result: *const CassResult,
955+
index: size_t,
956+
) -> *const CassDataType {
957+
let result_from_raw: &CassResult = ptr_to_ref(result);
958+
let index_usize: usize = index
959+
.try_into()
960+
.expect("Provided index is out of bounds. Max possible value is usize::MAX");
961+
962+
result_from_raw
963+
.metadata
964+
.col_data_types
965+
.get(index_usize)
966+
.map(Arc::as_ptr)
967+
.unwrap_or(std::ptr::null())
968+
}
969+
908970
#[no_mangle]
909971
pub unsafe extern "C" fn cass_value_type(value: *const CassValue) -> CassValueType {
910972
let value_from_raw = ptr_to_ref(value);
@@ -1283,11 +1345,12 @@ pub unsafe extern "C" fn cass_result_column_count(result_raw: *const CassResult)
12831345
pub unsafe extern "C" fn cass_result_first_row(result_raw: *const CassResult) -> *const CassRow {
12841346
let result = ptr_to_ref(result_raw);
12851347

1286-
if result.rows.is_some() || result.rows.as_ref().unwrap().is_empty() {
1287-
return result.rows.as_ref().unwrap().first().unwrap();
1288-
}
1289-
1290-
std::ptr::null()
1348+
result
1349+
.rows
1350+
.as_ref()
1351+
.and_then(|rows| rows.first())
1352+
.map(|row| row as *const CassRow)
1353+
.unwrap_or(std::ptr::null())
12911354
}
12921355

12931356
#[no_mangle]
@@ -1322,6 +1385,200 @@ pub unsafe extern "C" fn cass_result_paging_state_token(
13221385
CassError::CASS_OK
13231386
}
13241387

1388+
#[cfg(test)]
1389+
mod tests {
1390+
use std::{ffi::c_char, ptr::addr_of_mut, sync::Arc};
1391+
1392+
use scylla::{
1393+
frame::response::result::{ColumnSpec, ColumnType, CqlValue, Row, TableSpec},
1394+
transport::PagingStateResponse,
1395+
};
1396+
1397+
use crate::{
1398+
cass_error::CassError,
1399+
cass_types::{CassDataType, CassValueType},
1400+
query_result::{
1401+
cass_result_column_data_type, cass_result_column_name, cass_result_first_row,
1402+
ptr_to_cstr_n, ptr_to_ref, size_t,
1403+
},
1404+
session::create_cass_rows_from_rows,
1405+
};
1406+
1407+
use super::{cass_result_column_count, cass_result_column_type, CassResult, CassResultData};
1408+
1409+
fn col_spec(name: &str, typ: ColumnType) -> ColumnSpec {
1410+
ColumnSpec {
1411+
table_spec: TableSpec::borrowed("ks", "tbl"),
1412+
name: name.to_owned(),
1413+
typ,
1414+
}
1415+
}
1416+
1417+
const FIRST_COLUMN_NAME: &str = "bigint_col";
1418+
const SECOND_COLUMN_NAME: &str = "varint_col";
1419+
const THIRD_COLUMN_NAME: &str = "list_double_col";
1420+
fn create_cass_rows_result() -> CassResult {
1421+
let metadata = Arc::new(CassResultData::from_result_payload(
1422+
PagingStateResponse::NoMorePages,
1423+
vec![
1424+
col_spec(FIRST_COLUMN_NAME, ColumnType::BigInt),
1425+
col_spec(SECOND_COLUMN_NAME, ColumnType::Varint),
1426+
col_spec(
1427+
THIRD_COLUMN_NAME,
1428+
ColumnType::List(Box::new(ColumnType::Double)),
1429+
),
1430+
],
1431+
None,
1432+
None,
1433+
));
1434+
1435+
let rows = create_cass_rows_from_rows(
1436+
vec![Row {
1437+
columns: vec![
1438+
Some(CqlValue::BigInt(42)),
1439+
None,
1440+
Some(CqlValue::List(vec![
1441+
CqlValue::Float(0.5),
1442+
CqlValue::Float(42.42),
1443+
CqlValue::Float(9999.9999),
1444+
])),
1445+
],
1446+
}],
1447+
&metadata,
1448+
);
1449+
1450+
CassResult {
1451+
rows: Some(rows),
1452+
metadata,
1453+
}
1454+
}
1455+
1456+
unsafe fn cass_result_column_name_rust_str(
1457+
result_ptr: *const CassResult,
1458+
column_index: u64,
1459+
) -> Option<&'static str> {
1460+
let mut name_ptr: *const c_char = std::ptr::null();
1461+
let mut name_length: size_t = 0;
1462+
let cass_err = cass_result_column_name(
1463+
result_ptr,
1464+
column_index,
1465+
addr_of_mut!(name_ptr),
1466+
addr_of_mut!(name_length),
1467+
);
1468+
assert_eq!(CassError::CASS_OK, cass_err);
1469+
ptr_to_cstr_n(name_ptr, name_length)
1470+
}
1471+
1472+
#[test]
1473+
fn rows_cass_result_api_test() {
1474+
let result = create_cass_rows_result();
1475+
1476+
unsafe {
1477+
let result_ptr = std::ptr::addr_of!(result);
1478+
1479+
// cass_result_column_count test
1480+
{
1481+
let column_count = cass_result_column_count(result_ptr);
1482+
assert_eq!(3, column_count);
1483+
}
1484+
1485+
// cass_result_column_name test
1486+
{
1487+
let first_column_name = cass_result_column_name_rust_str(result_ptr, 0).unwrap();
1488+
assert_eq!(FIRST_COLUMN_NAME, first_column_name);
1489+
let second_column_name = cass_result_column_name_rust_str(result_ptr, 1).unwrap();
1490+
assert_eq!(SECOND_COLUMN_NAME, second_column_name);
1491+
let third_column_name = cass_result_column_name_rust_str(result_ptr, 2).unwrap();
1492+
assert_eq!(THIRD_COLUMN_NAME, third_column_name);
1493+
}
1494+
1495+
// cass_result_column_type test
1496+
{
1497+
let first_col_type = cass_result_column_type(result_ptr, 0);
1498+
assert_eq!(CassValueType::CASS_VALUE_TYPE_BIGINT, first_col_type);
1499+
let second_col_type = cass_result_column_type(result_ptr, 1);
1500+
assert_eq!(CassValueType::CASS_VALUE_TYPE_VARINT, second_col_type);
1501+
let third_col_type = cass_result_column_type(result_ptr, 2);
1502+
assert_eq!(CassValueType::CASS_VALUE_TYPE_LIST, third_col_type);
1503+
let out_of_bound_col_type = cass_result_column_type(result_ptr, 555);
1504+
assert_eq!(
1505+
CassValueType::CASS_VALUE_TYPE_UNKNOWN,
1506+
out_of_bound_col_type
1507+
);
1508+
}
1509+
1510+
// cass_result_column_data_type test
1511+
{
1512+
let first_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 0));
1513+
assert_eq!(
1514+
&CassDataType::Value(CassValueType::CASS_VALUE_TYPE_BIGINT),
1515+
first_col_data_type
1516+
);
1517+
let second_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 1));
1518+
assert_eq!(
1519+
&CassDataType::Value(CassValueType::CASS_VALUE_TYPE_VARINT),
1520+
second_col_data_type
1521+
);
1522+
let third_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 2));
1523+
assert_eq!(
1524+
&CassDataType::List {
1525+
typ: Some(Arc::new(CassDataType::Value(
1526+
CassValueType::CASS_VALUE_TYPE_DOUBLE
1527+
))),
1528+
frozen: false
1529+
},
1530+
third_col_data_type
1531+
);
1532+
let out_of_bound_col_data_type = cass_result_column_data_type(result_ptr, 555);
1533+
assert!(out_of_bound_col_data_type.is_null());
1534+
}
1535+
}
1536+
}
1537+
1538+
fn create_non_rows_cass_result() -> CassResult {
1539+
let metadata = Arc::new(CassResultData::from_result_payload(
1540+
PagingStateResponse::NoMorePages,
1541+
vec![],
1542+
None,
1543+
None,
1544+
));
1545+
CassResult {
1546+
rows: None,
1547+
metadata,
1548+
}
1549+
}
1550+
1551+
#[test]
1552+
fn non_rows_cass_result_api_test() {
1553+
let result = create_non_rows_cass_result();
1554+
1555+
// Check that API functions do not panic when rows are empty - e.g. for INSERT queries.
1556+
unsafe {
1557+
let result_ptr = std::ptr::addr_of!(result);
1558+
1559+
assert_eq!(0, cass_result_column_count(result_ptr));
1560+
assert_eq!(
1561+
CassValueType::CASS_VALUE_TYPE_UNKNOWN,
1562+
cass_result_column_type(result_ptr, 0)
1563+
);
1564+
assert!(cass_result_column_data_type(result_ptr, 0).is_null());
1565+
assert!(cass_result_first_row(result_ptr).is_null());
1566+
1567+
{
1568+
let mut name_ptr: *const c_char = std::ptr::null();
1569+
let mut name_length: size_t = 0;
1570+
let cass_err = cass_result_column_name(
1571+
result_ptr,
1572+
0,
1573+
addr_of_mut!(name_ptr),
1574+
addr_of_mut!(name_length),
1575+
);
1576+
assert_eq!(CassError::CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS, cass_err);
1577+
}
1578+
}
1579+
}
1580+
}
1581+
13251582
// CassResult functions:
13261583
/*
13271584
extern "C" {

0 commit comments

Comments
 (0)