Commit Graph

1290 Commits

Author SHA1 Message Date
Pekka Enberg
e4d7474372 core: Switch to parking_lot for RwLock
We really need to make the WAL lock less expensive, but switching to
`parking_lot` is anyway something we should do.

Before:

```
Execute `SELECT 1`/Limbo
                        time:   [56.230 ns 56.463 ns 56.688 ns]
```

After:

```
Execute `SELECT 1`/Limbo
                        time:   [52.003 ns 52.132 ns 52.287 ns]
```
2025-02-04 18:38:33 +02:00
Pekka Enberg
750164fb85 Merge 'Sqlean Time extension' from Pedro Muniz
This PR implements a sqlean time compatible extension. I would
appreciate some help to review my code and see if there are ways to
enhance it. Also, if there is some edge case, I have missed please tell
me.
https://github.com/nalgeon/sqlean/blob/main/docs/time.md

Closes #854
2025-02-04 18:27:44 +02:00
Pekka Enberg
733f7de688 Merge branch 'main' into feature/time-ext 2025-02-04 18:27:14 +02:00
Pekka Enberg
f69804969c Merge 'Adding checkpoint result' from Sonny
### What?
adding checkpoint result returning number of pages in wal and num pages
checkpointed.
Part of #696
### Context
SQLite returns in checkpoint result of calling `pragma wal_checkpoint;`
`0|3|3` while limbo returns `0|0|0`.
https://sqlite.org/pragma.html#pragma_wal_checkpoint
- 1st col: 1 (checkpoint SQLITE_BUSY) or 0 (not busy).
- 2nd col: # modified pages written to wal file
- 3rd col: # pages moved to db after checkpoint
This PR aims to add 2nd and 3rd column to the checkpoint result.
SQLite
```
sqlite3 test.db
sqlite> pragma journal_mode=wal;
wal
sqlite> pragma journal_mode;
wal
sqlite> create table t1 (id text);
sqlite> insert into t1(id) values (1),(2);
sqlite> select * from t1;
1
2
sqlite> pragma wal_checkpoint;
0|3|3
```
Limbo
```
./target/debug/limbo test.db
Limbo v0.0.13
Enter ".help" for usage hints.
limbo> pragma journal_mode;
wal
limbo> create table t1(id text);
limbo> insert into t1(id) values (1),(2);
limbo> select * from t1;
1
2
# current the 2nd and 3rd columns are hard coded in limbo to 0
limbo> pragma wal_checkpoint;
0|0|0
```

Closes #827
2025-02-04 18:26:24 +02:00
Pekka Enberg
a045866a6c Merge 'core: Fix benchmark panic if syscall is interrupted' from Pekka Enberg
Fixes the following panics:
Benchmarking Execute `SELECT * FROM users LIMIT ?`/Limbo/100: Profiling
for 5.0000 sthread 'main' panicked at core/benches/benchmark.rs:69:43:
called `Result::unwrap()` on an `Err` value: IOError(Os { code: 4, kind:
Interrupted, message: "Interrupted system call" })
note: run with `RUST_BACKTRACE=1` environment variable to display a
backtrace

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

Closes #882
2025-02-04 18:25:34 +02:00
Pekka Enberg
bf1ef13c91 Merge 'Add Printf Support' from Zaid Humayun
Add basic printf function support in limbo
![Screenshot 2025-02-04 at 8 08 23 PM](https://github.com/user-
attachments/assets/b12931eb-8e79-4c8a-af77-c25c34cc5834)

Closes #886
2025-02-04 17:53:27 +02:00
Zaid Humayun
6a863b3da9 printf: this commit adds support for https://github.com/tursodatabase/limbo/issues/885 tracking printf functionality
this commit introduces basic support for printf functionality and doesn't include advanced modifiers like width etc.
2025-02-04 20:05:14 +05:30
Pekka Enberg
31552f0862 core/json: Kill some unwrap() calls 2025-02-04 14:55:19 +02:00
Pekka Enberg
2d9a54ccba Merge 'implement json_pretty' from Pedro Muniz
This PR implements json_pretty. At the moment, support for jsonb is
being added, so this function suffers from the same limitations as in
json(x). Also, I have not found a way to implement the same conversion
of Blob -> String that SQLite does. From my own experimentation, I
believe SQLite converts blobs to a lossy ascii representation, but I
would appreciate some help on this.

Closes #860
2025-02-04 14:51:47 +02:00
Pekka Enberg
0050f4aeea Merge 'Support column aliases in GROUP BY, ORDER BY and HAVING' from Jussi Saurio
Closes #744
```sql
# Wanda = 9, Whitney = 11, William = 111
do_execsql_test column_alias_in_group_by_order_by_having {
  select first_name as fn, count(1) as fn_count from users where fn in ('Wanda', 'Whitney', 'William') group by fn having fn_count > 10 order by fn_count;
} {Whitney|11
William|111}
```

Closes #864
2025-02-04 14:51:05 +02:00
Pekka Enberg
b4a3cadf58 Merge 'Improve in-memory IO performance, remove runtime borrow checking' from Preston Thorpe
Despite likely replacing this in-memory IO setup in the near future with
a `mmap` implementation (#859) , in the spirit of everyone getting
bitten by the perf bug lately I thought I would speed up our in-memory
IO a bit.

Closes #861
2025-02-04 14:50:38 +02:00
Pekka Enberg
097e56c19f core: Kill Statement::query() method
It's a pointless wrapper on top of `step()` that introduce additional
memory allocation and deallocation.
2025-02-04 13:46:11 +02:00
Pekka Enberg
7dbfdba59f core: Fix benchmark panic if syscall is interrupted
Fixes the following panics:

Benchmarking Execute `SELECT * FROM users LIMIT ?`/Limbo/100: Profiling for 5.0000 sthread 'main' panicked at core/benches/benchmark.rs:69:43:
called `Result::unwrap()` on an `Err` value: IOError(Os { code: 4, kind: Interrupted, message: "Interrupted system call" })
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
2025-02-04 13:24:55 +02:00
Pekka Enberg
fb0a560d76 Merge 'dont store insn comments unless the query is EXPLAIN' from Jussi Saurio
We spend a lot of time especially in `GROUP BY` queries providing
helpful comments for `EXPLAIN`, even when the query is not an `EXPLAIN`.
So let's not do that
Closes #784
```sql
Prepare `SELECT first_name, count(1) FROM users GROUP BY first_name HAVING count(1) > 1 ORDER BY cou...
                        time:   [4.2724 µs 4.2783 µs 4.2848 µs]
                        change: [-6.1063% -5.7376% -5.3626%] (p = 0.00 < 0.05)
                        Performance has improved.
```
doesn't affect the other trivial prepare benchmarks

Closes #875
2025-02-04 13:10:37 +02:00
Pekka Enberg
da96072780 Merge 'Lower ownership requirement for Value' from Levy A.
If you have a `&str` you would need to allocate and copy the string just
to pass a reference to it again. Same goes if you have a slice of bytes.
In all (most?) situations, that is not what you want and sometimes
impossible to satisfy. Example:
```rs
impl From<&str> for Value<'_> {
    fn from(value: &str) -> Self {
        Self::Text(&value.to_owned())
    }
}
```
Here, there is no way to pass a reference to a `String` without making
the lifetime `'static`, since the string has to be dropped by the end of
the function or leaked. I would consider this a anti-pattern. There is
no reason to keep a shared reference to a owned value. (And can't think
of any situation where you would need such thing)
Now, this is possible:
```rs
impl<'a> From<&'a str> for Value<'a> {
    fn from(value: &'a str) -> Self {
        Self::Text(value)
    }
}
```

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

Closes #838
2025-02-04 13:10:10 +02:00
Levy A.
9df0b01689 refactor: lower ownership requirement 2025-02-03 16:52:42 -03:00
Jussi Saurio
1f888fea4f Dont fsync the WAL on read queries 2025-02-03 20:42:50 +02:00
Jussi Saurio
d182ddf514 dont store insn comments unless the query is EXPLAIN 2025-02-03 19:53:33 +02:00
sonhmai
022a8d7a83 core: return checkpoint result 2025-02-03 19:02:16 +07:00
sonhmai
1c803aa079 feat: add wal checkpoint result 2025-02-03 18:57:22 +07:00
Jussi Saurio
d4cb0a1223 Merge 'Fix logical codegen' from Nikita Sivukhin
Fix few logical codegen issues and add fuzz tests for logical
expressions
-  Right now Limbo fails to recognize `false` constant in case when any
unary operator is used on the AST path. This PR add unary operator
option in the rewrite code and handle such cases properly.
```sql
limbo> SELECT NOT FALSE;

  × Parse error: no such column: FALSE - should this be a string literal in single-quotes?

```
- `ifnull` implementation produced incorrect codegen due to "careless"
management of registers
```
limbo> SELECT ifnull(0, NOT 0)
[NULL here]
```
- `like` implementation produced incorrect codegen due to "careless"
management of registers
```
limbo> SELECT like('a%', 'a') = 1;
thread 'main' panicked at core/vdbe/mod.rs:1902:41:
internal error: entered unreachable code: Like on non-text registers
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
Depends on https://github.com/tursodatabase/limbo/pull/867 (need
`GrammarGenerator` from this branch)

Closes #869
2025-02-03 12:39:41 +02:00
Jussi Saurio
d41dfd0c5d Merge 'Fix rowid search codegen' from Nikita Sivukhin
This PR fixes a bug when index search used incorrect operator if index
column were the "rhs" in the expression (not "lhs" as usual, e.g.
`SELECT * FROM t WHERE 1 < rowid_alias`)

Reviewed-by: Jussi Saurio (@jussisaurio)

Closes #870
2025-02-03 12:38:04 +02:00
Jussi Saurio
1e5501650a Support column aliases in GROUP BY, ORDER BY and HAVING 2025-02-03 10:44:05 +02:00
Nikita Sivukhin
979612cb34 fix miscompilation of like function 2025-02-03 11:25:14 +04:00
Nikita Sivukhin
11c47f5e44 fix miscomplation of ifnull scalar function 2025-02-03 11:25:14 +04:00
Nikita Sivukhin
a4a80f37bc rewrite unary expressions too - in order to support "NOT FALSE" expressions 2025-02-03 11:25:14 +04:00
Nikita Sivukhin
5a3587f7a2 use opposite operator for search if WHERE condition is swapped (e.g. 1 > x instead of x < 1) 2025-02-03 11:23:04 +04:00
Pekka Enberg
9458d1ed14 Merge 'Fix shr instruction' from Nikita Sivukhin
This PR fixes implementation of binary shift right/left instructions.
Before there were a minor incompatibility between limbo and sqlite
implementation in case when right shift second argument were more than
64 and first argument were negative. As sqlite implementation of right
binary shift is sign-extended - so `-1` should be returned in such case
when limbo returned zero.
This PR fixes this bug and also introduce a fuzz tests for arithemtic
expressions. This fuzz test were written with a help of
`GrammarGenerator` which allows to easily define probabilistic context-
free grammar and then later sample random strings from it.

Closes #867
2025-02-03 09:22:39 +02:00
Pekka Enberg
7257fb8aae Merge 'core: move pragma statement bytecode generator to its own file.' from Sonny
What?
- no logic change
- refactored and moved pragma statement bytecode generation to its own
package to better structure.

Closes #871
2025-02-03 09:10:33 +02:00
Pekka Enberg
6c34737240 Merge 'Fix rowid generation' from Nikita Sivukhin
Fix panic in case when table has row with rowid equals to `-1`
(`=u64::max`)
```sql
limbo> CREATE TABLE t(x INTEGER PRIMARY KEY)
limbo> INSERT INTO t VALUES (-1)
limbo> INSERT INTO t VALUES (NULL);
thread 'main' panicked at core/vdbe/mod.rs:2499:21:
attempt to add with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

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

Closes #868
2025-02-03 09:09:12 +02:00
Pekka Enberg
662d629666 Rename JoinAwareConditionExpr to WhereTerm
We transform all JOIN conditions into WHERE clause terms in the query
planner. The JoinAwareConditionExpr name tries to make that point, but I
think it makes things more confusing. Let's call it WhereTerm (suggested
by Jussi).
2025-02-03 07:46:51 +02:00
sonhmai
2d4bf2eb62 core: move pragma statement bytecode generator to its own file. 2025-02-03 09:21:14 +07:00
Nikita Sivukhin
2b9220992d fix attempt to add with overflow crash in case of rowid auto-generation 2025-02-02 20:10:58 +04:00
Nikita Sivukhin
43c9fc3c5c fix binary shift implementation 2025-02-02 19:24:22 +04:00
Nikita Sivukhin
2c958d7e2d derive Debug trait for limbo step result 2025-02-02 14:11:41 +04:00
Jussi Saurio
c18c6ad64d Marginal changes to use new data structures and field names 2025-02-02 10:18:13 +02:00
Jussi Saurio
82a2850de9 subquery.rs: use iteration instead of recursion and simplify 2025-02-02 10:18:13 +02:00
Jussi Saurio
98439cd936 optimizer.rs: refactor to use new data structures and remove unnecessary stuff
We don't need `push_predicates()` because that never REALLY was a predicate
pushdown optimization -- it just pushed WHERE clause condition expressions
into the correct SourceOperator nodes in the tree.

Now that we don't have a SourceOperator tree anymore and we keep the conditions
in the WHERE clause instead, we don't need to "push" anything anymore. Leaves
room for ACTUAL predicate pushdown optimizations later :)

We also don't need any weird bitmask stuff anymore, and perhaps we never did,
to determine where conditions should be evaluated.
2025-02-02 10:18:13 +02:00
Jussi Saurio
89fba9305a main_loop.rs: use iteration instead of recursion
Now that we do not have a tree of SourceOperators but rather
a Vec of TableReferences, we can just use loops instead of
recursion for handling the main query loop.
2025-02-02 10:18:13 +02:00
Jussi Saurio
09b6bad0af delete.rs: use new data structures when parsing delete 2025-02-02 10:18:13 +02:00
Jussi Saurio
2ddac4bf21 select.rs: use new data structures when parsing select 2025-02-02 10:18:13 +02:00
Jussi Saurio
16a97d3b98 planner.rs: refactor from/join + where parsing logic
- use new TableReference and JoinAwareConditionExpr
- add utilities for determining at which loop depth a
  WHERE condition should be evaluated, now that "operators"
  do not carry condition expressions inside them anymore.
2025-02-02 10:18:13 +02:00
Jussi Saurio
e63256f657 Change Display implementation of Plan to work with new data structures 2025-02-02 10:18:13 +02:00
Jussi Saurio
390d0e673f plan.rs: refactor data structures
- Get rid of SourceOperator tree
- Make plan have a Vec of TableReference, and TableReference now
  contains the information from the old SourceOperator.
- Remove `predicates` (conditions) from Table References -- put
  everything in the WHERE clause like SQLite, and attach metadata
  to the where clause expressions with JoinAwareConditionExpr struct.
- Refactor select_star() to be simpler now that we use a vec, not a tree
2025-02-02 10:18:13 +02:00
Pekka Enberg
dbb7d1a6ba Merge 'Pagecount' from Glauber Costa
This PR implements the Pagecount pragma, as well as its associated
bytecode opcode

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

Closes #819
2025-02-02 09:32:18 +02:00
PThorpe92
b5a5b34329 Use Cell for size in memoryio in place of unsafecell 2025-02-01 23:04:42 -05:00
PThorpe92
5c00b3dc6e Improve in-memory IO performance, remove runtime borrow checking 2025-02-01 21:54:39 -05:00
pedrocarlo
2e115d948d implement json_pretty 2025-02-01 23:04:46 -03:00
Glauber Costa
a3387cfd5f implement the pragma page_count
To do that, we also have to implement the vdbe opcode Pagecount.
2025-02-01 19:39:46 -05:00
Nikita Sivukhin
1bd8b4ef7a pass null_eq flag for instructions generated for expressions (not in the conditions) 2025-02-02 02:51:51 +04:00