Commit Graph

675 Commits

Author SHA1 Message Date
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
Ihor Andrianov
2cab36bfc3 add json_replace, jsonb_replace 2025-03-23 20:52:03 +02:00
Ihor Andrianov
c4549ad2cd split json traversal and mutation operation logic 2025-03-23 20:37:12 +02:00
Ihor Andrianov
252583cb1e add jsonb_obj jsonb_array 2025-03-20 15:22:52 +02:00
Pekka Enberg
4142f4f4cb Merge 'Organize extension library and feature gate VFS' from Preston Thorpe
I keep having 3+ PR's in at the same time and always deal with crazy
conflicts because everything in the `ext` library is together in one
file.
This PR moves each category of extension into its own file, and
separates the `vfs` functionality in Core into the `ext/dynamic` module,
so that it can be more easily separated from wasm (or non feature =
"fs") targets to prevent build issues.
The only semantic changes made in this PR is the feature gating of vfs,
the rest is simply organizing and cleaning up imports.
Was unsure if `vfs` should be a feature on the `core` side too, or to
just enable it with the `fs` feature which seemed reasonable, as that
was already the current behavior. But let me know if we want it entirely
behind it's own feature.

Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>

Closes #1124
2025-03-19 19:08:13 +02:00
Pekka Enberg
d4db5eb4c1 Merge 'Various JSON and JSONB function improvements' from Ihor Andrianov
Added jsonb_remove, jsonb_replace, json_replace.
Updated json_remove to use jsonb under the hood.
Fixed json function big numbers serialization.
Add tests for new functions.

Closes #1140
2025-03-19 17:21:44 +02:00
PThorpe92
57d4aa7216 Reorganize ext library and feature gate vfs to more easily prevent wasm build issues 2025-03-19 10:17:11 -04:00
Ihor Andrianov
32ea972151 make tests pass 2025-03-19 11:29:46 +02:00
Ihor Andrianov
b5e86a9e36 remove and replace functions defenitions 2025-03-18 21:43:48 +02:00
Pekka Enberg
a2c6831f30 Merge 'Implement FastLock for DatabaseHeader' from Pere Diaz Bou
The motivation behind implementing our own lock is to not depend on any
dependency as we should moving forward. This is a experiment for now as
a single test obviously is not enough but I believe this is the right
direction to on.
## benchmark tldr;
Execute benchmarks have a performance improvement around [1.78%, 7.5%]
which seems like it went okay as it was expected from removing
`pthread_mutex` calls.
## benchmarks before
```
Prepare `SELECT 1`/Limbo/SELECT 1
                        time:   [575.63 ns 577.33 ns 580.07 ns]
                        change: [-1.3304% -0.8881% -0.4675%] (p = 0.00 < 0.05)
                        Change within noise threshold.

Prepare `SELECT * FROM users LIMIT 1`/Limbo/SELECT * FROM users LIMIT 1
                        time:   [1.2070 µs 1.2114 µs 1.2166 µs]
                        change: [-0.8670% -0.4084% -0.0252%] (p = 0.06 > 0.05)
                        No change in performance detected.

Prepare `SELECT first_name, count(1) FROM users GROUP BY first_name HAVING count(1) > 1 ORDER BY cou...
                        time:   [2.9845 µs 2.9895 µs 2.9951 µs]
                        change: [-3.0470% -2.6038% -2.1301%] (p = 0.00 < 0.05)
                        Performance has improved.
Prepare `SELECT first_name, count(1) FROM users GROUP BY first_name HAVING count(1) > 1 ORDER BY cou... #2
                        time:   [1.6015 µs 1.6084 µs 1.6157 µs]
                        change: [-0.0676% +0.3850% +0.8704%] (p = 0.11 > 0.05)
                        No change in performance detected.
Execute `SELECT * FROM users LIMIT ?`/Limbo/1
                        time:   [442.46 ns 446.72 ns 454.13 ns]
                        change: [+3.9744% +4.5337% +5.3357%] (p = 0.00 < 0.05)
                        Performance has regressed.
Execute `SELECT * FROM users LIMIT ?`/Limbo/10
                        time:   [3.1722 µs 3.1850 µs 3.1980 µs]
                        change: [+7.1994% +7.7452% +8.2856%] (p = 0.00 < 0.05)
                        Performance has regressed.
Execute `SELECT * FROM users LIMIT ?`/Limbo/50
                        time:   [14.976 µs 15.024 µs 15.078 µs]
                        change: [+5.7879% +6.2419% +6.7139%] (p = 0.00 < 0.05)
                        Performance has regressed.
Execute `SELECT * FROM users LIMIT ?`/Limbo/100
                        time:   [29.834 µs 29.925 µs 30.024 µs]
                        change: [+4.6519% +5.0384% +5.4491%] (p = 0.00 < 0.05)
                        Performance has regressed.
Execute `SELECT 1`/Limbo
                        time:   [45.135 ns 45.439 ns 45.763 ns]
                        change: [-0.4703% -0.0496% +0.3622%] (p = 0.81 > 0.05)
                        No change in performance detected.
```
## benchmarks after
```
Prepare `SELECT 1`/Limbo/SELECT 1
                        time:   [585.61 ns 590.92 ns 596.49 ns]
                        change: [+0.5902% +1.1505% +1.7012%] (p = 0.00 < 0.05)
                        Change within noise threshold.

Prepare `SELECT * FROM users LIMIT 1`/Limbo/SELECT * FROM users LIMIT 1
                        time:   [1.2061 µs 1.2090 µs 1.2119 µs]
                        change: [-0.2364% +0.0977% +0.4252%] (p = 0.57 > 0.05)
                        No change in performance detected.

Prepare `SELECT first_name, count(1) FROM users GROUP BY first_name HAVING count(1) > 1 ORDER BY cou...
                        time:   [2.9854 µs 2.9893 µs 2.9936 µs]
                        change: [-0.5752% -0.2529% +0.0167%] (p = 0.09 > 0.05)
                        No change in performance detected.
Prepare `SELECT first_name, count(1) FROM users GROUP BY first_name HAVING count(1) > 1 ORDER BY cou... #2
                        time:   [1.5853 µs 1.5983 µs 1.6108 µs]
                        change: [-2.3810% -1.7986% -1.2748%] (p = 0.00 < 0.05)
                        Performance has improved.
Execute `SELECT * FROM users LIMIT ?`/Limbo/1
                        time:   [429.84 ns 431.34 ns 433.07 ns]
                        change: [-2.7721% -1.8504% -0.8738%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Execute `SELECT * FROM users LIMIT ?`/Limbo/10
                        time:   [2.9184 µs 2.9254 µs 2.9323 µs]
                        change: [-8.2377% -7.7816% -7.3373%] (p = 0.00 < 0.05)
                        Performance has improved.
Execute `SELECT * FROM users LIMIT ?`/Limbo/50
                        time:   [14.190 µs 14.229 µs 14.271 µs]
                        change: [-6.2034% -5.7858% -5.3552%] (p = 0.00 < 0.05)
                        Performance has improved.
Execute `SELECT * FROM users LIMIT ?`/Limbo/100
                        time:   [28.734 µs 28.856 µs 28.979 µs]
                        change: [-4.3640% -3.9462% -3.5492%] (p = 0.00 < 0.05)
                        Performance has improved.

Execute `SELECT 1`/Limbo
                        time:   [43.144 ns 43.237 ns 43.326 ns]
                        change: [-4.9417% -4.5554% -4.2030%] (p = 0.00 < 0.05)
                        Performance has improved.
```

Closes #1120
2025-03-18 13:44:16 +02:00
Pekka Enberg
f9d7834874 Merge 'Jsonb extract' from Ihor Andrianov
Made a jsonb traversal by json path.
Changed some ordinary json functions to use jsonb under the hood, so now
behavior of our json module more like sqlite.
Found and fixed some bugs on the way.

Closes #1135
2025-03-17 18:25:28 +02:00
Diego Reis
16396c57c7 Removes unnecessary clone 2025-03-17 10:06:14 -03:00
Pere Diaz Bou
00ab3d1c0c Fix ordering and implement Deref 2025-03-17 10:22:42 +01:00
Pere Diaz Bou
20f5ade95e Experiment with a custom Lock for database header 2025-03-17 10:21:34 +01:00
Diego Reis
590f90ad9a Fix AutoCommit handling of an ongoing halt checkpoint 2025-03-16 15:35:49 -03:00
Ihor Andrianov
23d7d82b6c add jsonb_extract function 2025-03-16 15:14:29 +02:00
Ihor Andrianov
0b22fbd566 Add jsonb to json_valid 2025-03-16 03:26:08 +02:00
Pekka Enberg
731fbaf3c7 Merge 'Jsonb implementation' from Ihor Andrianov
This PR implements a complete JSONB parser and serializer as current PR
draft looks stale.
Sorry for huge PR.
I've choose a recursive parsing approach because:
1. It's simpler to understand and maintain
2. It follows SQLite's implementation pattern, ensuring compatibility
3. It naturally maps to JSON's hierarchical structure
The implementation includes comprehensive test coverage for standard
JSON features and JSON5 extensions. All test cases pass successfully,
handling edge cases like nested structures, escape sequences, and
various number formats.
While the code is ready for review, I believe it would benefit from fuzz
testing in the future to identify any edge cases not covered by the
current tests.
Ready for review, proposals and feedback.

Closes #1114
2025-03-13 21:17:52 +02:00
Pere Diaz Bou
cc320a74ca few checkpoint result cleanup in vdbe 2025-03-12 15:48:22 +01:00
Pere Diaz Bou
be3badc1f3 modify a few btree log level and add end_write_txn after checkpoint 2025-03-12 15:48:22 +01:00
Ihor Andrianov
04f69220b7 add jsonb function implementation and json now understands blobs 2025-03-12 15:03:40 +02:00
Pekka Enberg
b0636e4494 Merge 'Adds Drop Table' from Zaid Humayun
This PR adds support for `DROP TABLE` and addresses issue
https://github.com/tursodatabase/limbo/issues/894
It depends on https://github.com/tursodatabase/limbo/pull/785 being
merged in because it requires the implementation of `free_page`.
EDIT: The PR above has been merged.
It adds the following:
* an implementation for the `DropTable` AST instruction via a method
called `translate_drop_table`
* a couple of new instructions - `Destroy` and `DropTable`. The former
is to modify physical b-tree pages and the latter is to modify in-memory
structures like the schema hash table.
* `btree_destroy` on `BTreeCursor` to walk the tree of pages for this
table and place it in free list.
* state machine traversal for both `btree_destroy` and
`clear_overflow_pages` to ensure performant, correct code.
* unit & tcl tests
* modifies the `Null` instruction to follow SQLite semantics and accept
a second register. It will set all registers in this range to null. This
is required for `DROP TABLE`.
The screenshots below have a comparison of the bytecodes generated via
SQLite & Limbo.
Limbo has the same instruction set except for the subroutines which
involve opening an ephemeral table, copying over the triggers from the
`sqlite_schema` table and then re-inserting them back into the
`sqlite_schema` table.
This is because `OpenEphemeral` is still a WIP and is being tracked at
https://github.com/tursodatabase/limbo/pull/768
![Screenshot 2025-02-09 at 7 05 03 PM](https://github.com/user-
attachments/assets/1d597001-a60c-4a76-89fd-8b90881c77c9)
![Screenshot 2025-02-09 at 7 05 35 PM](https://github.com/user-
attachments/assets/ecfd2a7a-2edc-49cd-a8d1-7b4db8657444)

Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>

Closes #897
2025-03-06 18:27:41 +02:00
Pekka Enberg
2c9d30cef4 core/vdbe: Don't commit MVCC on Halt if no autocommit
Spotted by Pere.
2025-03-06 12:52:03 +02:00
Pekka Enberg
d6c514c8d1 core: Integrate MVCC to B-Tree cursor 2025-03-06 10:16:42 +02:00