Fixed matching bug for defining collation context to use

This commit is contained in:
pedrocarlo 2025-04-20 02:02:07 -03:00
parent a818b6924c
commit bba9689674
2 changed files with 42 additions and 29 deletions

View file

@ -466,41 +466,42 @@ pub fn translate_expr(
let e2_reg = e1_reg + 1;
translate_expr(program, referenced_tables, e1, e1_reg, resolver)?;
let left_collation = program.curr_collation_ctx();
let left_collation_ctx = program.curr_collation_ctx();
program.reset_collation();
translate_expr(program, referenced_tables, e2, e2_reg, resolver)?;
let right_collation = program.curr_collation_ctx();
let right_collation_ctx = program.curr_collation_ctx();
program.reset_collation();
/*
* The rules for determining which collating function to use for a binary comparison
* operator (=, <, >, <=, >=, !=, IS, and IS NOT) are as follows:
*
* 1. If either operand has an explicit collating function assignment using the postfix COLLATE operator,
* then the explicit collating function is used for comparison,
* with precedence to the collating function of the left operand.
*
* 2. If either operand is a column, then the collating function of that column is used
* with precedence to the left operand. For the purposes of the previous sentence,
* a column name preceded by one or more unary "+" operators and/or CAST operators is still considered a column name.
*
* 3. Otherwise, the BINARY collating function is used for comparison.
*/
let collation_ctx = {
match (left_collation, right_collation) {
(Some((c_left, true)), _) => Some((c_left, true)),
(Some((c_left, from_collate_left)), Some((_, false))) => {
Some((c_left, from_collate_left))
}
(Some((_, false)), Some((c_right, true))) => Some((c_right, true)),
(None, Some((c_right, from_collate_right))) => {
Some((c_right, from_collate_right))
}
_ => None,
/*
* The rules for determining which collating function to use for a binary comparison
* operator (=, <, >, <=, >=, !=, IS, and IS NOT) are as follows:
*
* 1. If either operand has an explicit collating function assignment using the postfix COLLATE operator,
* then the explicit collating function is used for comparison,
* with precedence to the collating function of the left operand.
*
* 2. If either operand is a column, then the collating function of that column is used
* with precedence to the left operand. For the purposes of the previous sentence,
* a column name preceded by one or more unary "+" operators and/or CAST operators is still considered a column name.
*
* 3. Otherwise, the BINARY collating function is used for comparison.
*/
let collation_ctx = {
match (left_collation_ctx, right_collation_ctx) {
(Some((c_left, true)), _) => Some((c_left, true)),
(_, Some((c_right, true))) => Some((c_right, true)),
(Some((c_left, from_collate_left)), None) => Some((c_left, from_collate_left)),
(None, Some((c_right, from_collate_right))) => {
Some((c_right, from_collate_right))
}
};
program.set_collation(collation_ctx);
(Some((c_left, from_collate_left)), Some((_, false))) => {
Some((c_left, from_collate_left))
}
_ => None,
}
};
program.set_collation(collation_ctx);
emit_binary_insn(program, op, e1_reg, e2_reg, target_register)?;
program.reset_collation();

View file

@ -67,6 +67,18 @@ 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])),
)
def cleanup(db_fullpath: str):