Commit Graph

3518 Commits

Author SHA1 Message Date
Pekka Enberg
e0c414f9dd Merge 'Introduce libFuzzer' from Levy A.
This PR introduces structured fuzzing with
[libFuzzer](https://llvm.org/docs/LibFuzzer.html). The expression target
implementation is not complete, but already found a compatibility issue.
More fuzzing targets should be moved from `tests/fuzz` to `fuzz` and
benefit from more advanced fuzzing techniques.
- [x] Add fuzzing guide to `README.md`
   - Install `cargo-fuzz`.
   - Use the nightly version of cargo with the `fuzz` dev shell or use
rustup to switch versions.
   - Run `cargo fuzz run ...`
- [x] Add all binary operations.
# 🐞 Bugs
Compatibility issue found when trying to `select ?` with a `NaN` value.
Sqlite returns `NULL`, while Limbo returns `NaN` (reasonable, but
incompatible).
```
thread '<unnamed>' panicked at fuzz_targets/expression.rs:130:5:
assertion `left == right` failed
  left: Null
 right: Float(NaN)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
==59288== ERROR: libFuzzer: deadly signal
    #0 0x00010564c0f0 in __sanitizer_print_stack_trace+0x28 (librustc-nightly_rt.asan.dylib:arm64+0x5c0f0)
    #1 0x0001024e7b64 in fuzzer::PrintStackTrace()+0x30 (expression:arm64+0x101c53b64)
    #2 0x0001024da650 in fuzzer::Fuzzer::CrashCallback()+0x60 (expression:arm64+0x101c46650)
    #3 0x000195fa6de0 in _sigtramp+0x34 (libsystem_platform.dylib:arm64+0x3de0)
    #4 0x000195f6ff6c in pthread_kill+0x11c (libsystem_pthread.dylib:arm64+0x6f6c)
    #5 0x000195e7c904 in abort+0x7c (libsystem_c.dylib:arm64+0x79904)
    #6 0x000102580990 in std::sys::pal::unix::abort_internal::hd275d720c474f43c+0x8 (expression:arm64+0x101cec990)
    #7 0x000102621604 in std::process::abort::h62d9ecef2f17e944+0x8 (expression:arm64+0x101d8d604)
    #8 0x0001024d93bc in libfuzzer_sys::initialize::_$u7b$$u7b$closure$u7d$$u7d$::h3b4b43a8f9432830+0xb8 (expression:arm64+0x101c453bc)
    #9 0x000102577de0 in std::panicking::rust_panic_with_hook::h19683f6fd94fb24c+0x2b8 (expression:arm64+0x101ce3de0)
    #10 0x000102577970 in std::panicking::begin_panic_handler::_$u7b$$u7b$closure$u7d$$u7d$::h4e98e5e8777eac5e+0x8c (expression:arm64+0x101ce3970)
    #11 0x0001025754e0 in std::sys::backtrace::__rust_end_short_backtrace::h12a2d70ebc9128b2+0x8 (expression:arm64+0x101ce14e0)
    #12 0x000102577628 in rust_begin_unwind+0x1c (expression:arm64+0x101ce3628)
    #13 0x000102623340 in core::panicking::panic_fmt::h8c4d74b8e5179d60+0x1c (expression:arm64+0x101d8f340)
    #14 0x0001026236cc in core::panicking::assert_failed_inner::he8fd1f85d57f866a+0x104 (expression:arm64+0x101d8f6cc)
    #15 0x0001025c73dc in core::panicking::assert_failed::h3e7590b91d46bff9 panicking.rs:364
    #16 0x000100930910 in expression::do_fuzz::hfcf5c5e5fde1a31c expression.rs:130
    #17 0x0001009373fc in rust_fuzzer_test_input lib.rs:359
    #18 0x0001024d2f34 in std::panicking::try::do_call::hce6ebc856827ae8b+0xc4 (expression:arm64+0x101c3ef34)
    #19 0x0001024d9624 in __rust_try+0x18 (expression:arm64+0x101c45624)
    #20 0x0001024d896c in LLVMFuzzerTestOneInput+0x16c (expression:arm64+0x101c4496c)
    #21 0x0001024dc3cc in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long)+0x148 (expression:arm64+0x101c483cc)
    #22 0x0001024db8dc in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*)+0x58 (expression:arm64+0x101c478dc)
    #23 0x0001024dd920 in fuzzer::Fuzzer::MutateAndTestOne()+0x258 (expression:arm64+0x101c49920)
    #24 0x0001024de908 in fuzzer::Fuzzer::Loop(std::__1::vector<fuzzer::SizedFile, std::__1::allocator<fuzzer::SizedFile>>&)+0x38c (expression:arm64+0x101c4a908)
    #25 0x0001024fd120 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long))+0x1bac (expression:arm64+0x101c69120)
    #26 0x00010250d884 in main+0x34 (expression:arm64+0x101c79884)
    #27 0x000195bf0270  (<unknown module>)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 3 CopyPart-ShuffleBytes-CrossOver-; base unit: a36928cfe783d55be82d526168a2da57372fdfdc
0xff,0xfd,0xff,0x3f,0x87,0x0,0x6e,0x6f,0x77,0x48,0x48,0x48,0xff,0x48,0xff,0xff,0x5b,0xff,0x5b,
\377\375\377?\207\000nowHHH\377H\377\377[\377[
artifact_prefix='/Users/levy/Documents/limbo/fuzz/artifacts/expression/'; Test unit written to /Users/levy/Documents/limbo/fuzz/artifacts/expression/crash-63bfc8813b82bd8b97c557650289a6bc2c055ca5
Base64: //3/P4cAbm93SEhI/0j//1v/Ww==

────────────────────────────────────────────────────────────────────────────────

Failing input:

        artifacts/expression/crash-63bfc8813b82bd8b97c557650289a6bc2c055ca5

Output of `std::fmt::Debug`:

        Value(
            Real(
                NaN,
            ),
        )

Reproduce with:

        cargo fuzz run expression artifacts/expression/crash-63bfc8813b82bd8b97c557650289a6bc2c055ca5

Minimize test case with:

        cargo fuzz tmin expression artifacts/expression/crash-63bfc8813b82bd8b97c557650289a6bc2c055ca5

────────────────────────────────────────────────────────────────────────────────
```

Reviewed-by: Preston Thorpe (@PThorpe92)
Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>

Closes #1116
2025-03-26 18:36:39 +02:00
Pekka Enberg
114847415b Merge 'WAL frame checksum support' from Daniel Boll
closes #1151

Closes #1184
2025-03-26 17:48:52 +02:00
Daniel Boll
c2a2dfa67b Remove unused imports and handle WAL header read error
Refactor random number generation for WAL header salts
2025-03-26 11:31:29 -03:00
Pekka Enberg
fca643641c Merge 'Fix compute_shl negate with overflow' from Krishna Vishal
Fixes #1156
- Changed `compute_shl` implementation to handle negation with overflow.
- Added TCL tests.

Closes #1171
2025-03-26 16:08:59 +02:00
Pekka Enberg
3cb8cda746 Merge 'Unary + is a noop' from Levy A.
Fixes #1154.
Unary `+` is a noop in Sqlite: <https://sqlite.org/lang_expr.html#operat
ors_and_parse_affecting_attributes>.

Closes #1177
2025-03-26 15:59:45 +02:00
Pekka Enberg
96ab7938a8 github: Bump JavaScript workflow timeout to 20 minutes 2025-03-26 15:59:00 +02:00
Pekka Enberg
d6de99a7bb Merge 'Initial JavaScript bindings with napi-rs' from Pekka Enberg
Closes #1183
2025-03-26 13:36:19 +02:00
Pekka Enberg
9ef729f81c Initial JavaScript bindings with napi-rs 2025-03-26 13:30:13 +02:00
Levy A.
5eae685fa8 add tests 2025-03-26 07:04:03 -03:00
Daniel Boll
4ea3faf0f0 Remove unnecessary TODO comment in wal.rs 2025-03-25 21:46:17 -03:00
Daniel Boll
6d42d6d485 Remove commented-out code and update min_frame assignment 2025-03-25 21:44:18 -03:00
Daniel Boll
5fc9ccdc8c Update checkpoint result initialization and WAL frame handling
- Use `CheckpointResult::default()` instead of `CheckpointResult::new()`
- Correct WAL frame header salt and checksum handling
- Ensure frame ID is 1-based and adjust frame offset calculation
- Add `Default` implementation for `CheckpointResult`
- Use random values for WAL header salts
2025-03-25 21:38:12 -03:00
Pekka Enberg
79620946c1 Merge 'JSON cache' from Ihor Andrianov
SQLite uses a similar approach for operations where up to 4 JSON objects
are accessed multiple times in a single query.
`SELECT json_extact(a, 'some_path'), json_remove(a, 'some_path')
json_set(a, 'some_path', 'some_value') from t;`

Closes #1163
2025-03-25 18:11:33 +02:00
Pekka Enberg
920b2efe31 Merge 'Bump rusqlite to 0.34' from Pere Diaz Bou
Closes #1175
2025-03-25 18:09:18 +02:00
Levy A.
dd10fb13a7 fix: unary + is a noop 2025-03-25 11:43:19 -03:00
Pere Diaz Bou
004dc374b2 bump rusqlite to 0.34 2025-03-25 14:17:31 +01:00
Pekka Enberg
28919038f1 Merge 'core: Rename FileStorage to DatabaseFile' from Pekka Enberg
Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>

Closes #1174
2025-03-25 11:35:00 +02:00
Pekka Enberg
df6af6ed79 core: Rename FileStorage to DatabaseFile 2025-03-25 11:15:16 +02:00
Pekka Enberg
1f29e1fe08 Add PyPI link to README 2025-03-25 09:49:44 +02:00
Pekka Enberg
b507ac401d Merge 'Fix a typo in README.md' from Tshepang Mbambo
Closes #1173
2025-03-25 09:31:05 +02:00
Pekka Enberg
93c0a29611 Merge 'Fix platform specific FFI C pointer type casts' from Preston Thorpe
Fixes #1159

Closes #1170
2025-03-25 09:10:16 +02:00
Pekka Enberg
731c3f037a Merge 'Improve Python bindings' from Diego Reis
Yet another PR to close #494.
While testing the code provided in the issue I noticed that it wasn't
closing the connection as it should, leading to lifetime issues like:
`Connection is unsendable, but is being dropped on another thread`. The
following code works fine:
```python
import limbo

def main():
    con = limbo.connect("test.db")
    cur = con.cursor()

    try:
        cur.execute("""
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                username TEXT NOT NULL,
                email TEXT NOT NULL,
                role TEXT NOT NULL,
                created_at DATETIME NOT NULL DEFAULT (datetime('now'))
            )
        """)

        # Insert some sample data
        sample_users = [
            ("alice", "alice@example.com", "admin"),
            ("bob", "bob@example.com", "user"),
            ("charlie", "charlie@example.com", "moderator"),
            ("diana", "diana@example.com", "user")
        ]

        for username, email, role in sample_users:
            cur.execute("""
                INSERT INTO users (username, email, role)
                VALUES (?, ?, ?)
            """, (username, email, role))

        con.commit()

        # Query the table
        res = cur.execute("SELECT * FROM users")
        record = res.fetchone()
        print(record)

    finally:
        # Ensure connection is closed on the same thread <----
        con.close()
        pass

main()
```
You can test it [here](https://colab.research.google.com/drive/1NJau6Y9H
TRJrnYK_xp2AzwP_qEH8VsQx?usp=sharing)
To address these issues, this PR:
- Adds support for `with statement` a common resource management pattern
in Python;
- Close connection if it is dropped

Closes #1164
2025-03-25 09:08:01 +02:00
Tshepang Mbambo
8b48c4b7b7 readme: typo 2025-03-25 09:06:40 +02:00
krishvishal
1660ae5542 missed adding _ and a space. 2025-03-25 12:04:48 +05:30
krishvishal
785be8479f Fix a fuzzer failure and add tcl test covering the failure 2025-03-25 11:43:51 +05:30
krishvishal
f12e3a6993 For a few TCL tests more. 2025-03-25 10:28:48 +05:30
krishvishal
a8129d5e58 Add TCL tests for compute_shl 2025-03-25 10:26:08 +05:30
krishvishal
b55dc586bd change compute_shl implementation to handle negation with overflow 2025-03-25 10:10:15 +05:30
PThorpe92
e9420e7d2b Fix platform specific ffi c ptr types 2025-03-24 22:48:07 -04:00
Diego Reis
160d48d34e ext/python: Workaround to file permission error
To get more info see:
https://github.com/tursodatabase/limbo/actions/runs/14039536389/job/39312362848
2025-03-24 16:39:24 -03:00
Diego Reis
6edf3dd3b1 ext/python: Makes linter happy 2025-03-24 12:40:59 -03:00
Diego Reis
9a8970b6a8 ext/python: Update example 2025-03-24 12:21:30 -03:00
Diego Reis
ab8187f4e6 ext/python: Gracefully close connection by closing it at Drop 2025-03-24 12:21:15 -03:00
Diego Reis
4ca5b11bed ext/python: Add support for Context Manager 2025-03-24 12:20:13 -03:00
Ihor Andrianov
59f00ff0c3 fix not removing lock if cache did not exist 2025-03-24 15:09:18 +02:00
Ihor Andrianov
d8e070a360 moved json_cache to state 2025-03-24 14:48:40 +02:00
Ihor Andrianov
e5199b0f1a add tests 2025-03-24 13:17:59 +02:00
Ihor Andrianov
1511c9b3bf add json cache to json functions and fix tests 2025-03-24 13:17:58 +02:00
Ihor Andrianov
615de2a0d3 add json_cache struct 2025-03-24 13:17:57 +02:00
Ihor Andrianov
1daab8cd7c add bench to check json cache 2025-03-24 13:17:57 +02:00
Pekka Enberg
6798341b05 github: Don't close issues as stale so aggressively 2025-03-24 11:49:13 +02:00
Pekka Enberg
a9099cd6a5 Merge 'Schema translation cleanups' from Pekka Enberg
Closes #1161
2025-03-24 11:09:08 +02:00
Pekka Enberg
c5cdc859af Merge 'core: Fix Destroy opcode root page handling' from Pekka Enberg
The `p1` register points to the root page, not to a cursor.
Fixes #1136

Closes #1162
2025-03-24 11:09:00 +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
0ec7dbc44e core: Move translate_create_table() to schema module 2025-03-24 10:44:41 +02:00
Pekka Enberg
0727f4aca6 core: Move temporary table handling to translate_create_table() 2025-03-24 10:38:55 +02:00
Pekka Enberg
7d4ac13926 core: Move translate_drop_table() to schema module 2025-03-24 10:37:02 +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
Pekka Enberg
2bbc2b15bd Merge 'Fix SELECT 0.0 = 0 returning false' from lgualtieri75
Fixes #1155

Closes #1158
2025-03-24 08:49:09 +02:00