Skip to content

Commit 84df0c8

Browse files
committed
result_data: include info about column data types
CassDataType can be a heavy object if the type is nested. In this commit we include info about column data types in result metadata (Arc<Vec<Arc<CassDataType>>>). This will be needed to implement cass_result_column_data_type function. We also adjust the construction of `CassValue::value_type` field and avoid allocations. We simply clone Arc from result metadata.
1 parent 0b255fd commit 84df0c8

File tree

2 files changed

+85
-18
lines changed

2 files changed

+85
-18
lines changed

scylla-rust-wrapper/src/query_result.rs

Lines changed: 30 additions & 1 deletion
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,36 @@ 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+
let col_data_types = maybe_col_data_types.unwrap_or_else(|| {
39+
// This allocation is unfortunately necessary, because of the type of CassResultData::col_data_types.
40+
Arc::new(
41+
col_specs
42+
.iter()
43+
.map(|col_spec| Arc::new(get_column_type(&col_spec.typ)))
44+
.collect(),
45+
)
46+
});
47+
48+
CassResultData {
49+
paging_state_response,
50+
col_specs,
51+
col_data_types,
52+
tracing_id,
53+
}
54+
}
55+
}
56+
2857
/// The lifetime of CassRow is bound to CassResult.
2958
/// It will be freed, when CassResult is freed.(see #[cass_result_free])
3059
pub struct CassRow {

scylla-rust-wrapper/src/session.rs

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::argconv::*;
22
use crate::batch::CassBatch;
33
use crate::cass_error::*;
4-
use crate::cass_types::{get_column_type, CassDataType, MapDataType, UDTDataType};
4+
use crate::cass_types::{CassDataType, MapDataType, UDTDataType};
55
use crate::cluster::build_session_builder;
66
use crate::cluster::CassCluster;
77
use crate::exec_profile::{CassExecProfile, ExecProfileName, PerStatementExecProfile};
@@ -214,11 +214,12 @@ pub unsafe extern "C" fn cass_session_execute_batch(
214214
match query_res {
215215
Ok(_result) => Ok(CassResultValue::QueryResult(Arc::new(CassResult {
216216
rows: None,
217-
metadata: Arc::new(CassResultData {
218-
paging_state_response: PagingStateResponse::NoMorePages,
219-
col_specs: vec![],
220-
tracing_id: None,
221-
}),
217+
metadata: Arc::new(CassResultData::from_result_payload(
218+
PagingStateResponse::NoMorePages,
219+
vec![],
220+
None,
221+
None,
222+
)),
222223
}))),
223224
Err(err) => Ok(CassResultValue::QueryError(Arc::new(err))),
224225
}
@@ -285,40 +286,77 @@ pub unsafe extern "C" fn cass_session_execute(
285286
.set_execution_profile_handle(handle),
286287
}
287288

288-
let query_res: Result<(QueryResult, PagingStateResponse), QueryError> = match statement {
289+
// Creating a type alias here to fix clippy lints.
290+
// I want this type to be explicit, so future developers can understand
291+
// what's going on here (and why we include some weird Option of data types).
292+
type QueryRes = Result<
293+
(
294+
QueryResult,
295+
PagingStateResponse,
296+
// We unfortunately have to retrieve the metadata here.
297+
// Since `query.qery` is consumed, we cannot match the statement
298+
// after execution, to retrieve the cached metadata in case
299+
// of prepared statements.
300+
Option<Arc<Vec<Arc<CassDataType>>>>,
301+
),
302+
QueryError,
303+
>;
304+
let query_res: QueryRes = match statement {
289305
Statement::Simple(query) => {
306+
// We don't store result metadta for Queries - return None.
307+
let maybe_result_col_data_types = None;
308+
290309
if paging_enabled {
291310
session
292311
.query_single_page(query.query, bound_values, paging_state)
293312
.await
313+
.map(|(qr, psr)| (qr, psr, maybe_result_col_data_types))
294314
} else {
295315
session
296316
.query_unpaged(query.query, bound_values)
297317
.await
298-
.map(|result| (result, PagingStateResponse::NoMorePages))
318+
.map(|result| {
319+
(
320+
result,
321+
PagingStateResponse::NoMorePages,
322+
maybe_result_col_data_types,
323+
)
324+
})
299325
}
300326
}
301327
Statement::Prepared(prepared) => {
328+
// Clone vector of the Arc<CassDataType>, so we don't do additional allocations when constructing
329+
// CassDataTypes in `CassResultData::from_result_payload`.
330+
let maybe_result_col_data_types = Some(prepared.result_col_data_types.clone());
331+
302332
if paging_enabled {
303333
session
304334
.execute_single_page(&prepared.statement, bound_values, paging_state)
305335
.await
336+
.map(|(qr, psr)| (qr, psr, maybe_result_col_data_types))
306337
} else {
307338
session
308339
.execute_unpaged(&prepared.statement, bound_values)
309340
.await
310-
.map(|result| (result, PagingStateResponse::NoMorePages))
341+
.map(|result| {
342+
(
343+
result,
344+
PagingStateResponse::NoMorePages,
345+
maybe_result_col_data_types,
346+
)
347+
})
311348
}
312349
}
313350
};
314351

315352
match query_res {
316-
Ok((result, paging_state_response)) => {
317-
let metadata = Arc::new(CassResultData {
353+
Ok((result, paging_state_response, maybe_col_data_types)) => {
354+
let metadata = Arc::new(CassResultData::from_result_payload(
318355
paging_state_response,
319-
col_specs: result.col_specs().to_vec(),
320-
tracing_id: result.tracing_id,
321-
});
356+
result.col_specs().to_vec(),
357+
maybe_col_data_types,
358+
result.tracing_id,
359+
));
322360
let cass_rows = create_cass_rows_from_rows(result.rows, &metadata);
323361
let cass_result = Arc::new(CassResult {
324362
rows: cass_rows,
@@ -358,9 +396,9 @@ fn create_cass_rows_from_rows(
358396
fn create_cass_row_columns(row: Row, metadata: &Arc<CassResultData>) -> Vec<CassValue> {
359397
row.columns
360398
.into_iter()
361-
.zip(metadata.col_specs.iter())
362-
.map(|(val, col)| {
363-
let column_type = Arc::new(get_column_type(&col.typ));
399+
.zip(metadata.col_data_types.iter())
400+
.map(|(val, col_data_type)| {
401+
let column_type = Arc::clone(col_data_type);
364402
CassValue {
365403
value: val.map(|col_val| get_column_value(col_val, &column_type)),
366404
value_type: column_type,

0 commit comments

Comments
 (0)