Commit Graph

2988 Commits

Author SHA1 Message Date
pedrocarlo
b3351dc709 tests + adjustment to halt error message 2025-06-20 16:29:10 -03:00
pedrocarlo
9048ad398b modify loop functions to accomodate for ephemeral tables 2025-06-20 16:29:10 -03:00
pedrocarlo
74beac5ea8 ephemeral table for update when rowid is being update 2025-06-20 16:28:10 -03:00
Jussi Saurio
f396528d53 Merge 'Fix DELETE not emitting constant WhereTerms' from Pedro Muniz
Fixes DELETE not emitting conditional jumps at all if the associated
WhereTerm is a constant, e.g.
```sql
limbo> create table t(x);
limbo> explain DELETE FROM t WHERE 5-5;
addr  opcode             p1    p2    p3    p4             p5  comment
----  -----------------  ----  ----  ----  -------------  --  -------
0     Init               0     7     0                    0   Start at 7
1     OpenWrite          0     2     0                    0   root=2; t
2     Rewind             0     6     0                    0   Rewind table t
3       RowId            0     1     0                    0   r[1]=t.rowid
4       Delete           0     0     0                    0
5     Next               0     3     0                    0
6     Halt               0     0     0                    0
7     Transaction        0     1     0                    0   write=true
8     Goto               0     1     0                    0
```
I was adding more stuff to the simulator in a Branch of mine, and I
caught this error with delete. Upstreaming the fix here. As we do with
Update, I added the translation step for the `WhereTerms` of the query.
Edit: Closes #1732. Closes #1733. Closes #1734. Closes #1735. Closes
#1736. Closes #1738. Closes #1739. Closes #1740.
Edit: Also pushes constant where term translation to `init_loop` for
Update and Select as well.

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

Closes #1746
2025-06-20 22:00:32 +03:00
Jussi Saurio
c69047106c Merge 'Implement RowData opcode' from meteorgan
The `RowData` opcode is required to implement #1575.
I haven't found a ideal way to test this PR independently, but I
verified its functionality while working on #1575(to be committed soon),
and it performs effectively.

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

Closes #1756
2025-06-20 21:58:47 +03:00
Jussi Saurio
38f6b8c031 Merge 'Support indent for Goto opcode when executing explain' from meteorgan
it works as expected
```
limbo> explain insert into tb1 select * from tb2 union select * from tb3;
addr  opcode             p1    p2    p3    p4             p5  comment
----  -----------------  ----  ----  ----  -------------  --  -------
0     Init               0     29    0                    0   Start at 29
1     InitCoroutine      1     21    2                    0
2     OpenEphemeral      0     0     0                    0   cursor=0 is_table=false
3     OpenRead           1     3     0                    0   table=tb2, root=3
4     Rewind             1     9     0                    0   Rewind table tb2
5       Column           1     0     2                    0   r[2]=tb2.age
6       MakeRecord       2     1     3                    0   r[3]=mkrec(r[2..2]); for union_dedupe
7       IdxInsert        0     3     0                    0   key=r[3]
8     Next               1     5     0                    0
9     OpenRead           2     4     0                    0   table=tb3, root=4
10    Rewind             2     15    0                    0   Rewind table tb3
11      Column           2     0     2                    0   r[2]=tb3.age
12      MakeRecord       2     1     4                    0   r[4]=mkrec(r[2..2]); for union_dedupe
13      IdxInsert        0     4     0                    0   key=r[4]
14    Next               2     11    0                    0
15    Rewind             0     18    0                    0   Rewind  union_dedupe
16      Column           0     0     2                    0   r[2]=union_dedupe.age
17      Yield            1     0     0                    0
18    Next               0     16    0                    0
19    Close              0     0     0                    0
20    EndCoroutine       1     0     0                    0
21    OpenWrite          3     2     0                    0   root=2; tb1
22      Yield            1     28    0                    0
23      Copy             2     7     0                    0   r[7]=r[2]
24      NewRowid         3     6     0                    0   r[6]=rowid
25      MakeRecord       7     1     8                    0   r[8]=mkrec(r[7..7])
26      Insert           3     8     6     tb1            0   intkey=r[6] data=r[8]
27    Goto               0     22    0                    0
28    Halt               0     0     0                    0
29    Transaction        0     1     0                    0   write=true
30    Goto               0     1     0                    0
```

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

Closes #1775
2025-06-20 21:57:40 +03:00
Jussi Saurio
020f083b98 Merge 'Fix handling of non-aggregate expressions' from Piotr Rżysko
This PR has two parts:
1. The first commit refactors how information about which registers
should be populated in the aggregation loop is calculated and
propagated. This simplification revealed a bug, which is addressed as
part of the same commit (see the included test).
2. The second commit fixes incorrect behavior for queries where complex
expressions include both aggregate and non-aggregate components. For
example, the following query previously produced incorrect results:
```sql
SELECT
  CASE WHEN c0 != 'x' THEN group_concat(c1, ',') ELSE 'x' END
FROM t0
GROUP BY c0;
```
In such cases, non-aggregate columns like `c0` were not available during
the result construction for each group, leading to incorrect evaluation.

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

Closes #1780
2025-06-20 21:56:35 +03:00
Luca Muscat
7cf77fb35b Fix fuzz issue #1763 by using the log2 & log10 functions where applicable
It is easy to chalk this fuzzer issue to erratic floating point
behaviour, but this is not the case here.

Currently, `exec_math_log` calculates log with arbitrary bases by using
the following formula: `log_a(b) ~= ln(b) / ln(a)`. This calculation is
an approximation with lots of its floating point precision lost to
dividing the results of natural logarithms.

By using the specialized versions of the log functions (`log2` &
`log10`), we can avoid this loss of precision.

SQLite also uses these specialized log functions when possible, so it
doesn't hurt to do the same thing when aiming for parity.
2025-06-20 10:52:13 +02:00
Piotr Rzysko
64a0333119 Fix missing column references in non-aggregate expressions
Previously, queries like:
```
SELECT
    CASE WHEN c0 != 'x' THEN group_concat(c1, ',') ELSE 'x' END
FROM t0
GROUP BY c0;
```

would return incorrect results because c0 was not copied during the
aggregation loop into a register accessible to the logic processing the
grouped results (e.g., the CASE WHEN expression in this example).

The same issue applied to expressions in the HAVING and ORDER BY clauses.
2025-06-20 06:19:16 +02:00
Piotr Rzysko
08c1767ba7 Collect non-aggregate columns in one place
Previously, the logic for collecting non-aggregate columns was duplicated
across multiple locations and implemented inconsistently. This caused a
bug that was revealed by the refactoring in this commit (see the added
test).
2025-06-20 06:17:14 +02:00
pedrocarlo
fcff306f98 emit constant where terms in init_loop 2025-06-19 13:50:38 -03:00
pedrocarlo
b1706ae849 change location where WhereTerms are emitted 2025-06-19 13:50:38 -03:00
pedrocarlo
86ea224069 add delete where basic functionality 2025-06-19 13:50:38 -03:00
Pere Diaz Bou
65372994d4 op_transaction end_read_tx in case of begin_write_tx is busy
In case of starting a write txn, we always start by starting a read txn.
If we don't end_read_tx then it will never release locks.
2025-06-18 17:40:53 +02:00
Pere Diaz Bou
10d02525d6 introduce concurrent write test
The idea is quite simple: write with 4 concurrent writers and once all
are finsihed, check the count of rows written is correct.
2025-06-18 17:40:53 +02:00
Pere Diaz Bou
34592b172c run index tests with flags instead of ignore 2025-06-17 19:33:23 +02:00
Pere Diaz Bou
e90996783b clippy 2025-06-17 19:33:23 +02:00
Pere Diaz Bou
48ae6766d7 fix comp errors 2025-06-17 19:33:23 +02:00
Pere Diaz Bou
f91d2c5e99 fix disable in write cases 2025-06-17 19:33:23 +02:00
Pere Diaz Bou
b5f2f375b8 disable alter, delete, create index, insert and update for indexes 2025-06-17 19:33:23 +02:00
Pere Diaz Bou
bcbce15d7b disable UNION deduplication 2025-06-17 19:33:23 +02:00
Pere Diaz Bou
dde93e8deb disable distinct without index_experimental
distinct uses indexes, therefore we need to disable them
2025-06-17 19:33:23 +02:00
Pere Diaz Bou
9ae4563bcd index_experimental flag to enable index usages
Currently indexes are the bulk of the problem with `UPDATE` and
`DELETE`, while we work on fixing those it makes sense to disable
indexing since they are not stable. We want to try to make everything
else stable before we continue with indexing.
2025-06-17 19:33:23 +02:00
meteorgan
5c7d1423e7 Support indent for Goto opcode when executing explain 2025-06-17 23:55:39 +08:00
pedrocarlo
20115c1e74 return parse error when calling unimplemented pragma checkpoint modes 2025-06-17 11:42:20 -03:00
Luca Muscat
a5ac1884c1 core: Stop treating the contents of a Value::Blob as a String
By encoding a Vec<u8> (vector of bytes), a lossy conversion from a
`Vec<u8>` to a `String` occurs. The lossy conversion leads to an
incorrect hex value to be displayed.

Avoid the lossy conversion and let the `hex` crate do its thing.
2025-06-16 21:10:17 +02:00
meteorgan
caa1801ec4 cargo fmt 2025-06-16 22:09:43 +08:00
meteorgan
4f742a3a0f Implement RowData opcode 2025-06-16 22:07:35 +08:00
Pekka Enberg
db4945eada Merge 'Fix update queries to set n_changes ' from Kim Seon Woo
- `Update` query doesn't update `n_changes`. Let's make it work
- Add `InsertFlags` to add meta information related to insert operations
- For update query, add `UPDATE` flag
- Currently, the update query executes `Insn::Delete` and `Insn::Insert`
internally, it increases `n_change` by 2. So, for the update query,
let's skip increasing `n_change` for the `Insn::Insert`
https://github.com/tursodatabase/limbo/issues/1681

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

Closes #1683
2025-06-16 16:30:20 +03:00
Pekka Enberg
4496a0d08a core: Clean up integrity_check()
Suggested by Jussi.
2025-06-16 14:46:36 +03:00
Pekka Enberg
882c5ca168 Merge 'Simple integrity check on btree' from Pere Diaz Bou
This PR adds support for the instruction `IntegrityCk` which performs an
integrity check on the contents of a single table. Next PR I will try to
implement the rest of the integrity check where we would check indexes
containt correct amount of data and some more.
<img width="1151" alt="image" src="https://github.com/user-
attachments/assets/29d54148-55ba-480f-b972-e38587f0a483" />

Closes #1719
2025-06-16 13:46:26 +03:00
Pekka Enberg
dd001f9444 Merge 'Return parse error instead of corrupt error for no such table' from Pedro Muniz
This is more in line with SQLite:
```sql
sqlite> insert into t values (randomblob(1024*1024 * 6));
Parse error: no such table: t
```

Reviewed-by: Preston Thorpe (@PThorpe92)

Closes #1744
2025-06-16 11:04:50 +03:00
Pekka Enberg
90c1e3fc06 Switch Connection to use Arc instead of Rc
Connection needs to be Arc so that bindings can wrap it with `Mutex` for
multi-threading.
2025-06-16 10:43:19 +03:00
pedrocarlo
fef9add773 emit parse error instead of corrupt error for no such table 2025-06-14 18:45:23 -03:00
meteorgan
b910fd0012 drop unused code in op_column 2025-06-15 00:50:16 +08:00
Jussi Saurio
30e4511d62 Merge 'NOT NULL constraint' from Anton Harniakou
Implements basic support for `NOT NULL` contraint check.

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

Closes #1675
2025-06-13 14:25:24 +03:00
Anton Harniakou
25d0584b19 Fix typo 2025-06-13 11:57:39 +03:00
Jussi Saurio
3f90fad131 Merge 'Simulator Ast Generation + Simulator Unary Operator + Refactor to use limbo_core::Value in Simulator for massive code reuse' from Pedro Muniz
This PR is a Drop-In replacement to the Predicate defined in the
Simulator. Predicate is basically the same as our ast::Expr, but it
supports a small number of the SQL expression syntax. By creating a
NewType that wraps ast::Expr we can tap into our already mostly
correctly defined parser structs. This change will enable us to easily
add generation for more types of sql queries.
I also added an ArbitraryFrom impl for ast::Expr that can be used in a
freestyle way (for now) for differential testing.
This PR also aims to implement Unary Operator logic similar to the
Binary Operator logic we have for predicate. After this change we may
need to adjust the Logic for how some assertions are triggered.
<s>Sometimes the `Select-Select-Optimizer` property thinks that these
two queries should return the same thing:
```sql
SELECT (twinkling_winstanley.sensible_federations > x'66616e7461737469625e0f37879823db' AND twinkling_winstanley.sincere_niemeyer < -7428368947470022783) FROM twinkling_winstanley WHERE 1;

SELECT * FROM twinkling_winstanley WHERE twinkling_winstanley.sensible_federations > x'66616e7461737469625e0f37879823db' AND twinkling_winstanley.sincere_niemeyer < -7428368947470022783;
```
However after running the shrunk plan manually, the simulator was
incorrect in asserting that. Maybe this a bug a in the generation of
such a query? Not sure yet. </s>
<b>EDIT: The simulator was correctly catching a bug and I thought I was
the problem. The bug was in `exec_if` and I fixed it in this PR.</b>
I still need to expand the Unary Operator generation to other types of
predicates. For now, I just implemented it for `SimplePredicate` as I'm
trying to avoid to bloat even more this PR.
<b>EDIT: I decided to just have one PR open for all the changes I'm
making to make my life a bit easier and to avoid merge conflicts with my
own branches that I keep spawning for new code.</b>
PS: This should only be considered for merging after
https://github.com/tursodatabase/limbo/pull/1619 is merged. Then, I will
remove the draft status from this PR.

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

Closes #1674
2025-06-13 11:23:10 +03:00
PThorpe92
33b52bfb84 Replace refcel in wal sync, add counter timeout to conn close shutdown 2025-06-13 11:12:42 +03:00
PThorpe92
e134bd19da Remove close from Drop impl 2025-06-13 11:11:30 +03:00
PThorpe92
eecf6ae6e6 Wait till we write the page to increment current page in wal checkpoint 2025-06-13 11:11:30 +03:00
PThorpe92
9f966910bc Add manual wal sync before checkpoint in connection Drop 2025-06-13 11:11:30 +03:00
meteorgan
c0d260fd54 revise some comments 2025-06-13 10:39:36 +03:00
meteorgan
fd09675d8c clean up 2025-06-13 10:39:36 +03:00
meteorgan
6179d8de23 refactor compound select 2025-06-13 10:39:32 +03:00
Jussi Saurio
efed4bc07d Merge 'Complete ALTER TABLE implementation' from Levy A.
Resolves #895
- [x] `ALTER TABLE _ ADD _`
- [x] `ALTER TABLE _ DROP _`
- [x] `ALTER TABLE _ RENAME _ TO _`

Reviewed-by: Preston Thorpe (@PThorpe92)
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #1527
2025-06-13 10:23:43 +03:00
Jussi Saurio
04c590f5a6 Add comment about re-entrancy of op_idx_insert() 2025-06-12 12:36:53 +03:00
Jussi Saurio
bdbd021bbb Fix large inserts to unique indexes hanging
We were incorrectly setting `moved_before` as `false` after checking
for unique constraint violation, but the reality is that after the
uniqueness check, we are already correctly positioned -- if no match
was found, the cursor is positioned at either:

a) no row, or
b) at the first entry that is greater than the key we are inserting.

This means we don't have to move anymore and can just insert.
2025-06-12 12:25:17 +03:00
pedrocarlo
8dbf09bb42 betters instrumentation for btree operations 2025-06-11 23:34:32 -03:00
Levy A.
5d60d82499 fix: add default 2025-06-11 14:19:06 -03:00