Pere Diaz Bou
c808863256
test update with index
2025-05-01 11:44:23 +03:00
Pere Diaz Bou
a30241ca91
Add state machine for op_idx_delete + DeleteState simplification
...
DeleteState had a bit too many unnecessary states so I removed them.
Usually we care about having a different state when I/O is triggered
requiring a state to be stored for later.
Furthermore, there was a bug with op_idx_delete where if balance is
triggered, op_idx_delete wouldn't be re-entrant. So a state machine was
added to prevent that from happening.
2025-04-29 14:58:20 +03:00
Jussi Saurio
c3441f9685
vdbe: move comments if instructions were moved around in emit_constant_insns()
2025-04-24 11:05:21 +03:00
Jussi Saurio
0f5c791784
vdbe: refactor label resolution to account for insn offsets changing
2025-04-24 11:05:21 +03:00
Jussi Saurio
9dadc58194
Add support for Insn::Once
2025-04-14 11:23:37 +03:00
Jussi Saurio
d286a56e15
refactor: fold Async/Await insns into a single instruction
2025-04-14 09:40:20 +03:00
Levy A.
d210ee1497
cargo fmt
2025-04-12 18:55:48 -03:00
Levy A.
5c0b112125
fix: return null when parameter is unbound
2025-04-12 17:43:04 -03:00
Pekka Enberg
31f0d174d7
core/vdbe: Move exec_*() funtions to execute.rs
2025-04-10 09:42:03 +03:00
Pekka Enberg
5906d7971a
core/vdbe: Clean up imports
2025-04-10 09:25:15 +03:00
Jussi Saurio
3e42a62cd0
Add SeekLE/SeekLT operations to VDBE
2025-04-09 10:14:29 +03:00
Jussi Saurio
ed929d2a0a
Merge 'Properly handle insertion of indexed columns' from Preston Thorpe
...
```console
limbo> create index p on products(price);
limbo> explain insert into products (name,price) values ('huh',32);
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 17 0 0 Start at 17
1 OpenWriteAsync 0 273 0 0
2 OpenWriteAwait 0 0 0 0
3 String8 0 3 0 huh 0 r[3]='huh'
4 Integer 32 4 0 0 r[4]=32
5 OpenWriteAsync 1 297 0 0
6 OpenWriteAwait 0 0 0 0
7 NewRowId 0 1 0 0
8 MakeRecord 2 3 5 0 r[5]=mkrec(r[2..4])
9 InsertAsync 0 5 1 0
10 InsertAwait 0 0 0 0
11 Copy 4 6 0 0 r[6]=r[4]
12 Copy 1 7 0 0 r[7]=r[1]
13 MakeRecord 6 2 8 0 r[8]=mkrec(r[6..7])
14 IdxInsertAsync 1 8 6 0 key=r[8]
15 IdxInsertAwait 1 0 0 0
16 Halt 0 0 0 0
17 Transaction 0 1 0 0 write=true
18 Null 0 2 0 0 r[2]=NULL
19 Goto 0 1 0 0
```
When an insert happens, we need to be sure to insert into the index
btree as well.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com >
Closes #1265
2025-04-09 10:13:59 +03:00
PThorpe92
4b9b6c969b
Parse schema rows after extensions are loaded
2025-04-08 20:10:47 -04:00
PThorpe92
1f29307fe8
Support proper index handling when doing insertions
2025-04-08 08:55:14 -04:00
PThorpe92
a2b9d8d371
Use Correct flag on idx insert to prevent seeking
2025-04-05 11:19:09 -04:00
Pekka Enberg
c592e27dca
core/vdbe: Move explain() to last method in Program
...
...it's the least interesting one and we should have `step()` at the top.
2025-04-02 18:55:35 +03:00
Pere Diaz Bou
7e4b57f2e2
VDBE with direct function dispatch
...
This PR is unapologetically stolen from @vmg's implementation in Vitess
implemented here https://github.com/vitessio/vitess/pull/12369 . If you
want a more in depth explanation of how this works you can read the
[blog post he carefully
wrote](https://planetscale.com/blog/faster-interpreters-in-go-catching-up-with-cpp ).
In limbo we have a huge problem with [register
spilling](https://en.wikipedia.org/wiki/Register_allocation ), this can
be easily observed with the prolog of `Program::step` before:
```llvm
start:
%e.i.i304.i = alloca [0 x i8], align 8
%formatter.i305.i = alloca [64 x i8], align 8
%buf.i306.i = alloca [24 x i8], align 8
%formatter.i259.i = alloca [64 x i8], align 8
..................... these are repeated for hundreds of lines
.....................
%formatter.i52.i = alloca [64 x i8], align 8
%buf.i53.i = alloca [24 x i8], align 8
%formatter.i.i = alloca [64 x i8], align 8
%buf.i.i = alloca [24 x i8], align 8
%_87.i = alloca [48 x i8], align 8
%_82.i = alloca [24 x i8], align 8
%_73.i = alloca [24 x i8], align 8
%_66.i8446 = alloca [24 x i8], align 8
%_57.i = alloca [24 x i8], align 8
%_48.i = alloca [24 x i8], align 8
```
After these changes we completely remove the need of register spilling
(yes that is the complete prolog):
```llvm
start:
%self1 = alloca [80 x i8], align 8
%pager = alloca [8 x i8], align 8
%mv_store = alloca [8 x i8], align 8
store ptr %0, ptr %mv_store, align 8
store ptr %1, ptr %pager, align 8
%2 = getelementptr inbounds i8, ptr %state, i64 580
%3 = getelementptr inbounds i8, ptr %state, i64 576
%4 = getelementptr inbounds i8, ptr %self, i64 16
%5 = getelementptr inbounds i8, ptr %self, i64 8
%6 = getelementptr inbounds i8, ptr %self1, i64 8
br label %bb1, !dbg !286780
```
When it comes to branch prediction, we don't really fix a lot because
thankfully rust already compiles `match` expressions
to a jump table:
```llvm
%insn = getelementptr inbounds [0 x %"vdbe::insn::Insn"], ptr %self657,
i64 0, i64 %index, !dbg !249527
%332 = load i8, ptr %insn, align 8, !dbg !249528 , !range !38291 ,
!noundef !14
switch i8 %332, label %default.unreachable26674 [
i8 0, label %bb111
i8 1, label %bb101
i8 2, label %bb100
i8 3, label %bb110
...
i8 104, label %bb5
i8 105, label %bb16
i8 106, label %bb14
], !dbg !249530
```
Some results
----
```
function dispatch:
Execute `SELECT 1`/limbo_execute_select_1
time: [29.498 ns 29.548 ns 29.601 ns]
change: [-3.6125% -3.3592% -3.0804%] (p = 0.00 <
0.05)
main:
Execute `SELECT 1`/limbo_execute_select_1
time: [33.789 ns 33.832 ns 33.878 ns]
```
2025-04-02 14:55:37 +02:00
Pekka Enberg
6199c3994a
Merge 'Create plan for Update queries' from Preston Thorpe
...
closes #1186 , or at least works towards it by implementing an actual
Plan for update queries instead of translating everything inline. This
allows for actually using index's, rewriting const expressions, pushing
predicates instead of hardcoding a full scan in the translation.
### TODOs:
1. `RETURNING` clause/result columns
2. `OFFSET` clauses
3. on conflict
### LIMIT:
By supporting `LIMIT` directly in update queries, we'll have to put the
tests outside of the compatibility tests, maybe in the CLI tests.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com >
Closes #1189
2025-04-01 17:33:32 +03:00
Pekka Enberg
169864456e
Merge 'Fix IdxCmp insn comparisons' from Jussi Saurio
...
We never hit bugs due to these because of 1. not having multi column
indexes in our TCL test databases, 2. otherwise not really having Rust
tests involving indexes, and 3. `IdxLt` and `IdxLe` not actually being
used anywhere yet
Also as @PThorpe92 pointed out there are some nuances to the comparison
logic we may need to eventually implement regarding comparisons with
uneven number of keys:
https://github.com/sqlite/sqlite/blob/master/src/vdbeaux.c#L4719
Reviewed-by: Preston Thorpe (@PThorpe92)
Closes #1215
2025-03-31 10:40:01 +03:00
Jussi Saurio
42e25d23dd
Fix IdxCmp insn comparisons
2025-03-30 23:01:41 +03:00
PThorpe92
516e443a2b
Fix use index cursor id in emitter and prevent reinsert pk on update
2025-03-30 12:15:25 -04:00
Ihor Andrianov
a234aa3647
remove vec cloning from json agg functions
2025-03-30 19:10:15 +03:00
Ihor Andrianov
40bb867d54
clippy
2025-03-30 19:01:16 +03:00
Ihor Andrianov
db5e364210
made json an optional module again
2025-03-30 19:01:03 +03:00
Ihor Andrianov
6c126dcd97
add jsonb_set
2025-03-30 18:58:40 +03:00
Ihor Andrianov
101dd51d7c
add jsonb_group_object and array
2025-03-30 18:58:39 +03:00
Ihor Andrianov
568dc54b9e
big cleanup
2025-03-30 18:58:33 +03:00
Ihor Andrianov
a983c979c6
jsonb_merge, json_group_array, json_group_object
2025-03-30 18:47:33 +03:00
Pere Diaz Bou
a13b33fec9
clippy again
2025-03-29 22:07:43 +01:00
Pere Diaz Bou
d9f5cd870d
clippy
2025-03-29 22:04:08 +01:00
Pere Diaz Bou
4a9c4cff02
fix comparison of immutable records in seekgt
2025-03-29 22:04:08 +01:00
Pere Diaz Bou
1bfec65f23
remove dbg
2025-03-29 22:04:08 +01:00
Pere Diaz Bou
ee55116ca6
return row as reference to registers
2025-03-29 22:04:08 +01:00
Pere Diaz Bou
5b7fcd27bd
make column reuse blob/text fields
2025-03-29 22:02:49 +01:00
Pere Diaz Bou
bf37fd3314
wip
2025-03-29 22:02:49 +01:00
Pekka Enberg
4ee60348f2
Merge 'Fixes probably all floating point math issues and floating point display issues.' from Ihor Andrianov
...
Closes #1206
Closes #447
Closes #1117
Issues:
1. Rust floating point math fucntions are non deterministic.
2. SQLite have complex floating point display rules.
I changed rust functions to libm for math ops and implemented Display
trait for OwnedValue:Float. A lot of float formatting SQLite probably
inherits from C have to be handcrafted.
Closes #1208
2025-03-29 17:33:53 +02:00
Ihor Andrianov
8b9f34af71
fix tests and return nan as null
2025-03-29 14:46:11 +02:00
Ihor Andrianov
303f1b3749
replace std math functions with libm for compat
2025-03-29 12:16:14 +02:00
Pere Diaz Bou
83d0c9a1b6
fix read overflow page procedure
2025-03-28 11:30:19 +01:00
Pere Diaz Bou
dc8acf1a4a
cell_get no allocations
2025-03-28 11:12:27 +01:00
Pekka Enberg
387b68fc06
Merge 'Expose 'Explain' to prepared statement to allow for alternate Writer ' from Preston Thorpe
...
### The problem:
I often need to copy the output of an `Explain` statement to my
clipboard. Currently this is not possible because it currently will only
write to stdout.
All other limbo output, I am able to run `.output file` in the CLI, then
enter my query and in another tmux pane I simply `cat file | xclip -in
-selection clipboard`.
### The solution:
Expose a `statement.explain()` method that returns the query explanation
as a string. If the user uses something like `execute` instead of
prepare, it will default to `stdout` as expected, but this allows the
user to access the query plan on the prepared statement and do with it
what they please.
Closes #1166
2025-03-28 09:55:58 +02:00
Pere Diaz Bou
9291f60722
Introduce Register struct
...
OwnedValue has become a powerhouse of madness, mainly because I decided
to do it like that when I first introduced AggContext. I decided it was
enough and I introduced a `Register` struct that contains `OwnedValue`,
`Record` and `Aggregation`, this way we don't use `OwnedValue` for
everything make everyone's life harder.
This is the next step towards making ImmutableRecords the default
because I want to remove unnecessary allocations. Right now we clone
OwnedValues when we generate a record more than needed.
2025-03-27 17:53:02 +01:00
Pere Diaz Bou
8642d416c7
Introduce immutable record.
...
Currently we have a Record, which is a dumb vector of cloned values.
This is incredibly bad for performance as we do not want to clone
objects unless needed. Therefore, let's start by introducing this type
so that any record that has already been serialized will be returned
from btree in the format of a simple payload with reference to payload.
2025-03-25 17:35:41 +01:00
PThorpe92
7b55f7a167
Move explain to statement to allow for alternate writer
2025-03-24 18:48:12 -04:00
Ihor Andrianov
d8e070a360
moved json_cache to state
2025-03-24 14:48:40 +02:00
Ihor Andrianov
1511c9b3bf
add json cache to json functions and fix tests
2025-03-24 13:17:58 +02:00
Pekka Enberg
65bf33023c
core: Fix Destroy opcode root page handling
...
The `p1` register points to the root page, not to a cursor.
Fixes #1136
2025-03-24 10:54:49 +02:00
Pekka Enberg
31bbc5144a
Merge 'Initial pass at UPDATE support' from Preston Thorpe
...
This PR is to support `Update` queries. Follows sqlite behavior as much
as possible.
### limbo
```console
limbo> create table t (a,b,c);
limbo> explain update t set a = 1 where b = 2;
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 18 0 0 Start at 18
1 OpenWriteAsync 0 2 0 0
2 OpenWriteAwait 0 0 0 0
3 RewindAsync 0 0 0 0
4 RewindAwait 0 17 0 0 Rewind table t
5 Column 0 1 4 0 r[4]=t.b
6 Ne 4 5 15 0 if r[4]!=r[5] goto 15
7 RowId 0 6 0 0 r[6]=t.rowid
8 IsNull 6 17 0 0 if (r[6]==NULL) goto 17
9 Integer 1 1 0 0 r[1]=1
10 Column 0 1 2 0 r[2]=t.b
11 Column 0 2 3 0 r[3]=t.c
12 MakeRecord 1 3 7 0 r[7]=mkrec(r[1..3])
13 InsertAsync 0 7 6 0
14 InsertAwait 0 0 0 0
15 NextAsync 0 0 0 0
16 NextAwait 0 5 0 0
17 Halt 0 0 0 0
18 Transaction 0 1 0 0 write=true
19 Integer 2 5 0 0 r[5]=2
20 Goto 0 1 0 0
```
### sqlite
```console
sqlite> explain update t set a = 1 where b = 2;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 15 0 0 Start at 15
1 Null 0 1 2 0 r[1..2]=NULL
2 Noop 1 0 1 0
3 OpenWrite 0 2 0 2 0 root=2 iDb=0; t
4 Rewind 0 14 0 0
5 Column 0 1 5 0 r[5]= cursor 0 column 1
6 Ne 6 13 5 BINARY-8 81 if r[5]!=r[6] goto 13
7 Rowid 0 2 0 0 r[2]= rowid of 0
8 IsNull 2 14 0 0 if r[2]==NULL goto 14
9 Integer 1 3 0 0 r[3]=1
10 Column 0 1 4 0 r[4]= cursor 0 column 1
11 MakeRecord 3 2 1 0 r[1]=mkrec(r[3..4])
12 Insert 0 1 2 t 7 intkey=r[2] data=r[1]
13 Next 0 5 0 1
14 Halt 0 0 0 0
15 Transaction 0 1 1 0 1 usesStmtJournal=0
16 Integer 2 6 0 0 r[6]=2
17 Goto 0 1 0 0
```
Closes #1130
2025-03-24 09:19:22 +02:00
Pekka Enberg
e8c0a6e728
Merge 'Various JSON improvements' from Ihor Andrianov
...
Added jsonb_object, jsonb_array, json_insert, jsonb_insert.
MongoDB is sweating now.
Closes #1160
2025-03-24 09:17:40 +02:00
PThorpe92
c83cc6dff2
Small nits/clippy errors in vdbe
2025-03-23 17:08:15 -04:00