Commit Graph

598 Commits

Author SHA1 Message Date
Jorge Hermo
fa8eb9549a Merge with main 2025-01-15 22:10:35 +01:00
Levy A.
9b8722f38e refactor: more well rounded implementation
`?0` parameters are now handled by the parser.
2025-01-15 16:53:26 -03:00
Levy A.
5de2694834 feat: more parameter support
add `Statement::{parameter_index, parameter_name, parameter_count,
bind_at}`. some refactoring is still needed, this is quite a rough
iteration
2025-01-15 16:51:04 -03:00
Levy A.
d3582a382f fix: small bugs 2025-01-15 16:51:04 -03:00
Levy A.
08c8c655e9 feat: initial implementation of Statement::bind 2025-01-15 16:51:04 -03:00
psvri
845de125db Align MustBeInt logic with sqlite 2025-01-16 00:09:45 +05:30
psvri
d3f28c51f4 Implement ShiftRight 2025-01-15 21:21:51 +05:30
psvri
5b4d82abbf Implement ShiftLeft 2025-01-15 18:54:07 +05:30
PThorpe92
23d9d09b70 Add load_extension function, resolve shared lib extensions 2025-01-14 12:01:07 -05:00
PThorpe92
98eff6cf7a Enable passing arguments to external functions 2025-01-14 07:20:50 -05:00
PThorpe92
3412a3d4c2 Rough design for extension api/draft extension 2025-01-14 07:20:48 -05:00
PThorpe92
0a10d893d9 Sketch out runtime extension loading 2025-01-14 07:18:07 -05:00
Jorge Hermo
20566919a4 fix: compilation in CI 2025-01-13 23:19:57 +01:00
Jorge Hermo
c1702b34eb Merge with main 2025-01-13 22:21:13 +01:00
Jorge Hermo
df3123e128 Merge with main 2025-01-13 22:20:17 +01:00
Pekka Enberg
44550ab749 cargo fmt 2025-01-13 18:58:40 +02:00
Pekka Enberg
c7ea2393b3 Merge 'Store cursor types in program state and remove trait Cursor' from Jussi Saurio
I was planning on starting work on index insertion, but realized we need
to know whether our cursor refers to a table or an index etc., so it
resulted in this refactoring work.
- `cursor_ref` now contains what _type_ of cursor it is (table, index,
pseudo, sorter)
- `program.cursors` is now `program.btree_table_cursors`,
`program.btree_index_cursors` etc and they are unboxed because dynamic
dispatch is no longer necessary
- Cursor trait removed -- 95% of the shit was btree specific anyway, so
I just moved them to `BTreeCursor`. In certain instructions in the VDBE
we expect a btree cursor and in others we expect a pseudo/sorter etc,
lets make that explicit.
- I also removed `BTreeCursor::get_new_rowid()` specific tests that
required macros to generate a mock implementation of the `Cursor` trait
-- main reason is I couldn't figure out how to reimplement this without
the trait, and the second reason is that I don't think we really need
those tests, AND the proc macro is constantly failing in my editor as
well and screwing up `rust-analyzer`

Closes #655
2025-01-13 18:40:46 +02:00
Pekka Enberg
1e94dbffcc Merge branch 'main' into json-error-position 2025-01-13 18:21:37 +02:00
Jorge Hermo
3785e7c7f8 feat: initial json_object implementation 2025-01-13 01:09:48 +01:00
Jorge Hermo
016d9d17ab refactor: json functions vdbe 2025-01-13 00:05:14 +01:00
Jussi Saurio
92888c54e9 remove get_new_rowid() specific tests that require mocking 2025-01-11 17:41:10 +02:00
Jussi Saurio
bf48c0ae72 Remove trait Cursor 2025-01-11 17:19:25 +02:00
Jussi Saurio
9909539b9d Store cursor type (table,index,pseudo,sorter) when allocating cursor 2025-01-11 17:04:16 +02:00
Peter Sooley
b5fed15997 implement json_error_position 2025-01-10 11:12:30 -08:00
Kacper Madej
536fbe9d9e Fix imports 2025-01-10 12:24:08 +07:00
Kacper Madej
743a8b2d94 Merge branch 'main' into right-arrow-json 2025-01-10 11:28:13 +07:00
Kacper Madej
dd533414ef Implement -> and ->> operators for json 2025-01-09 15:38:32 +07:00
Kacper Madej
eebf9bfaac Implement json_type 2025-01-09 11:29:17 +07:00
Jussi Saurio
731ff1480f Simplify working with labels
TLDR: no need to call either of:

program.emit_insn_with_label_dependency() -> just call program.emit_insn()
program.defer_label_resolution() -> just call program.resolve_label()

Changes:

- make BranchOffset an explicit enum (Label, Offset, Placeholder)
- remove program.emit_insn_with_label_dependency() - label dependency is automatically detected
- for label to offset mapping, use a hashmap from label(negative i32) to offset (positive u32)
- resolve all labels in program.build()
- remove program.defer_label_resolution() - all labels are resolved in build()
2025-01-07 12:53:10 +02:00
PThorpe92
ca428b3dda Julianday function and additional tests/comments 2025-01-04 10:42:34 -05:00
PThorpe92
7c4a780cc2 Add DateTime func and support more modifiers 2025-01-04 08:41:03 -05:00
Jussi Saurio
1b61749c0f feat/core/translate: create automatic index in CREATE TABLE when necessary 2025-01-04 13:54:44 +02:00
Pekka Enberg
bd5f081ea8 Merge 'Add support for changes() and total_changes() functions' from Lemon-Peppermint
#525
- Adds the necessary `ScalarFunc` variants to support the `changes()` &
`total_changes()` SQLite function.
- Adds the necessary fields to the `Connection` struct to track changes.
- Modify the `InsertAwait` OpCode behaviour to affect the changes
counter.

Closes #589
2025-01-04 10:14:06 +02:00
Jussi Saurio
a934ead904 Merge 'Json extract' from Kacper Madej
Implements the `json_extract` function.
In the meantime, the json path has already been implemented by
@petersooley in https://github.com/tursodatabase/limbo/pull/555 which is
a requirement for `json_extract`.
However, this PR takes a different approach and parses the JSON path
using the JSON grammar, because there are a lot of quirks in how a JSON
`key` can look (see the JSON grammar in the Pest file).
The downside is that it allocates more memory than the current
implementation, but might be easier to maintain in the long run.
I included a lot of tests with some quirky behavior of the
`json_extract` (some of them still need some work). I also noticed that
these changed between sqlite versions (had `SQLite 3.43.2` locally and
`3.45` gave different results). Due to this, I'm not sure how much value
there is in trying to be fully compatible with SQLite. Perhaps the
approach taken by @petersooley solves 99% of use-cases?

Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #524
2025-01-03 23:53:29 +02:00
Lemon-Peppermint
9109dbf8ec Add changes tracking to the 'Connection' struct + 'Insn::InsertAwait' now affects changes counter 2025-01-03 00:04:20 +02:00
Lemon-Peppermint
abd8e6af43 Add early 'changes()' & 'total_changes()' support 2025-01-02 23:35:19 +02:00
Pekka Enberg
90d01f468f Merge 'Support uncorrelated FROM clause subqueries' from Jussi Saurio
I will warn that this PR is quite big out of necessity, since subqueries
are, as the name implies, queries within queries, so everything that
works with a regular query should also work with a subquery, roughly
speaking.
---
- Adds support for:
    * uncorrelated subqueries in FROM clause (i.e. appear as a "table",
and do not refer to outer tables). Example of this at the end of the PR
description.
    * column and subquery aliasing (`select sub.renamed from (select
name as renamed from products) sub`)
    * inner and outer filtering of subqueries (`select sub.name from
(select name from products where name = 'joe') sub`, and,  `select
sub.name from (select name from products) sub where sub.name = 'joe'`)
    * joining between regular tables and subqueries
    * joining between multiple subqueries
    * in general working with subqueries should roughly equal working
with regular tables
- Main idea: subqueries are just wrappers of a `SelectPlan` that never
emit ResultRows, instead they `Yield` control back to the parent query,
and the parent query can copy the subquery result values into a
ResultRow. New variant `SourceOperator::Subquery` that wraps a subquery
`SelectPlan`.
- Plans can now not only refer to btree tables (`select p.name from
products`) but also subqueries (`select sub.foo from (select name as foo
from products) sub`. Hence this PR also adds support for column aliases
which didn't exist before.
    * An `Expr::Column` that refers to a regular table will result in an
`Insn::Column` (i.e. a read from disk/memory) whereas an `Expr::Column`
that refers to a subquery will result in an `Insn::Copy` (from register
to register) instead
- Subquery handling is entirely unoptimized, there's no predicate
pushdown from outer query to subqueries, or elimination of redundant
subqueries (e.g. in the trivial example `SELECT * FROM (SELECT * FROM
users) sub` the subquery can just be entirely removed)
---
This PR does not add support (yet) for:
- subqueries in result columns: `SELECT t.foo, (SELECT .......) as
column_from_subquery FROM t`
- subqueries in WHERE clauses e.g. `SELECT * FROM t1 WHERE t1.foo IN
(SELECT ...)`
- subquery-related optimizations, of which there are plenty available.
No analysis is done regarding e.g. whether predicates on the outer query
level could be pushed into the subquery, or whether the subquery could
be entirely eliminated. Both of the above can probably be done fairly
easily for a bunch of trivial cases.
---
Example bytecode with comments added:
```
limbo> EXPLAIN SELECT p.name, sub.funny_name FROM products p JOIN (
  select id, concat(name, '-lol') as funny_name from products
) sub USING (id) LIMIT 3;

addr  opcode             p1    p2    p3    p4             p5  comment
----  -----------------  ----  ----  ----  -------------  --  -------
0     Init               0     31    0                    0   Start at 31

// Coroutine implementation starts at insn 2, jump immediately to 14
1     InitCoroutine      1     14    2                    0

2     OpenReadAsync      0     3     0                    0   table=products, root=3
3     OpenReadAwait      0     0     0                    0
4     RewindAsync        0     0     0                    0
5     RewindAwait        0     13    0                    0   Rewind table products
6       RowId            0     2     0                    0   r[2]=products.rowid
7       Column           0     1     4                    0   r[4]=products.name
8       String8          0     5     0     -lol           0   r[5]='-lol'
9       Function         0     4     3     concat         0   r[3]=func(r[4..5])

// jump back to main loop of query (insn 20)
10      Yield            1     0     0                    0

11    NextAsync          0     0     0                    0
12    NextAwait          0     6     0                    0
13    EndCoroutine       1     0     0                    0
14    OpenReadAsync      1     3     0                    0   table=p, root=3
15    OpenReadAwait      0     0     0                    0
16    RewindAsync        1     0     0                    0
17    RewindAwait        1     30    0                    0   Rewind table p

// Since this subquery is the inner loop of the join, reinitialize it on every iteration of the outer loop
18      InitCoroutine    1     0     2                    0

// Jump back to the subquery implementation to assign another row into registers
19      Yield            1     28    0                    0

20      RowId            1     8     0                    0   r[8]=p.rowid

// Copy sub.id
21      Copy             2     9     0                    0   r[9]=r[2]

// p.id == sub.id?
22      Ne               8     9     27                   0   if r[8]!=r[9] goto 27
23      Column           1     1     6                    0   r[6]=p.name

// copy sub.funny_name
24      Copy             3     7     0                    0   r[7]=r[3]

25      ResultRow        6     2     0                    0   output=r[6..7]
26      DecrJumpZero     10    30    0                    0   if (--r[10]==0) goto 30
27      Goto             0     19    0                    0
28    NextAsync          1     0     0                    0
29    NextAwait          1     18    0                    0
30    Halt               0     0     0                    0
31    Transaction        0     0     0                    0
32    Integer            3     10    0                    0   r[10]=3
33    Goto               0     1     0                    0
```

Closes #566
2025-01-02 11:15:07 +02:00
Kacper Madej
4fc1b66225 Merge branch 'main' into json-extract 2025-01-02 15:04:16 +07:00
Jussi Saurio
df6c8c9dd1 comment about yield instruction 2025-01-01 08:22:47 +02:00
Jussi Saurio
776ffc6131 assert instead of fallback 2025-01-01 08:21:20 +02:00
Jussi Saurio
3e5be21707 remove commented out code 2025-01-01 08:18:49 +02:00
PThorpe92
ed95007298 Separate exec insns to individual functions 2024-12-31 07:55:40 -05:00
PThorpe92
d572089b80 Refactor out repetitive agg_func code in vdbe 2024-12-31 07:53:55 -05:00
Jussi Saurio
2066475e03 feat: subqueries in FROM clause 2024-12-31 14:18:29 +02:00
Pekka Enberg
0aabcddf18 ext/uuid: Convert uuid4() to external function 2024-12-31 13:56:32 +02:00
Pekka Enberg
33dbd6c892 core: External functions 2024-12-31 13:56:32 +02:00
Kacper Madej
692301e72c Merge branch 'main' into json-extract 2024-12-31 15:53:08 +07:00
Kacper Madej
2e730ead25 Merge branch 'main' into json-extract 2024-12-31 15:41:18 +07:00
Pekka Enberg
80e12dfbf7 Merge 'Fixes glob giving wrong results in some cases ' from Vrishabh
Fixes #577
With the previous implementation we weren't escaping the regex meta
characters . And in certain cases glob had a different meaning than
regex.
For e.g , the below shows a glob pattern with its regex equivalent
- `[][]` translates to `[\]\[]`
- `[^][]` translates to `[^\]\[]`

Closes #578
2024-12-31 10:31:49 +02:00
Kacper Madej
ad9acf7400 Add support for json_extract 2024-12-31 15:11:36 +07:00