11use crate :: argconv:: * ;
22use 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+ } ;
46use crate :: inet:: CassInet ;
57use crate :: metadata:: {
68 CassColumnMeta , CassKeyspaceMeta , CassMaterializedViewMeta , CassSchemaMeta , CassTableMeta ,
@@ -22,9 +24,39 @@ pub struct CassResult {
2224pub 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])
3062pub 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]
909971pub 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)
12831345pub 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/*
13271584extern "C" {
0 commit comments