-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allocate the right-hand-side register for a binary expression after translating the left-hand-side #321
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jussisaurio
approved these changes
Sep 13, 2024
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
jussisaurio
added a commit
that referenced
this pull request
Sep 14, 2024
…m Jussi Saurio #321 recently fixed an error with register allocation order concerning binary expressions in `translate_condition_expr`. I noticed we had the same bug in `translate_expr` as well, and this led into noticing that our implementation of `Insn::Function` diverges from SQLite in that it doesn't provide a context object that keeps track of how many arguments the function call has. Not having the arg count available at runtime means that e.g.: ``` do_execsql_test length-date-binary-expr { select length(date('now')) = 10; } {1} ``` Returned 0 instead of 1, because at runtime another register was already allocated, and `date()` was implemented like this: ``` Func::Scalar(ScalarFunc::Date) => { let result = exec_date(&state.registers[*start_reg..]); // all registers starting from start_reg state.registers[*dest] = result; state.pc += 1; } ``` SQlite bytecode engine docs for Function say: > Invoke a user function (P4 is a pointer to an sqlite3_context object that contains a pointer to the function to be run) with arguments taken from register P2 and successors. The number of arguments is in the sqlite3_context object that P4 points to. Accordingly, this PR implements a `FuncCtx` struct that contains a `Func` and `arg_count` (usize). Reviewed-by: Pere Diaz Bou <pere-altea@hotmail.com> Closes #323
penberg
added a commit
that referenced
this pull request
Sep 22, 2024
…after translating the left-hand-side' from RJ Barman I found a bug in queries using a like function in the where clause, ex: `SELECT first_name, last_name FROM users WHERE like('Jas%', first_name) = 1`. That panicked with the message: ``` thread 'main' panicked at core/vdbe/mod.rs:1226:33: internal error: entered unreachable code: Like on non-text registers ``` This was caused by an off-by-one error in the vdbe code for executing a `ScalarFunc::Like`. However, this only happened in where-like-fn queries. Queries using the like operator (ex: `SELECT first_name, last_name FROM users WHERE first_name LIKE 'Jas%'`) did not have this problem. I did some digging around, looked at the explains for these queries from both limbo and sqlite, and it turns out, for binary expressions, limbo positions the arguments in the register differently, which is the ultimate root cause of this problem. For the where-like-fn query, before execution limbo's registers look like this: ``` [Null, Null, Integer(1), Text("Jas%"), Text("Jason"), Null, Null] ^the rhs 1 ^pattern ^haystack str ``` Sqlite's look look something like this: ``` [Null, Null, Text("Jas%"), Text("Jason"), Integer(1), Null, Null] ^pattern ^haystack str ^the rhs 1 ``` Ultimately limbo's execution of scalar like function was looking in positions 2 and 3 always, but because we stored the right-hand-side before the like-fn arguments, there was an off-by-one error, and the non-text register it was finding was the `Integer(1)`. This PR changes the binary expression translation to allocate the right- hand-side register *after* translating the left-hand-side, fixing the off-by-one and matching sqlite's register layout. Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #321
penberg
pushed a commit
that referenced
this pull request
Sep 22, 2024
…m Jussi Saurio #321 recently fixed an error with register allocation order concerning binary expressions in `translate_condition_expr`. I noticed we had the same bug in `translate_expr` as well, and this led into noticing that our implementation of `Insn::Function` diverges from SQLite in that it doesn't provide a context object that keeps track of how many arguments the function call has. Not having the arg count available at runtime means that e.g.: ``` do_execsql_test length-date-binary-expr { select length(date('now')) = 10; } {1} ``` Returned 0 instead of 1, because at runtime another register was already allocated, and `date()` was implemented like this: ``` Func::Scalar(ScalarFunc::Date) => { let result = exec_date(&state.registers[*start_reg..]); // all registers starting from start_reg state.registers[*dest] = result; state.pc += 1; } ``` SQlite bytecode engine docs for Function say: > Invoke a user function (P4 is a pointer to an sqlite3_context object that contains a pointer to the function to be run) with arguments taken from register P2 and successors. The number of arguments is in the sqlite3_context object that P4 points to. Accordingly, this PR implements a `FuncCtx` struct that contains a `Func` and `arg_count` (usize). Reviewed-by: Pere Diaz Bou <pere-altea@hotmail.com> Closes #323
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
I found a bug in queries using a like function in the where clause, ex:
SELECT first_name, last_name FROM users WHERE like('Jas%', first_name) = 1
. That panicked with the message:This was caused by an off-by-one error in the vdbe code for executing a
ScalarFunc::Like
. However, this only happened in where-like-fn queries. Queries using the like operator (ex:SELECT first_name, last_name FROM users WHERE first_name LIKE 'Jas%'
) did not have this problem.I did some digging around, looked at the explains for these queries from both limbo and sqlite, and it turns out, for binary expressions, limbo positions the arguments in the register differently, which is the ultimate root cause of this problem.
For the where-like-fn query, before execution limbo's registers look like this:
Sqlite's look look something like this:
Ultimately limbo's execution of scalar like function was looking in positions 2 and 3 always, but because we stored the right-hand-side before the like-fn arguments, there was an off-by-one error, and the non-text register it was finding was the
Integer(1)
.This PR changes the binary expression translation to allocate the right-hand-side register after translating the left-hand-side, fixing the off-by-one and matching sqlite's register layout.