Skip to content

Commit 8276e21

Browse files
Fix multi-column column index rebuild ordering
1 parent 36de434 commit 8276e21

2 files changed

Lines changed: 48 additions & 1 deletion

File tree

core-relations/src/hash_index/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ impl IndexBase for ColumnIndex {
350350

351351
radix_sort_pairs_by_value(&mut pairs);
352352
if cols.len() > 1 {
353+
// Multi-column collection is column-major, so a stable value sort
354+
// can leave each value's rows out of order across columns.
355+
for group in pairs.chunk_by_mut(|a, b| a.0 == b.0) {
356+
group.sort_unstable_by_key(|&(_, row)| row);
357+
}
353358
// Remove duplicates (same value in multiple columns of the same row).
354359
pairs.dedup();
355360
}

core-relations/src/hash_index/tests.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::numeric_id::NumericId;
1+
use crate::{numeric_id::NumericId, offsets::Offsets};
22

33
use crate::{
44
TupleIndex,
5+
hash_index::ColumnIndex,
56
table_shortcuts::{fill_table, v},
67
table_spec::{ColumnId, WrappedTable},
78
};
@@ -89,3 +90,44 @@ fn basic_updates() {
8990
}
9091
}
9192
}
93+
94+
#[test]
95+
fn multi_column_column_index_rebuild_orders_each_value_by_row() {
96+
let rows = (0..128).map(|i| {
97+
let left = if i >= 96 { v(7) } else { v(1_000 + i) };
98+
let right = if i < 32 { v(7) } else { v(2_000 + i) };
99+
vec![v(i), left, right]
100+
});
101+
let mut table = WrappedTable::new(fill_table(rows, 1, None, |old, new| {
102+
assert_eq!(old, new, "no conflicts in this test");
103+
None
104+
}));
105+
let mut index = Index::new(vec![ColumnId::new(1), ColumnId::new(2)], ColumnIndex::new());
106+
index.refresh(table.as_ref());
107+
108+
empty_execution_state!(es);
109+
let start_version = table.version().major;
110+
while table.version().major == start_version {
111+
table.new_buffer().stage_remove(&[v(0)]);
112+
table.merge(&mut es);
113+
table.new_buffer().stage_insert(&[v(0), v(1000), v(7)]);
114+
table.merge(&mut es);
115+
}
116+
117+
index.refresh(table.as_ref());
118+
let key = v(7);
119+
let subset = index.get_subset(&key).unwrap();
120+
let mut row_ids = Vec::new();
121+
subset.offsets(|row_id| row_ids.push(row_id.index()));
122+
123+
let mut expected = Vec::new();
124+
table
125+
.scan(table.all().as_ref())
126+
.iter()
127+
.for_each(|(row_id, row)| {
128+
if row[1] == key || row[2] == key {
129+
expected.push(row_id.index());
130+
}
131+
});
132+
assert_eq!(row_ids, expected);
133+
}

0 commit comments

Comments
 (0)