Li Yazhou
03288e5170
add impl about scalar function soundex with test
2024-12-12 21:48:05 +08:00
Alex Miller
c4d4569dc9
Merge remote-tracking branch 'upstream/main' into expr-iif
2024-12-11 20:13:54 -08:00
alpaylan
021456326e
change 0.1+0.2 test into 0.3 as limbo does not yet support decimals
2024-12-11 16:32:06 -05:00
alpaylan
da28ed51ca
add implementation and tests for replace scalar function
2024-12-11 16:23:13 -05:00
PThorpe92
d5391dc716
Add vdbe bitwise operators: and, or, not
2024-12-11 11:06:22 -05:00
jussisaurio
eb9374aebf
Merge 'Add support for CASE expressions.' from Alex Miller
...
There's two forms of case:
CASE (WHEN [bool expr] THEN [value])+ (ELSE [value])? END
which checks a series of boolean conditions, and:
CASE expr (WHEN [expr] THEN [value})+ (ELSE [value])? END
Which checks a series of equality conditions.
This implements support for both. Note that the ELSE is optional, and
will be equivalent to `ELSE null` if not specified.
sqlite3 gives the implementation as:
```
sqlite> explain select case a WHEN a THEN b WHEN c THEN d ELSE 0 END from casetest;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 16 0 0 Start at 16
1 OpenRead 0 3 0 4 0 root=3 iDb=0; casetest
2 Rewind 0 15 0 0
3 Column 0 0 2 0 r[2]= cursor 0 column 0
4 Column 0 0 3 0 r[3]= cursor 0 column 0
5 Ne 3 8 2 BINARY-8 83 if r[2]!=r[3] goto 8
6 Column 0 1 1 0 r[1]= cursor 0 column 1
7 Goto 0 13 0 0
8 Column 0 2 3 0 r[3]= cursor 0 column 2
9 Ne 3 12 2 BINARY-8 83 if r[2]!=r[3] goto 12
10 Column 0 3 1 0 r[1]= cursor 0 column 3
11 Goto 0 13 0 0
12 Integer 0 1 0 0 r[1]=0
13 ResultRow 1 1 0 0 output=r[1]
14 Next 0 3 0 1
15 Halt 0 0 0 0
16 Transaction 0 0 2 0 1 usesStmtJournal=0
17 Goto 0 1 0 0
```
and after this patch, limbo gives:
```
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 19 0 0 Start at 19
1 OpenReadAsync 0 4 0 0 table=casetest, root=4
2 OpenReadAwait 0 0 0 0
3 RewindAsync 0 0 0 0
4 RewindAwait 0 18 0 0 Rewind table casetest
5 Column 0 0 2 0 r[2]=casetest.a
6 Column 0 0 3 0 r[3]=casetest.a
7 Ne 2 3 10 0 if r[2]!=r[3] goto 10
8 Column 0 1 1 0 r[1]=casetest.b
9 Goto 0 15 0 0
10 Column 0 2 3 0 r[3]=casetest.c
11 Ne 2 3 14 0 if r[2]!=r[3] goto 14
12 Column 0 3 1 0 r[1]=casetest.d
13 Goto 0 15 0 0
14 Integer 0 1 0 0 r[1]=0
15 ResultRow 1 1 0 0 output=r[1]
16 NextAsync 0 0 0 0
17 NextAwait 0 5 0 0
18 Halt 0 0 0 0
19 Transaction 0 0 0 0
20 Goto 0 1 0 0
```
And then as there's nowhere to annotate this new support in COMPAT.md, I
added a corresponding heading for SELECT expressions and what is/isn't
supported.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com >
Closes #425
2024-12-11 17:05:41 +02:00
Pekka Enberg
04f196113a
Merge 'Add last_insert_rowid() function' from Krishna Vishal
...
- Changed `Cursor` trait to be able to get access to `root_page`
- SQLite only updates last_insert_rowid for non-schema inserts. So we
check if the `InsertAwait` is not for `root_page` before updating
rowid
In SQLite it looks like this:
```
sqlite> EXPLAIN SELECT last_insert_rowid();
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 4 0 0
1 Function 0 0 1 last_insert_rowid(0) 0
2 ResultRow 1 1 0 0
3 Halt 0 0 0 0
4 Goto 0 1 0 0
```
In limbo it will look like this:
```
limbo> EXPLAIN SELECT last_insert_rowid();
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 4 0 0 Start at 4
1 Function 0 2 1 last_insert_rowid 0 r[1]=func()
2 ResultRow 1 1 0 0 output=r[1]
3 Halt 0 0 0 0
4 Transaction 0 0 0 0
5 Goto 0 1 0 0
```
Closes #427
2024-12-11 10:44:34 +02:00
Pekka Enberg
eda1f5396c
Merge 'Add octet_length scalar function' from Kacper Kołodziej
...
Adds `octet_length` scalar function.
Part of solution for: #144
Closes #430
2024-12-11 07:44:04 +02:00
Kacper Kołodziej
d4bff2c93e
add octet_length scalar function
2024-12-10 22:56:38 +01:00
Kacper Kołodziej
660d3e8d07
fix: count characters in string in length function
...
`length` function should count characters, not bytes.
https://www.sqlite.org/lang_corefunc.html#length
2024-12-10 22:48:50 +01:00
krishvishal
134b5576ad
Ran cargo fmt
2024-12-09 22:55:54 +05:30
krishvishal
7e2928a5f1
Feature: last_insert_rowid()
...
- Changed `Cursor` trait to be able to get access to `root_page`
- SQLite only updates last_insert_rowid for non-schema inserts. So we check if the `InsertAwait` is not for `root_page` before
updating rowid
2024-12-09 22:48:42 +05:30
krishvishal
1e23af7d24
Added last_insert_rowid() function.
...
Need to fix its behavior. Problem is probably with `Cursor` implementation.
2024-12-09 17:41:28 +05:30
Alex Miller
eb00226cfe
Add support for CASE expressions.
...
There's two forms of case:
CASE (WHEN [bool expr] THEN [value])+ (ELSE [value])? END
which checks a series of boolean conditions, and:
CASE expr (WHEN [expr] THEN [value})+ (ELSE [value])? END
Which checks a series of equality conditions.
This implements support for both. Note that the ELSE is optional, and
will be equivalent to `ELSE null` if not specified.
sqlite3 gives the implementation as:
sqlite> explain select case a WHEN a THEN b WHEN c THEN d ELSE 0 END from casetest;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 16 0 0 Start at 16
1 OpenRead 0 3 0 4 0 root=3 iDb=0; casetest
2 Rewind 0 15 0 0
3 Column 0 0 2 0 r[2]= cursor 0 column 0
4 Column 0 0 3 0 r[3]= cursor 0 column 0
5 Ne 3 8 2 BINARY-8 83 if r[2]!=r[3] goto 8
6 Column 0 1 1 0 r[1]= cursor 0 column 1
7 Goto 0 13 0 0
8 Column 0 2 3 0 r[3]= cursor 0 column 2
9 Ne 3 12 2 BINARY-8 83 if r[2]!=r[3] goto 12
10 Column 0 3 1 0 r[1]= cursor 0 column 3
11 Goto 0 13 0 0
12 Integer 0 1 0 0 r[1]=0
13 ResultRow 1 1 0 0 output=r[1]
14 Next 0 3 0 1
15 Halt 0 0 0 0
16 Transaction 0 0 2 0 1 usesStmtJournal=0
17 Goto 0 1 0 0
and after this patch, limbo gives:
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 18 0 0 Start at 18
1 OpenReadAsync 0 4 0 0 table=casetest, root=4
2 OpenReadAwait 0 0 0 0
3 RewindAsync 0 0 0 0
4 RewindAwait 0 17 0 0 Rewind table casetest
5 Column 0 0 2 0 r[2]=casetest.a
6 Column 0 0 3 0 r[3]=casetest.a
7 Ne 2 3 10 0 if r[2]!=r[3] goto 10
8 Column 0 1 1 0 r[1]=casetest.b
9 Goto 0 14 0 0
10 Column 0 2 3 0 r[3]=casetest.c
11 Ne 2 3 14 0 if r[2]!=r[3] goto 14
12 Column 0 3 1 0 r[1]=casetest.d
13 Goto 0 14 0 0
14 ResultRow 1 1 0 0 output=r[1]
15 NextAsync 0 0 0 0
16 NextAwait 0 5 0 0
17 Halt 0 0 0 0
18 Transaction 0 0 0 0
19 Integer 0 1 0 0 r[1]=0
20 Goto 0 1 0 0
And then as there's nowhere to annotate this new support in COMPAT.md, I
added a corresponding heading for SELECT expressions and what is/isn't
supported.
2024-12-08 14:09:03 -08:00
Alex Miller
183ea8e362
Implement support for iif().
...
In sqlite, iif() looks like:
sqlite> create table iiftest(a int, b int, c int);
sqlite> explain select iif(a,b,c) from iiftest;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 11 0 0 Start at 11
1 OpenRead 0 2 0 3 0 root=2 iDb=0; iiftest
2 Rewind 0 10 0 0
3 Column 0 0 2 0 r[2]= cursor 0 column 0
4 IfNot 2 7 1 0
5 Column 0 1 1 0 r[1]= cursor 0 column 1
6 Goto 0 8 0 0
7 Column 0 2 1 0 r[1]= cursor 0 column 2
8 ResultRow 1 1 0 0 output=r[1]
9 Next 0 3 0 1
10 Halt 0 0 0 0
11 Transaction 0 0 1 0 1 usesStmtJournal=0
12 Goto 0 1 0 0
And with this change, in limbo it looks like:
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 14 0 0 Start at 14
1 OpenReadAsync 0 2 0 0 table=iiftest, root=2
2 OpenReadAwait 0 0 0 0
3 RewindAsync 0 0 0 0
4 RewindAwait 0 13 0 0 Rewind table iiftest
5 Column 0 0 2 0 r[2]=iiftest.a
6 IfNot 2 9 1 0 if !r[2] goto 9
7 Column 0 1 1 0 r[1]=iiftest.b
8 Goto 0 10 0 0
9 Column 0 2 1 0 r[1]=iiftest.c
10 ResultRow 1 1 0 0 output=r[1]
11 NextAsync 0 0 0 0
12 NextAwait 0 5 0 0
13 Halt 0 0 0 0
14 Transaction 0 0 0 0
15 Goto 0 1 0 0
2024-12-07 21:04:03 -08:00
jussisaurio
3f80e41e7a
support HAVING
2024-11-30 10:05:13 +02:00
jussisaurio
418ad40401
Merge 'Fix some Clippy warnings' from Lauri Virtanen
...
Reviewed-by: Pere Diaz Bou <limeng.1@bytedance.com >
Closes #417
2024-11-25 16:43:06 +02:00
Lauri Virtanen
70c4d6b360
Support multiplying combinations of different types
2024-11-24 22:11:37 +02:00
Lauri Virtanen
af9d407dee
Fix issues with subtraction of different type combinations
2024-11-24 22:10:23 +02:00
Lauri Virtanen
cafbf5499f
Support divide operator in expressions
2024-11-24 22:10:07 +02:00
Lauri Virtanen
afeb1cbe74
Clippy warning fixes
2024-11-24 20:24:47 +02:00
Lauri Virtanen
a7100d8e9b
Autofix clippy issues with cargo fix --clippy
2024-11-24 20:24:47 +02:00
jussisaurio
c722074016
missing cursorresult handling
2024-11-21 20:29:46 +02:00
jussisaurio
f945795ae6
consistent naming
2024-11-21 20:25:51 +02:00
jussisaurio
d8eb4be424
better, less cool names
2024-11-21 20:23:53 +02:00
jussisaurio
3002f2a552
io macro
2024-11-21 20:23:23 +02:00
jussisaurio
6dc427fc9b
Merge 'impl order by desc' from lemonwx
...
Hi all,
I attempted to implement the `order by desc`, which mainly consists of
the following two parts:
1. for cases where the primary key can be utilized, I implemented
`push_scan_direction` to push the scan direction down to the `Scan`.
2. for cases where the primary key cannot be utilized, I re-implemented
the sorting in `Sorter::rewind` based on whether it's desc or asc.
there is also some related work to be done, such as sort using secondary
index, I will attempt to do next.
Please help review this and let me know how I can improve it, thanks in
advance
Reviewed-by: Pere Diaz Bou <pere-altea@hotmail.com >
Closes #376
2024-11-21 16:37:38 +02:00
Pekka Enberg
fc07445e0a
Merge 'sim: improve simulator' from Pere Diaz Bou
...
Newly improved simulator with CREATE TABLE, INSERT, SELECT, connection
management, etc...
This new simulator is finding a bunch of bugs with write path so after
this PR I will start fixing those.
Closes #405
2024-11-20 08:59:13 +02:00
limeng.1
8cca659052
impl order by desc
2024-11-19 11:39:07 +08:00
jussisaurio
b86501f12e
Merge 'implement CAST(col as type)' from Jussi Saurio
...
Closes #398
Reviewed-by: Pere Diaz Bou <pere-altea@hotmail.com >
Closes #404
2024-11-18 20:53:58 +02:00
jussisaurio
9efd45025d
enum instead of string
2024-11-18 18:26:04 +02:00
Pere Diaz Bou
a738ef6e91
comment use of rng in limbo
2024-11-18 13:40:37 +01:00
Pere Diaz Bou
9c4ca28bd9
Merge 'CREATE TABLE support' from Pekka Enberg
...
Closes #383
2024-11-18 13:40:20 +01:00
Pere Diaz Bou
80f60852df
remove wrong comment
2024-11-18 10:41:20 +01:00
Pere Diaz Bou
9f72655e30
tree_create -> btree_create
2024-11-18 10:31:47 +01:00
Pekka Enberg
5efc218e6e
Merge 'support subtract in translate_expr() (not in condition expressions yet)' from Jussi Saurio
...
closes #402
Closes #403
2024-11-18 09:28:23 +02:00
jussisaurio
62761d2b34
uppercase only once
2024-11-17 22:22:03 +02:00
jussisaurio
ddd0cc041c
implement CAST(col as type)
2024-11-17 22:12:22 +02:00
jussisaurio
491bdd3bfc
support subtract in translate_expr() (not in condition expressions yet)
2024-11-17 18:47:16 +02:00
jussisaurio
9a4864bc6a
support parenthesized(single expr) in translate_expr()
2024-11-17 18:36:30 +02:00
Pere Diaz Bou
569e98cb32
fmt
2024-11-16 17:08:22 +01:00
Pere Diaz Bou
090615b289
create btree table + parse schema
2024-11-16 16:24:28 +01:00
Pekka Enberg
fc5e42bb94
CREATE TABLE support
2024-11-16 13:07:10 +01:00
Pekka Enberg
cd5db55cf2
core: Make JSON support configurable
...
This adds a `json` feature flag, which allows users to disable JSON
support if needed.
2024-11-16 09:49:09 +02:00
Pere Diaz Bou
48f0e72e14
checkpoint on drop connection
2024-11-12 17:03:30 +01:00
Pere Diaz Bou
f009eb35c6
suspendable checkpoint
2024-11-05 15:29:54 +01:00
Pere Diaz Bou
c0e51c4ca6
wip wal
2024-11-05 15:29:53 +01:00
Pekka Enberg
fdf3b0d16b
Merge '(core): Primary key index scans and single-column secondary index scans' from Jussi Saurio
...
This PR adds an index on `users.age` to `testing.db`, and support for
indexed lookups. Only single-column ascending indexes are currently
supported.
This PR also gets rid of `Operator::Seekrowid` in favor of
`Operator::Search` which handles all non-full-table-scan searches: 1.
integer primary key (rowid) point queries 2. integer primary key index
scans, and 3. secondary index scans.
examples:
```
limbo> select first_name, age from users where age > 90 limit 10;
Miranda|90
Sarah|90
Justin|90
Justin|90
John|90
Jeremy|90
Stephanie|90
Joshua|90
Jenny|90
Jennifer|90
limbo> explain query plan select first_name, age from users where age > 90 limit 10;
QUERY PLAN
`--TAKE 10
`--PROJECT first_name, age
| `--SEARCH users USING INDEX age_idx
limbo> explain select first_name, age from users where age > 90 limit 10;
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 15 0 0 Start at 15
1 OpenReadAsync 0 2 0 0 table=users, root=2
2 OpenReadAwait 0 0 0 0
3 OpenReadAsync 1 274 0 0 table=age_idx, root=274
4 OpenReadAwait 0 0 0 0
5 Integer 90 1 0 0 r[1]=90
6 SeekGT 1 14 1 0
7 DeferredSeek 1 0 0 0
8 Column 0 1 2 0 r[2]=users.first_name
9 Column 0 9 3 0 r[3]=users.age
10 ResultRow 2 2 0 0 output=r[2..3]
11 DecrJumpZero 4 14 0 0 if (--r[4]==0) goto 14
12 NextAsync 1 0 0 0
13 NextAwait 1 7 0 0
14 Halt 0 0 0 0
15 Transaction 0 0 0 0
16 Integer 10 4 0 0 r[4]=10
17 Goto 0 1 0 0
```
Sqlite version:
```
sqlite> explain select first_name, age from users where age > 90 limit 10;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 13 0 0 Start at 13
1 Integer 10 1 0 0 r[1]=10; LIMIT counter
2 OpenRead 0 2 0 10 0 root=2 iDb=0; users
3 OpenRead 1 274 0 k(2,,) 0 root=274 iDb=0; age_idx
4 Integer 90 2 0 0 r[2]=90
5 SeekGT 1 12 2 1 0 key=r[2]
6 DeferredSeek 1 0 0 0 Move 0 to 1.rowid if needed
7 Column 0 1 3 0 r[3]= cursor 0 column 1
8 Column 1 0 4 0 r[4]= cursor 1 column 0
9 ResultRow 3 2 0 0 output=r[3..4]
10 DecrJumpZero 1 12 0 0 if (--r[1])==0 goto 12
11 Next 1 6 0 0
12 Halt 0 0 0 0
13 Transaction 0 0 3 0 1 usesStmtJournal=0
14 Goto 0 1 0 0
```
---
´Seek` instructions are also now supported for primary key rowid
searches:
```
limbo> select id, first_name from users where id > 9995;
9996|Donald
9997|Ruth
9998|Dorothy
9999|Gina
10000|Nicole
limbo> explain query plan select id, first_name from users where id > 9995;
QUERY PLAN
`--PROJECT id, first_name
`--SEARCH users USING INTEGER PRIMARY KEY (rowid=?)
limbo> explain select id, first_name from users where id > 9995;
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 11 0 0 Start at 11
1 OpenReadAsync 0 2 0 0 table=users, root=2
2 OpenReadAwait 0 0 0 0
3 Integer 9995 1 0 0 r[1]=9995
4 SeekGT 0 10 1 0
5 RowId 0 2 0 0 r[2]=users.rowid
6 Column 0 1 3 0 r[3]=users.first_name
7 ResultRow 2 2 0 0 output=r[2..3]
8 NextAsync 0 0 0 0
9 NextAwait 0 5 0 0
10 Halt 0 0 0 0
11 Transaction 0 0 0 0
12 Goto 0 1 0 0
```
sqlite:
```
sqlite> explain select id, first_name from users where id > 9995;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 8 0 0 Start at 8
1 OpenRead 0 2 0 2 0 root=2 iDb=0; users
2 SeekGT 0 7 1 0 key=r[1]; pk
3 Rowid 0 2 0 0 r[2]=users.rowid
4 Column 0 1 3 0 r[3]= cursor 0 column 1
5 ResultRow 2 2 0 0 output=r[2..3]
6 Next 0 3 0 0
7 Halt 0 0 0 0
8 Transaction 0 0 3 0 1 usesStmtJournal=0
9 Integer 9995 1 0 0 r[1]=9995
10 Goto 0 1 0 0
```
---
More complex example with a join that uses both a rowid lookup and a
secondary index scan:
```
limbo> explain query plan select u.first_name, p.name from users u join products p on u.id = p.id and u.age > 70;
QUERY PLAN
`--PROJECT u.first_name, p.name
`--JOIN
| |--SEARCH u USING INDEX age_idx
| `--SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
limbo> explain select u.first_name, p.name from users u join products p on u.id = p.id and u.age > 70;
addr opcode p1 p2 p3 p4 p5 comment
---- ----------------- ---- ---- ---- ------------- -- -------
0 Init 0 18 0 0 Start at 18
1 OpenReadAsync 0 2 0 0 table=u, root=2
2 OpenReadAwait 0 0 0 0
3 OpenReadAsync 1 274 0 0 table=age_idx, root=274
4 OpenReadAwait 0 0 0 0
5 OpenReadAsync 2 3 0 0 table=p, root=3
6 OpenReadAwait 0 0 0 0
7 Integer 70 1 0 0 r[1]=70
8 SeekGT 1 17 1 0
9 DeferredSeek 1 0 0 0
10 RowId 0 2 0 0 r[2]=u.rowid
11 SeekRowid 2 2 15 0 if (r[2]!=p.rowid) goto 15
12 Column 0 1 3 0 r[3]=u.first_name
13 Column 2 1 4 0 r[4]=p.name
14 ResultRow 3 2 0 0 output=r[3..4]
15 NextAsync 1 0 0 0
16 NextAwait 1 9 0 0
17 Halt 0 0 0 0
18 Transaction 0 0 0 0
19 Goto 0 1 0 0
```
sqlite:
```
sqlite> explain select u.first_name, p.name from users u join products p on u.id = p.id and u.age > 70;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 14 0 0 Start at 14
1 OpenRead 0 2 0 10 0 root=2 iDb=0; users
2 OpenRead 2 274 0 k(2,,) 0 root=274 iDb=0; age_idx
3 OpenRead 1 3 0 2 0 root=3 iDb=0; products
4 Integer 70 1 0 0 r[1]=70
5 SeekGT 2 13 1 1 0 key=r[1]
6 DeferredSeek 2 0 0 0 Move 0 to 2.rowid if needed
7 IdxRowid 2 2 0 0 r[2]=rowid; users.rowid
8 SeekRowid 1 12 2 0 intkey=r[2]
9 Column 0 1 3 0 r[3]= cursor 0 column 1
10 Column 1 1 4 0 r[4]= cursor 1 column 1
11 ResultRow 3 2 0 0 output=r[3..4]
12 Next 2 6 0 0
13 Halt 0 0 0 0
14 Transaction 0 0 3 0 1 usesStmtJournal=0
15 Goto 0 1 0 0
```
Closes #350
2024-10-13 10:11:23 +03:00
Lauri Virtanen
0ae1412193
Add instr(X,Y) scalar function
...
Relates to issue #144
2024-10-06 20:19:37 +03:00
jussisaurio
15a66ea662
single seek function in cursor trait
2024-10-06 09:21:15 +03:00