Commit Graph

598 Commits

Author SHA1 Message Date
l.gualtieri
cf407f639e fix #1064 2025-02-27 19:47:51 +01:00
Pekka Enberg
936ae307b7 core: Kill value type
We currently have two value types, `Value` and `OwnedValue`. The
original thinking was that `Value` is external type and `OwnedValue` is
internal type. However, this just results in unnecessary transformation
between the types as data crosses the Limbo library boundary.

Let's just follow SQLite here and consolidate on a single value type
(where `sqlite3_value` is just an alias for the internal `Mem` type).
The way this will eventually work is that we can have bunch of
pre-allocated `OwnedValue` objects in `ProgramState` and basically
return a reference to them all the way to the application itself, which
extracts the actual value.
2025-02-26 10:57:45 +02:00
Pekka Enberg
fe440b7b34 Merge 'Fix casting text to integer to match SQLite' from Preston Thorpe
```console
thread 'fuzz::tests::logical_expression_fuzz_run' panicked at tests\integration\fuzz\mod.rs:818:13:
assertion `left == right` failed: query: SELECT  ( ( 3622873 || -8851250 ) * ( ( ( -124 ) + ( -5792536 ) ) ) ) = ( 179434259456392 < 65481085924370 ), limbo: [[Integer(1)]], sqlite: [[Integer(0)]]
  left: [[Integer(1)]]
 right: [[Integer(0)]]
```
This and a few other failing fuzzing tests were due to incorrectly
parsing numerics from strings. Some of our casting was done properly,
but it wasn't being applied to all cases where the behavior was needed.
It was also attempting to parse a string[0..N] N times until
`string[0..N].parse()` would no longer succeed. This searches for the
index of the first illegal character and parses the resulting slice
once.
Tests were added for some of the edgecases that were previously failing.
This PR also adds a macro in vdbe/insn.rs that allows for a bit of
cleanup and reduces some matching.

Closes #1053
2025-02-25 15:44:37 +02:00
Pekka Enberg
7f2525ac27 Merge 'Implement create virtual table using vtab modules, more work on virtual tables' from Preston Thorpe
This PR started out as one to improve the API of extensions but I ended
up building on top of this quite a bit and it just kept going. Sorry
this one is so large but there wasn't really a good stopping point, as
it kept leaving stuff in broken states.
**VCreate**: Support for `CREATE VIRTUAL TABLE t USING vtab_module`
**VUpdate**: Support for `INSERT` and `DELETE` methods on virtual
tables.
Sqlite uses `xUpdate` function with the `VUpdate` opcode to handle all
insert/update/delete functionality in virtual tables..
have to just document that:
```
if args[0] == NULL:  INSERT args[1] the values in args[2..]

if args[1] == NULL: DELETE args[0]

if args[0] != NULL && len(args) > 2: Update values=args[2..]  rowid=args[0]
```
I know I asked @jussisaurio on discord about this already, but it just
sucked so bad that I added some internal translation so we could expose
a [nice API](https://github.com/tursodatabase/limbo/pull/996/files#diff-
3e8f8a660b11786745b48b528222d11671e9f19fa00a032a4eefb5412e8200d1R54) and
handle the logic ourselves while keeping with sqlite's opcodes.
I'll change it back if I have to, I just thought it was genuinely awful
to have to rely on comments to explain all that to extension authors.
The included extension is not meant to be a legitimately useful one, it
is there for testing purposes. I did something similar in #960 using a
test extension, so I figure when they are both merged, I will go back
and combine them into one since you can do many kinds at once, and that
way it will reduce the amount of crates and therefore compile time.
1. Remaining opcodes.
2. `UPDATE` (when we support the syntax)
3. `xConnect` - expose API for a DB connection to a vtab so it can
perform arbitrary queries.

Closes #996
2025-02-25 15:31:12 +02:00
PThorpe92
b31363aecb More improvements/cleanups to vdbe around casting 2025-02-24 21:31:26 -05:00
PThorpe92
6d55cdba3b Remove allocations from numeric text casting, cleanups 2025-02-24 12:30:38 -05:00
PThorpe92
7e94a152a5 Consolidate code to parse numerics from text 2025-02-24 11:21:25 -05:00
PThorpe92
66f0835d51 Add tests for corrected behavior around casting 2025-02-24 11:21:25 -05:00
PThorpe92
8070e51e26 Fix vdbe casting and rounding issues 2025-02-24 11:21:22 -05:00
PThorpe92
8f27a5fc92 Fix (fuzzing tests) casting text to integer to match sqlite behavior 2025-02-24 11:13:25 -05:00
Pekka Enberg
16306ee1f4 Merge 'Modify the LIKE function to work with all types' from Mohamed Hossam
This PR fixes
[#1040](https://github.com/tursodatabase/limbo/issues/1040) and modifies
the `LIKE` function in the VDBE to work on expressions of all types like
SQLite.
Looking at how SQLite handles this, it gets the text value of the
expression regardless of its affinity. I used `exec_cast(exp, "TEXT")`
to achieve the same effect. Since most `LIKE` queries will probably be
done on `TEXT` expressions, I avoid casting the expression if it's
already `TEXT`. If either of the expressions was `NULL`, SQLite returns
nothing i.e. `NULL`. I also changed the unreachable arm message from
`Like on non-text registers` to `Like failed`.
The following queries produced the same results in Limbo:
```
SQLite version 3.46.1 2024-08-13 09:16:08 (UTF-16 console I/O)
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> CREATE TABLE tbl (n NULL, i INTEGER, r REAL, t TEXT, b BLOB);
sqlite> INSERT INTO tbl VALUES(NULL,1,2.0,'a',X'0500');
sqlite> SELECT * FROM tbl;
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE n LIKE NULL;
sqlite> SELECT * FROM tbl WHERE n LIKE 'NULL';
sqlite> SELECT * FROM tbl WHERE n LIKE 1;
sqlite> SELECT * FROM tbl WHERE n LIKE 2.0;
sqlite> SELECT * FROM tbl WHERE n LIKE x'0500';
sqlite>
sqlite> SELECT * FROM tbl WHERE i LIKE NULL;
sqlite> SELECT * FROM tbl WHERE i LIKE 1;
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE i LIKE '1';
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE i LIKE 2.0;
sqlite> SELECT * FROM tbl WHERE i LIKE 1.0;
sqlite> SELECT * FROM tbl WHERE i LIKE x'0500';
sqlite>
sqlite> SELECT * FROM tbl WHERE r LIKE NULL;
sqlite> SELECT * FROM tbl WHERE r LIKE 2;
sqlite> SELECT * FROM tbl WHERE r LIKE 2.0;
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE r LIKE '2.0';
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE r LIKE 'a';
sqlite> SELECT * FROM tbl WHERE r LIKE x'0500';
sqlite>
sqlite> SELECT * FROM tbl WHERE t LIKE NULL;
sqlite> SELECT * FROM tbl WHERE t LIKE 1;
sqlite> SELECT * FROM tbl WHERE t LIKE 2.0;
sqlite> SELECT * FROM tbl WHERE t LIKE 'a';
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE t LIKE x'0500';
sqlite>
sqlite> SELECT * FROM tbl WHERE b LIKE NULL;
sqlite> SELECT * FROM tbl WHERE b LIKE 1;
sqlite> SELECT * FROM tbl WHERE b LIKE 2.0;
sqlite> SELECT * FROM tbl WHERE b LIKE 'a';
sqlite> SELECT * FROM tbl WHERE b LIKE x'0500';
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE b LIKE 'x''0500''';
sqlite> SELECT * FROM tbl WHERE b LIKE '♣';
sqlite>
sqlite> SELECT * FROM tbl WHERE 1 LIKE 1;
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE 2.0 LIKE 2.0;
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE 2.0 LIKE '2.0';
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE '2.0' LIKE 2.0;
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE '123.45' LIKE 123.45;
|1|2.0|a|♣
sqlite> SELECT * FROM tbl WHERE NULL LIKE NULL;
sqlite> SELECT * FROM tbl WHERE x'0500' LIKE x'0500';
|1|2.0|a|♣
sqlite> SELECT typeof(n), typeof(i), typeof(r), typeof(t), typeof(b) FROM tbl;
null|integer|real|text|blob
```
Though, these queries are very basic, and more testing could be done.

Closes #1044
2025-02-24 11:27:02 +02:00
m0hossam
2204d92a0b Modify LIKE to handle all affinities including Nulls 2025-02-22 04:43:43 +02:00
pedrocarlo
2e38aa1d6b remove dbg 2025-02-20 16:09:39 -03:00
pedrocarlo
13639899a5 more adjustments to parser to handle edge cases 2025-02-20 16:05:50 -03:00
pedrocarlo
033d0116d6 rewrote parsing from text to integer and real 2025-02-20 02:16:30 -03:00
m0hossam
2425b601f7 Cast the matching value into TEXT before matching 2025-02-20 04:57:01 +02:00
m0hossam
1935426509 Add support for Int columns in LIKE function 2025-02-20 00:42:41 +02:00
Zaid Humayun
dc2bb7cb9b DropTable: implementation complete
added helper methods to Schema to remove table and indices from in-memory structures
completed the implementation for DropTable using that
2025-02-19 21:46:26 +05:30
Zaid Humayun
40b08c559c vdbe: modified instruction DropTable
the instruction DropTable has been modified to correctly match SQLite semantics
2025-02-19 21:46:26 +05:30
Zaid Humayun
97d87955cc DROP TABLE: renamed BTreeCusor::btree_drop to BTreeCursor::btree_destroy
this more closely matches semantics
2025-02-19 21:46:26 +05:30
Zaid Humayun
713465c592 instruction: added destroy instruction
added required functionality for destroy. minor cleanup of print statements
2025-02-19 21:46:25 +05:30
Zaid Humayun
b8bebf3fa3 translate: updated the command to more closely match SQLite semantics
the command for drop table translation has been updated so that it more closely matches the semantics of SQLite's drop table command.

there are a few more things missing like ephemeral tables, destroy etc.
2025-02-19 21:46:25 +05:30
Zaid Humayun
76e2d98381 drop table: addresses issue https://github.com/tursodatabase/limbo/issues/894 which requires DROP TABLE to be implemented
this is the initial commit is for the implementation of DROP TABLE. It adds support for the DROP TABLE instruction and adds a DropBTree instruction. It also implements the btree_drop method in btree.rs which makes use of free_page method which will be implemented via PR https://github.com/tursodatabase/limbo/pull/785
2025-02-19 21:46:25 +05:30
pedrocarlo
409297cfdd remove comment 2025-02-19 00:05:56 -03:00
pedrocarlo
0ca6bbab05 modified cast_text_to_number for more compatability with sqlite 2025-02-18 16:28:44 -03:00
Pekka Enberg
98010517d5 Merge 'Add affinity() function to Column' from Jussi Saurio
This is a first step to supporting [sqlite column
affinity](https://www.sqlite.org/datatype3.html) properly in limbo --
just adds an `affinity()` function to `Column` that can then be used
elsewhere

Closes #1030
2025-02-18 17:44:38 +02:00
Jussi Saurio
baf2aec3e9 Fix incorrect CAST text->numeric if valid prefix is 1 char long 2025-02-18 15:07:36 +02:00
Jussi Saurio
89e48a16db Add affinity() function to Column 2025-02-18 10:56:30 +02:00
PThorpe92
9b742e1a76 Remove clone in vtab from_args 2025-02-17 22:37:17 -05:00
PThorpe92
4d2044b010 Fix ownership semantics in extention value conversions 2025-02-17 20:44:45 -05:00
PThorpe92
38e54ca85e Update schema dot command to show virtual tables 2025-02-17 20:44:45 -05:00
PThorpe92
8b5772fe1c Implement VUpdate (insert/delete for virtual tables 2025-02-17 20:44:44 -05:00
PThorpe92
9c8083231c Implement create virtual table and VUpdate opcode 2025-02-17 20:44:44 -05:00
Pere Diaz Bou
b64cc769b6 fix rebase 2025-02-16 18:31:03 +01:00
Jussi Saurio
cbfd77849d Merge 'Fix substr' from Nikita Sivukhin
Align `substr` implementation with SQLite spec
(https://www.sqlite.org/lang_corefunc.html#substr):
> The substr(X,Y,Z) function returns a substring of input string X that
begins with the Y-th character and which is Z characters long. If Z is
omitted then substr(X,Y) returns all characters through the end of the
string X beginning with the Y-th. The left-most character of X is number
1. If Y is negative then the first character of the substring is found
by counting from the right rather than the left. If Z is negative then
the abs(Z) characters preceding the Y-th character are returned. If X is
a string then characters indices refer to actual UTF-8 characters. If X
is a BLOB then the indices refer to bytes.

Reviewed-by: Jussi Saurio (@jussisaurio)

Closes #1013
2025-02-15 18:16:57 +02:00
Jussi Saurio
e4541edb48 Fix IdxGt,IdxGe,IdxLt,IdxLe instructions
According to SQLite documentation, the way to use these instructions
is to compare the seek key to the index key as you would with the
Compare opcode. The compare opcode states:

"Compare two vectors of registers in reg(P1)..reg(P1+P3-1)
(call this vector "A") and in reg(P2)..reg(P2+P3-1) ("B")."

In other words, we should compare the same number of columns from each,
not compare the entire keys.

This fixes a few Clickbench queries returning incorrect results, and
so closes #1009

---

Future work: support index seek keys that use multiple columns. Our
index seek is many times slower than SQLite because we're not utilizing
all the possible columns -- instead we just use the first index column
to seek.
2025-02-15 12:44:56 +02:00
Nikita Sivukhin
91d723016d fix test 2025-02-15 13:29:14 +04:00
Nikita Sivukhin
b35dab5b6d fix substr implementation 2025-02-15 13:21:43 +04:00
[B
5214cf9859 Added IdxLE and IdxLT opcodes 2025-02-14 20:22:30 +01:00
Pekka Enberg
e3925c4531 core/vdbe: Fix Program::halt() to respect autocommit state 2025-02-14 12:11:37 +02:00
Pekka Enberg
ae3c6b7ec5 core/vdbe: Fix AutoCommit instruction to halt the VM
Pointed out by Jussi
2025-02-14 11:43:16 +02:00
Pekka Enberg
948585bb42 core/vdbe: Extract Program::halt() helper
We need this for AutoCommit opcode too.
2025-02-14 11:42:24 +02:00
Pekka Enberg
34b0c7c09a core/vdbe: AutoCommit instruction 2025-02-14 10:26:31 +02:00
Doug Anderson444
0aa5de6d9f rm log, switch all to tracing 2025-02-11 09:03:36 -04:00
Pekka Enberg
d221f158cc Merge 'Add read implementation of user_version pragma with ReadCookie opcode' from Jonathan Webb
Just a bare bones implementation of ReadCookie and support for the
user_version pragma

Closes #909
2025-02-10 12:12:15 +02:00
Pekka Enberg
604ca4085d Merge 'Make record values private' from Tiago
This is an attempt to move towards #881. I am not sure this is the
direction you want to take. In any case, I thought I would take a crack
at converting `values` from `Record` to private and see how bad it would
be.
In the end, as you can see, it is not so bad. I think performance-wise
it shouldn't be a bad hit with Rust's zero-cost abstraction. Also,
during the process I noticed a couple improvements that could be made
here and there but I honestly wanted to start with something small
enough that wouldn't be too hard to review.
Anyway, let me know if this is really how you would like to proceed.

Closes #962
2025-02-10 11:23:21 +02:00
Pekka Enberg
fcad8d125e Merge 'refactor: remove RC<String> requirement for build_text and new text' from Pedro Muniz
This PR aims to simplify text creation and to reduce allocation overhead
of creating a new OwnedValue::Text. Instead of creating Rc<String> every
time you need to create a text, you just pass the string slice and the
Rc<String> is created at the end. This change, at least on my machine,
has removed a lot of variability in the benchmarking performance, while
maintaining roughly the same performance.

Closes #961
2025-02-10 11:21:50 +02:00
Pekka Enberg
00a546e775 Merge 'Fix string funcs' from Nikita Sivukhin
Add fuzz test for string functions and fix 2 bugs in implementation of
`LTRIM/RTRIM/TRIM` and `QUOTE`:
- `QUOTE` needs to escape internal quote(`'`) symbols
- `LTRIM`/`RTRIM`/`TRIM` needs to check if they have additional argument

Closes #958
2025-02-10 11:17:51 +02:00
Pekka Enberg
55058cade3 Merge 'Fix cast' from Nikita Sivukhin
Fix codegen for `CAST` expression and also adjust implementation of
`CAST: Real -> Int` because `SQLite` use "closest integer between the
REAL value and zero" as a CAST result.

Closes #956
2025-02-10 10:53:56 +02:00
Tiago Ribeiro
295691d81b Update core/vdbe to use the new retrieval methods to access Record values. 2025-02-10 00:27:51 -07:00