This PR adjust emitted instructions for expressions which include `IS` /
`IS NOT` operators (support for them in the conditions were added in the
#847)
Reviewed-by: Glauber Costa (@glommer)
Closes#857
This PR remove manual null-comparison optimization (introduced in #847)
which replace `Eq`/`Ne` instructions with explicit `IsNull`/`NotNull`.
There are few factors for this change:
1. Before, manual optimization were incorrect because it ignored
`jump_if_condition_is_true` flag which is important to properly build
logical condition evaluation
2. Manual optimization covered all scenarios in test cases and scenarios
when both sides are non trivial expressions were not covered by tests
3. Limbo already mark literals in the initial emitted bytecode as
constants and will evaluate and store them only once - so performance
difference from manual optimization seems very minor to me (but I am
wrong with high probability)
4. I think (but again, I am wrong with high probability) that such
replacement can be done in the generic optimizator layer instead of
manually encode them in the first emit phase
Fixes#850
Reviewed-by: Glauber Costa (@glommer)
Closes#856
The main difference between = and != is how null values are handled.
SQLite passes a flag "NULLEQ" to Eq and Ne to disambiguate that.
In the presence of that flag, NULL = NULL.
Some prep work is done to make sure we can pass a flag instead of a
boolean to Eq and Ne. I looked into the bitflags crate but got a bit
scared with the list of dependencies.
Warning:
The following query produces a different result for Limbo:
```
select * from demo where value is null or id == 2;
```
I strongly suspect the issue is with the OR implementation, though. The
bytecode generated is quite different.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#847
This seems to really be just an alias for IS:
"The IS NOT DISTINCT FROM operator is an alternative spelling for the IS
operator. Likewise, the IS DISTINCT FROM operator means the same thing
as IS NOT. Standard SQL does not support the compact IS and IS NOT
notation. Those compact forms are an SQLite extension. You have to use
the prolix and much less readable IS NOT DISTINCT FROM and IS DISTINCT
FROM operators on other SQL database engines."
Improvements:
- Use [rust-overlay](https://github.com/oxalica/rust-overlay), better
maintained than fenix and allows for:
- Use `rust-toolchain.toml` as the source of truth for the current rust
version, instead of tracking with stable. Preventing conflicting
versions with non-nix users.
- Add flake checks, could be useful for CI in the future, together with
crane and cachix.
- Add package, allow people to add limbo as a regular nix package. Now
we can `nix build .#`, `nix run .#` and `nix shell .#` (this one adds
`limbo` to the current `PATH`)
- Use [new `apple-sdk` pattern](https://discourse.nixos.org/t/the-
darwin-sdks-have-been-updated/55295), no need to declare each framework
now.
Closes#835
This PR continues work on the Go bindings.
- Register all symbols from the library at load time to prevent any
repeated `dlsym` calls.
- Add locks to prevent multiple concurrent FFI calls to functions that
act on the same state.
- Adds documentation/example in the go module `README`.
- Fixes memory access issue causing segfault due to passing pointer to
array of strings, that is difficult to work with in Go without the right
primitives. In place, simply return the amount of ResultColumns and Go
can provide the index to receive the column name, similar to
`rowsGetValue`
On next limbo release, I'll add the example to the main `README` next to
the other language examples. Until then, `go get
github.com/tursodatabase/limbo` will not work so the example will remain
in the bindings readme.
Closes#845
Instead of always having the caller specify all instructions, this
work introduces convenience functions into the program builder,
making the code a lot cleaner.
Draft for now, as this is done on top of #841
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#844
The main difference between = and != is how null values are handled.
SQLite passes a flag "NULLEQ" to Eq and Ne to disambiguate that.
In the presence of that flag, NULL = NULL.
Some prep work is done to make sure we can pass a flag instead of a
boolean to Eq and Ne. I looked into the bitflags crate but got a bit
scared with the list of dependencies.
This PR implements Noop. I really don't know what else to say. This
bytecode according to sqlite does: _Do nothing. Continue downward to the
next opcode._ I advanced the program counter to account for continuing
to the next instruction.
Closes#795
Instead of always having the caller specify all instructions, this
work introduces convenience functions into the program builder,
making the code a lot cleaner.
The error is due to comparing the PRIMARY KEY's name to INTEGER when in
it was all in lowercase. This was causing `needs_auto_index` to be set
to `true`.
After the fix:
```
/limbo /tmp/sc2-limbo.db
Limbo v0.0.13
Enter ".help" for usage hints.
limbo> CREATE TABLE temp (t1 integer, primary key (t1));
hexdump -s 28 -n 4 /tmp/sc2-limbo.db
000001c 0000 0200 -- matches SQLite
0000020
```
Closes https://github.com/tursodatabase/limbo/issues/824
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#830
The pragma list will only grow. The strum crate can be used to:
* automatically convert to string from enum
* automatically convert to enum from string
* implement an iterator over all elements of the enum
...speeds up PR cycle time by not running on all the possible Python
configurations all the time.
Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>
Closes#840
This is mostly refactoring Cursor.write_info to instead be an enum,
where one of the options is a WriteInfo. This permits one to add other
state machines to Cursor, and I added the state needed for Count as an
example, but all the testing for count's implementation depends on
ANALYZE #656 working end-to-end (to some degree) so that one can write a
SQL test for it.
But this code seems conflict-prone, so it seems better to get it in
sooner than later.
I also finally understood what the point of RefCell is from fighting
with rust on this, so that was nice.
Closes#836
More convenient side by side comparison with sqlite. Got this idea from
[criterion's documentation](https://bheisler.github.io/criterion.rs/book
/user_guide/comparing_functions.html). Some examples:
<img width="1010" alt="image" src="https://github.com/user-
attachments/assets/1cb400f6-f6a5-44af-a429-8e09a42dcd0d" />
<img width="1002" alt="image" src="https://github.com/user-
attachments/assets/ef35dfa6-6474-4fec-9b78-d81b274f2ca1" />
Closes#839
Both () and = variants covered. It is important to make sure that
the transaction is a read transaction, so we cannot hide all that logic
inside update_pragma, and have to make our decision before that.
SQLite holds on to it deeply, for example:
sqlite> create table a(a int);
sqlite> create table b(b integer);
sqlite> create table c(c glauber);
sqlite> pragma table_info=a;
0|a|INT|0||0
sqlite> pragma table_info=b;
0|b|INTEGER|0||0
sqlite> pragma table_info=c;
0|c|glauber|0||0
So we'll keep it as well so we can produce the same responses.