diff --git a/core/translate/group_by.rs b/core/translate/group_by.rs index 7785c4d2c..d7ac98c29 100644 --- a/core/translate/group_by.rs +++ b/core/translate/group_by.rs @@ -462,6 +462,7 @@ pub fn group_by_process_single_group( start_reg_a: registers.reg_group_exprs_cmp, start_reg_b: groups_start_reg, count: group_by.exprs.len(), + collation: program.curr_collation(), }); program.add_comment( diff --git a/core/translate/optimizer/join.rs b/core/translate/optimizer/join.rs index c10fcc4fa..3a2679b7c 100644 --- a/core/translate/optimizer/join.rs +++ b/core/translate/optimizer/join.rs @@ -1205,6 +1205,7 @@ mod tests { notnull: false, default: None, unique: false, + collation: None, } } fn _create_column_of_type(name: &str, ty: Type) -> Column { diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index c0d912e0c..2c3bcd2d4 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -365,6 +365,7 @@ pub fn op_compare( start_reg_a, start_reg_b, count, + collation, } = insn else { unreachable!("unexpected Insn {:?}", insn) @@ -372,6 +373,7 @@ pub fn op_compare( let start_reg_a = *start_reg_a; let start_reg_b = *start_reg_b; let count = *count; + let collation = collation.unwrap_or_default(); if start_reg_a + count > start_reg_b { return Err(LimboError::InternalError( @@ -383,7 +385,12 @@ pub fn op_compare( for i in 0..count { let a = state.registers[start_reg_a + i].get_owned_value(); let b = state.registers[start_reg_b + i].get_owned_value(); - cmp = Some(a.cmp(b)); + cmp = match (a, b) { + (Value::Text(left), Value::Text(right)) => { + Some(collation.compare_strings(left.as_str(), right.as_str())) + } + _ => Some(a.cmp(b)), + }; if cmp != Some(std::cmp::Ordering::Equal) { break; } diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index a39ef5482..a2ef91d01 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -141,12 +141,13 @@ pub fn insn_to_str( start_reg_a, start_reg_b, count, + collation, } => ( "Compare", *start_reg_a as i32, *start_reg_b as i32, *count as i32, - Value::build_text(""), + Value::build_text(&format!("k({count}, {})", collation.unwrap_or_default())), 0, format!( "r[{}..{}]==r[{}..{}]", diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index d94ec521c..156abfcd6 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -153,6 +153,7 @@ pub enum Insn { start_reg_a: usize, start_reg_b: usize, count: usize, + collation: Option, }, /// Place the result of rhs bitwise AND lhs in third register. BitAnd { diff --git a/testing/cli_tests/collate.py b/testing/cli_tests/collate.py index 3dd5daadd..69fa0d574 100644 --- a/testing/cli_tests/collate.py +++ b/testing/cli_tests/collate.py @@ -67,19 +67,25 @@ class CollateTest(BaseModel): "SELECT x FROM t1 WHERE a = d ORDER BY x;", "\n".join(map(lambda x: str(x), [1, 4])), ) - + limbo.run_test( "Text comparison 'abc'=c is performed using the RTRIM collating sequence.", "SELECT x FROM t1 WHERE 'abc' = c ORDER BY x;", "\n".join(map(lambda x: str(x), [1, 2, 3])), ) - + limbo.run_test( "Text comparison c='abc' is performed using the RTRIM collating sequence.", "SELECT x FROM t1 WHERE c = 'abc' ORDER BY x;", "\n".join(map(lambda x: str(x), [1, 2, 3])), ) + limbo.run_test( + " Grouping is performed using the NOCASE collating sequence (Values 'abc', 'ABC', and 'Abc' are placed in the same group).", + "SELECT count(*) FROM t1 GROUP BY d ORDER BY 1;", + "\n".join(map(lambda x: str(x), [4])), + ) + def cleanup(db_fullpath: str): wal_path = f"{db_fullpath}-wal"