Skip to content

Commit 52b2b14

Browse files
committed
metadata: introduce CassColumnSpec
This structure will hold information about the column name and the column data type. Refactored the `CassResultData`, so now it holds one vector of `CassColumnSpec` instead of two separate vectors for names and data types. Previous version was buggy for prepared statements: - data types came from cached metadata from the statement - column names came from metadata provided by query result Because of this, the vector could be of a different length, when someone ALTERed the corresponding table. Notice that after this commit, we don't reuse cached metadata from prepared statement and reuse the metadata provided from the server. Next commits will fix that.
1 parent 904a971 commit 52b2b14

File tree

3 files changed

+45
-56
lines changed

3 files changed

+45
-56
lines changed

scylla-rust-wrapper/src/cass_types.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ pub enum MapDataType {
138138
KeyAndValue(Arc<CassDataType>, Arc<CassDataType>),
139139
}
140140

141+
pub struct CassColumnSpec {
142+
pub name: String,
143+
pub data_type: Arc<CassDataType>,
144+
}
145+
141146
#[derive(Clone, Debug, PartialEq, Eq)]
142147
pub enum CassDataType {
143148
Value(CassValueType),

scylla-rust-wrapper/src/query_result.rs

Lines changed: 34 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::argconv::*;
22
use crate::cass_error::CassError;
33
use crate::cass_types::{
4-
cass_data_type_type, get_column_type, CassDataType, CassValueType, MapDataType,
4+
cass_data_type_type, get_column_type, CassColumnSpec, CassDataType, CassValueType, MapDataType,
55
};
66
use crate::inet::CassInet;
77
use crate::metadata::{
@@ -24,37 +24,22 @@ pub struct CassResult {
2424
}
2525

2626
pub struct CassResultData {
27-
pub col_names: Vec<String>,
28-
pub col_data_types: Arc<Vec<Arc<CassDataType>>>,
27+
pub col_specs: Vec<CassColumnSpec>,
2928
}
3029

3130
impl CassResultData {
32-
pub fn from_result_payload(
33-
col_specs: &[ColumnSpec<'_>],
34-
maybe_col_data_types: Option<Arc<Vec<Arc<CassDataType>>>>,
35-
) -> CassResultData {
36-
// `maybe_col_data_types` is:
37-
// - Some(_) for prepared statements executions
38-
// - None for unprepared (simple) queries executions
39-
let col_data_types = maybe_col_data_types.unwrap_or_else(|| {
40-
// This allocation is unfortunately necessary, because of the type of CassResultData::col_data_types.
41-
Arc::new(
42-
col_specs
43-
.iter()
44-
.map(|col_spec| Arc::new(get_column_type(col_spec.typ())))
45-
.collect(),
46-
)
47-
});
48-
49-
let col_names = col_specs
31+
pub fn from_column_specs(col_specs: &[ColumnSpec<'_>]) -> CassResultData {
32+
let col_specs = col_specs
5033
.iter()
51-
.map(|col_spec| col_spec.name().to_owned())
34+
.map(|col_spec| {
35+
let name = col_spec.name().to_owned();
36+
let data_type = Arc::new(get_column_type(col_spec.typ()));
37+
38+
CassColumnSpec { name, data_type }
39+
})
5240
.collect();
5341

54-
CassResultData {
55-
col_names,
56-
col_data_types,
57-
}
42+
CassResultData { col_specs }
5843
}
5944
}
6045

@@ -900,12 +885,12 @@ pub unsafe extern "C" fn cass_row_get_column_by_name_n(
900885

901886
return row_from_raw
902887
.result_metadata
903-
.col_names
888+
.col_specs
904889
.iter()
905890
.enumerate()
906-
.find(|(_, col_name)| {
907-
is_case_sensitive && *col_name == name_str
908-
|| !is_case_sensitive && col_name.eq_ignore_ascii_case(name_str)
891+
.find(|(_, col_spec)| {
892+
is_case_sensitive && col_spec.name == name_str
893+
|| !is_case_sensitive && col_spec.name.eq_ignore_ascii_case(name_str)
909894
})
910895
.map(|(index, _)| {
911896
return match row_from_raw.columns.get(index) {
@@ -926,11 +911,16 @@ pub unsafe extern "C" fn cass_result_column_name(
926911
let result_from_raw = ptr_to_ref(result);
927912
let index_usize: usize = index.try_into().unwrap();
928913

929-
if index_usize >= result_from_raw.metadata.col_data_types.len() {
914+
if index_usize >= result_from_raw.metadata.col_specs.len() {
930915
return CassError::CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS;
931916
}
932917

933-
let column_name = result_from_raw.metadata.col_names.get(index_usize).unwrap();
918+
let column_name = &result_from_raw
919+
.metadata
920+
.col_specs
921+
.get(index_usize)
922+
.unwrap()
923+
.name;
934924

935925
write_str_to_c(column_name, name, name_length);
936926

@@ -961,9 +951,9 @@ pub unsafe extern "C" fn cass_result_column_data_type(
961951

962952
result_from_raw
963953
.metadata
964-
.col_data_types
954+
.col_specs
965955
.get(index_usize)
966-
.map(Arc::as_ptr)
956+
.map(|col_spec| Arc::as_ptr(&col_spec.data_type))
967957
.unwrap_or(std::ptr::null())
968958
}
969959

@@ -1338,7 +1328,7 @@ pub unsafe extern "C" fn cass_result_row_count(result_raw: *const CassResult) ->
13381328
pub unsafe extern "C" fn cass_result_column_count(result_raw: *const CassResult) -> size_t {
13391329
let result = ptr_to_ref(result_raw);
13401330

1341-
result.metadata.col_data_types.len() as size_t
1331+
result.metadata.col_specs.len() as size_t
13421332
}
13431333

13441334
#[no_mangle]
@@ -1414,17 +1404,14 @@ mod tests {
14141404
const SECOND_COLUMN_NAME: &str = "varint_col";
14151405
const THIRD_COLUMN_NAME: &str = "list_double_col";
14161406
fn create_cass_rows_result() -> CassResult {
1417-
let metadata = Arc::new(CassResultData::from_result_payload(
1418-
&[
1419-
col_spec(FIRST_COLUMN_NAME, ColumnType::BigInt),
1420-
col_spec(SECOND_COLUMN_NAME, ColumnType::Varint),
1421-
col_spec(
1422-
THIRD_COLUMN_NAME,
1423-
ColumnType::List(Box::new(ColumnType::Double)),
1424-
),
1425-
],
1426-
None,
1427-
));
1407+
let metadata = Arc::new(CassResultData::from_column_specs(&[
1408+
col_spec(FIRST_COLUMN_NAME, ColumnType::BigInt),
1409+
col_spec(SECOND_COLUMN_NAME, ColumnType::Varint),
1410+
col_spec(
1411+
THIRD_COLUMN_NAME,
1412+
ColumnType::List(Box::new(ColumnType::Double)),
1413+
),
1414+
]));
14281415

14291416
let rows = create_cass_rows_from_rows(
14301417
vec![Row {
@@ -1532,7 +1519,7 @@ mod tests {
15321519
}
15331520

15341521
fn create_non_rows_cass_result() -> CassResult {
1535-
let metadata = Arc::new(CassResultData::from_result_payload(&[], None));
1522+
let metadata = Arc::new(CassResultData::from_column_specs(&[]));
15361523
CassResult {
15371524
rows: None,
15381525
metadata,

scylla-rust-wrapper/src/session.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ pub unsafe extern "C" fn cass_session_execute_batch(
220220
match query_res {
221221
Ok(_result) => Ok(CassResultValue::QueryResult(Arc::new(CassResult {
222222
rows: None,
223-
metadata: Arc::new(CassResultData::from_result_payload(&[], None)),
223+
metadata: Arc::new(CassResultData::from_column_specs(&[])),
224224
tracing_id: None,
225225
paging_state_response: PagingStateResponse::NoMorePages,
226226
}))),
@@ -353,11 +353,8 @@ pub unsafe extern "C" fn cass_session_execute(
353353
};
354354

355355
match query_res {
356-
Ok((result, paging_state_response, maybe_col_data_types)) => {
357-
let metadata = Arc::new(CassResultData::from_result_payload(
358-
result.col_specs(),
359-
maybe_col_data_types,
360-
));
356+
Ok((result, paging_state_response, _maybe_col_data_types)) => {
357+
let metadata = Arc::new(CassResultData::from_column_specs(result.col_specs()));
361358
let cass_rows = result
362359
.rows
363360
.map(|rows| create_cass_rows_from_rows(rows, &metadata));
@@ -397,9 +394,9 @@ pub(crate) fn create_cass_rows_from_rows(
397394
fn create_cass_row_columns(row: Row, metadata: &Arc<CassResultData>) -> Vec<CassValue> {
398395
row.columns
399396
.into_iter()
400-
.zip(metadata.col_data_types.iter())
401-
.map(|(val, col_data_type)| {
402-
let column_type = Arc::clone(col_data_type);
397+
.zip(metadata.col_specs.iter())
398+
.map(|(val, col_spec)| {
399+
let column_type = Arc::clone(&col_spec.data_type);
403400
CassValue {
404401
value: val.map(|col_val| get_column_value(col_val, &column_type)),
405402
value_type: column_type,

0 commit comments

Comments
 (0)