Skip to content

Commit 33ed7f1

Browse files
authored
Merge pull request #228 from muzarski/table-meta-column
implement `cass_table_meta_column`
2 parents f80ae3b + d65f06b commit 33ed7f1

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

scylla-rust-wrapper/src/metadata.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub struct CassTableMeta {
3232
pub columns_metadata: HashMap<String, CassColumnMeta>,
3333
pub partition_keys: Vec<String>,
3434
pub clustering_keys: Vec<String>,
35+
/// Non-key columns sorted alphabetically by name.
36+
pub non_key_sorted_columns: Vec<String>,
3537
pub views: HashMap<String, Arc<CassMaterializedViewMeta>>,
3638
}
3739

@@ -81,11 +83,25 @@ pub fn create_table_metadata(table_name: &str, table_metadata: &Table) -> CassTa
8183
columns_metadata.insert(column_name.clone(), cass_column_meta);
8284
});
8385

86+
let mut non_key_sorted_columns = columns_metadata
87+
.iter()
88+
.filter(|(_, column)| {
89+
!matches!(
90+
column.column_kind,
91+
CassColumnType::CASS_COLUMN_TYPE_PARTITION_KEY
92+
| CassColumnType::CASS_COLUMN_TYPE_CLUSTERING_KEY,
93+
)
94+
})
95+
.map(|(name, _column)| name.to_owned())
96+
.collect::<Vec<_>>();
97+
non_key_sorted_columns.sort_unstable();
98+
8499
CassTableMeta {
85100
name: table_name.to_owned(),
86101
columns_metadata,
87102
partition_keys: table_metadata.partition_key.clone(),
88103
clustering_keys: table_metadata.clustering_key.clone(),
104+
non_key_sorted_columns,
89105
views: HashMap::new(),
90106
}
91107
}
@@ -209,6 +225,59 @@ pub unsafe extern "C" fn cass_table_meta_column_count(table_meta: *const CassTab
209225
table_meta.columns_metadata.len() as size_t
210226
}
211227

228+
#[no_mangle]
229+
pub unsafe extern "C" fn cass_table_meta_column(
230+
table_meta: *const CassTableMeta,
231+
index: size_t,
232+
) -> *const CassColumnMeta {
233+
// The order of columns in cpp-driver (and in DESCRIBE TABLE in cqlsh):
234+
// 1. partition keys sorted by position <- this is guaranteed by rust-driver.
235+
// Table::partition_keys is a Vector of pk names, sorted by position.
236+
// 2. clustering keys sorted by position <- this is guaranteed by rust-driver (same reasoning as above).
237+
// 3. remaining columns in alphabetical order <- this is something we need to guarantee.
238+
//
239+
// Example:
240+
// CREATE TABLE t
241+
// (
242+
// i int, f int, g int STATIC, b int, c int STATIC, a int, d int, j int, h int,
243+
// PRIMARY KEY( (d, a, j), h, i )
244+
// );
245+
//
246+
// The order should be: d, a, j, h, i, b, c, f, g
247+
// First pks by position: d, a, j
248+
// Then cks by position: h, i
249+
// Then remaining columns alphabetically: b, c, f, g
250+
251+
let table_meta = RefFFI::as_ref(table_meta);
252+
let index = index as usize;
253+
254+
// Check if the index lands in partition keys. If so, simply return the corresponding column.
255+
if let Some(pk_name) = table_meta.partition_keys.get(index) {
256+
// unwrap: partition key must exist in columns_metadata. This is ensured by rust-driver.
257+
return RefFFI::as_ptr(table_meta.columns_metadata.get(pk_name).unwrap());
258+
}
259+
260+
// Update the index to search in clustering keys
261+
let index = index - table_meta.partition_keys.len();
262+
263+
// Check if the index lands in clustering keys. If so, simply return the corresponding column.
264+
if let Some(ck_name) = table_meta.clustering_keys.get(index) {
265+
// unwrap: clustering key must exist in columns_metadata. This is ensured by rust-driver.
266+
return RefFFI::as_ptr(table_meta.columns_metadata.get(ck_name).unwrap());
267+
}
268+
269+
// Update the index to search in remaining columns
270+
let index = index - table_meta.clustering_keys.len();
271+
272+
table_meta
273+
.non_key_sorted_columns
274+
.get(index)
275+
.map_or(std::ptr::null(), |column_name| {
276+
// unwrap: We guarantee that column_name exists in columns_metadata. See `create_table_metadata`.
277+
RefFFI::as_ptr(table_meta.columns_metadata.get(column_name).unwrap())
278+
})
279+
}
280+
212281
#[no_mangle]
213282
pub unsafe extern "C" fn cass_table_meta_partition_key(
214283
table_meta: *const CassTableMeta,

tests/src/integration/tests/test_schema_metadata.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,53 @@ CASSANDRA_INTEGRATION_TEST_F(SchemaMetadataTest, KeyspaceMetadata) {
254254
cass_schema_meta_free(schema_meta);
255255
}
256256

257+
CASSANDRA_INTEGRATION_TEST_F(SchemaMetadataTest, TableMetadataColumnOrder) {
258+
// The order should be: d, a, j, h, i, b, c, f, g
259+
// First pks by position: d, a, j
260+
// Then cks by position: h, i
261+
// Then remaining columns alphabetically: b, c, f, g
262+
263+
session_.execute(format_string("CREATE TABLE %s "
264+
"(i int, f int, g int STATIC, b int, c int STATIC, a int, d int, j int, h int, "
265+
"PRIMARY KEY( (d, a, j), h, i ) )", "column_order_test"));
266+
267+
const CassSchemaMeta* schema_meta = session_.schema_meta();
268+
269+
const CassKeyspaceMeta* keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta, keyspace_name_.c_str());
270+
ASSERT_TRUE(keyspace_meta);
271+
272+
const CassTableMeta* table_meta = cass_keyspace_meta_table_by_name(keyspace_meta, "column_order_test");
273+
ASSERT_TRUE(table_meta);
274+
275+
ASSERT_EQ(cass_table_meta_column_count(table_meta), 9u);
276+
277+
ASSERT_EQ(cass_table_meta_partition_key_count(table_meta), 3u);
278+
ASSERT_EQ(cass_table_meta_clustering_key_count(table_meta), 2u);
279+
280+
auto check_column = [&](size_t index, const char* name) {
281+
const CassColumnMeta* column_meta;
282+
const char* column_meta_name;
283+
size_t column_meta_name_length;
284+
285+
column_meta = cass_table_meta_column(table_meta, index);
286+
ASSERT_TRUE(column_meta);
287+
cass_column_meta_name(column_meta, &column_meta_name, &column_meta_name_length);
288+
ASSERT_EQ(std::string(column_meta_name, column_meta_name_length), name);
289+
};
290+
291+
check_column(0, "d");
292+
check_column(1, "a");
293+
check_column(2, "j");
294+
check_column(3, "h");
295+
check_column(4, "i");
296+
check_column(5, "b");
297+
check_column(6, "c");
298+
check_column(7, "f");
299+
check_column(8, "g");
300+
301+
cass_schema_meta_free(schema_meta);
302+
}
303+
257304
CASSANDRA_INTEGRATION_TEST_F(SchemaMetadataTest, MetadataIterator) {
258305
const CassSchemaMeta* schema_meta = session_.schema_meta();
259306

0 commit comments

Comments
 (0)