From bba9689674d113f4cb0eed3999e607c7e5e960ce Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Sun, 20 Apr 2025 02:02:07 -0300 Subject: [PATCH] Fixed matching bug for defining collation context to use --- core/translate/expr.rs | 59 ++++++++++++++++++------------------ testing/cli_tests/collate.py | 12 ++++++++ 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/core/translate/expr.rs b/core/translate/expr.rs index fe64e3a2d..24fba1800 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -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(); diff --git a/testing/cli_tests/collate.py b/testing/cli_tests/collate.py index 784b397a2..3dd5daadd 100644 --- a/testing/cli_tests/collate.py +++ b/testing/cli_tests/collate.py @@ -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):