Files
turso/COMPAT.md
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

414 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SQLite Compatibility
This document describes the SQLite compatibility status of Limbo:
- [SQLite Compatibility](#sqlite-compatibility)
- [Limitations](#limitations)
- [SQL statements](#sql-statements)
- [SQL functions](#sql-functions)
- [Scalar functions](#scalar-functions)
- [Aggregate functions](#aggregate-functions)
- [Date and time functions](#date-and-time-functions)
- [JSON functions](#json-functions)
- [SQLite API](#sqlite-api)
- [SQLite VDBE opcodes](#sqlite-vdbe-opcodes)
## Limitations
* Limbo does not support database access from multiple processes.
## SQL statements
| Statement | Status | Comment |
|------------------------------|---------|---------|
| ALTER TABLE | No | |
| ANALYZE | No | |
| ATTACH DATABASE | No | |
| BEGIN TRANSACTION | No | |
| COMMIT TRANSACTION | No | |
| CREATE INDEX | No | |
| CREATE TABLE | Partial | |
| CREATE TRIGGER | No | |
| CREATE VIEW | No | |
| CREATE VIRTUAL TABLE | No | |
| DELETE | No | |
| DETACH DATABASE | No | |
| DROP INDEX | No | |
| DROP TABLE | No | |
| DROP TRIGGER | No | |
| DROP VIEW | No | |
| END TRANSACTION | No | |
| EXPLAIN | Yes | |
| INDEXED BY | No | |
| INSERT | Partial | |
| ON CONFLICT clause | No | |
| PRAGMA | Partial | |
| PRAGMA cache_size   | Yes | |
| REINDEX | No | |
| RELEASE SAVEPOINT | No | |
| REPLACE | No | |
| RETURNING clause | No | |
| ROLLBACK TRANSACTION | No | |
| SAVEPOINT | No | |
| SELECT | Partial | |
| SELECT ... WHERE | Partial | |
| SELECT ... WHERE ... LIKE | Yes | |
| SELECT ... LIMIT | Yes | |
| SELECT ... ORDER BY | Partial | |
| SELECT ... GROUP BY | Partial | |
| SELECT ... HAVING | Partial | |
| SELECT ... JOIN | Partial | |
| SELECT ... CROSS JOIN | Partial | |
| SELECT ... INNER JOIN | Partial | |
| SELECT ... OUTER JOIN | Partial | |
| SELECT ... JOIN USING | Yes | |
| SELECT ... NATURAL JOIN | Yes | |
| UPDATE | No | |
| UPSERT | No | |
| VACUUM | No | |
| WITH clause | No | |
### SELECT Expressions
Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
| Syntax | Status | Comment |
|------------------------------|---------|---------|
| literals | Yes | |
| schema.table.column | Partial | Schemas aren't supported |
| unary operator | Partial | `-` supported, `+~` aren't |
| binary operator | Partial | Only `%`, `!<`, and `!>` are unsupported |
| agg() FILTER (WHERE ...) | No | Is incorrectly ignored |
| ... OVER (...) | No | Is incorrectly ignored |
| (expr) | Yes | |
| CAST (expr AS type) | Yes | |
| COLLATE | No | |
| (NOT) LIKE | No | |
| (NOT) GLOB | No | |
| (NOT) REGEXP | No | |
| (NOT) MATCH | No | |
| IS (NOT) | No | |
| IS (NOT) DISTINCT FROM | No | |
| (NOT) BETWEEN ... AND ... | No | |
| (NOT) IN (subquery) | No | |
| (NOT) EXISTS (subquery) | No | |
| CASE WHEN THEN ELSE END | Yes | |
| RAISE | No | |
## SQL functions
### Scalar functions
| Function | Status | Comment |
|------------------------------|--------|---------|
| abs(X) | Yes | |
| changes() | No | |
| char(X1,X2,...,XN) | Yes | |
| coalesce(X,Y,...) | Yes | |
| concat(X,...) | Yes | |
| concat_ws(SEP,X,...) | Yes | |
| format(FORMAT,...) | No | |
| glob(X,Y) | Yes | |
| hex(X) | Yes | |
| ifnull(X,Y) | Yes | |
| iif(X,Y,Z) | No | |
| instr(X,Y) | Yes | |
| last_insert_rowid() | Yes | |
| length(X) | Yes | |
| like(X,Y) | No | |
| like(X,Y,Z) | No | |
| likelihood(X,Y) | No | |
| likely(X) | No | |
| load_extension(X) | No | |
| load_extension(X,Y) | No | |
| lower(X) | Yes | |
| ltrim(X) | Yes | |
| ltrim(X,Y) | Yes | |
| max(X,Y,...) | Yes | |
| min(X,Y,...) | Yes | |
| nullif(X,Y) | Yes | |
| octet_length(X) | No | |
| printf(FORMAT,...) | No | |
| quote(X) | Yes | |
| random() | Yes | |
| randomblob(N) | Yes | |
| replace(X,Y,Z) | No | |
| round(X) | Yes | |
| round(X,Y) | Yes | |
| rtrim(X) | Yes | |
| rtrim(X,Y) | Yes | |
| sign(X) | Yes | |
| soundex(X) | No | |
| sqlite_compileoption_get(N) | No | |
| sqlite_compileoption_used(X) | No | |
| sqlite_offset(X) | No | |
| sqlite_source_id() | No | |
| sqlite_version() | Yes | |
| substr(X,Y,Z) | Yes | |
| substr(X,Y) | Yes | |
| substring(X,Y,Z) | Yes | |
| substring(X,Y) | Yes | |
| total_changes() | No | |
| trim(X) | Yes | |
| trim(X,Y) | Yes | |
| typeof(X) | Yes | |
| unhex(X) | Yes | |
| unhex(X,Y) | No | |
| unicode(X) | Yes | |
| unlikely(X) | No | |
| upper(X) | Yes | |
| zeroblob(N) | Yes | |
### Aggregate functions
| Function | Status | Comment |
|------------------------------|---------|---------|
| avg(X) | Yes | |
| count() | Yes | |
| count(*) | Yes | |
| group_concat(X) | Yes | |
| group_concat(X,Y) | Yes | |
| string_agg(X,Y) | Yes | |
| max(X) | Yes | |
| min(X) | Yes | |
| sum(X) | Yes | |
| total(X) | Yes | |
### Date and time functions
| Function | Status | Comment |
|-------------|---------|------------------------------|
| date() | Yes | partially supports modifiers |
| time() | Yes | partially supports modifiers |
| datetime() | No | |
| julianday() | No | |
| unixepoch() | Partial | does not support modifiers |
| strftime() | No | |
| timediff() | No | |
### JSON functions
| Function | Status | Comment |
|------------------------------------|---------|---------|
| json(json) | Partial | |
| jsonb(json) | | |
| json_array(value1,value2,...) | | |
| jsonb_array(value1,value2,...) | | |
| json_array_length(json) | | |
| json_array_length(json,path) | | |
| json_error_position(json) | | |
| json_extract(json,path,...) | | |
| jsonb_extract(json,path,...) | | |
| json -> path | | |
| json ->> path | | |
| json_insert(json,path,value,...) | | |
| jsonb_insert(json,path,value,...) | | |
| json_object(label1,value1,...) | | |
| jsonb_object(label1,value1,...) | | |
| json_patch(json1,json2) | | |
| jsonb_patch(json1,json2) | | |
| json_pretty(json) | | |
| json_remove(json,path,...) | | |
| jsonb_remove(json,path,...) | | |
| json_replace(json,path,value,...) | | |
| jsonb_replace(json,path,value,...) | | |
| json_set(json,path,value,...) | | |
| jsonb_set(json,path,value,...) | | |
| json_type(json) | | |
| json_type(json,path) | | |
| json_valid(json) | | |
| json_valid(json,flags) | | |
| json_quote(value) | | |
| json_group_array(value) | | |
| jsonb_group_array(value) | | |
| json_group_object(label,value) | | |
| jsonb_group_object(name,value) | | |
| json_each(json) | | |
| json_each(json,path) | | |
| json_tree(json) | | |
| json_tree(json,path) | | |
## SQLite API
| Interface | Status | Comment |
|------------------------------|---------|---------|
| sqlite3_open | Partial | |
| sqlite3_close | Yes | |
| sqlite3_prepare | Partial | |
| sqlite3_finalize | Yes | |
| sqlite3_step | Yes | |
| sqlite3_column_text | Yes | |
## SQLite VDBE opcodes
| Opcode | Status |
|-----------------|--------|
| Add | Yes |
| AddImm | No |
| Affinity | No |
| AggFinal | Yes |
| AggStep | Yes |
| AggStep | Yes |
| And | No |
| AutoCommit | No |
| BitAnd | No |
| BitNot | No |
| BitOr | No |
| Blob | Yes |
| Checkpoint | No |
| Clear | No |
| Close | No |
| CollSeq | No |
| Column | Yes |
| Compare | No |
| Concat | No |
| Copy | Yes |
| Count | No |
| CreateIndex | No |
| CreateTable | No |
| DecrJumpZero | Yes |
| Delete | No |
| Destroy | No |
| Divide | Yes |
| DropIndex | No |
| DropTable | No |
| DropTrigger | No |
| EndCoroutine | Yes |
| Eq | Yes |
| Expire | No |
| Explain | No |
| FkCounter | No |
| FkIfZero | No |
| Found | No |
| Function | Yes |
| Ge | Yes |
| Gosub | No |
| Goto | Yes |
| Gt | Yes |
| Halt | Yes |
| HaltIfNull | No |
| IdxDelete | No |
| IdxGE | No |
| IdxInsert | No |
| IdxLT | No |
| IdxRowid | No |
| If | Yes |
| IfNeg | No |
| IfNot | Yes |
| IfPos | Yes |
| IfZero | No |
| IncrVacuum | No |
| Init | Yes |
| InitCoroutine | Yes |
| Insert | No |
| InsertAsync | Yes |
| InsertAwait | Yes |
| InsertInt | No |
| Int64 | No |
| Integer | Yes |
| IntegrityCk | No |
| IsNull | No |
| IsUnique | No |
| JournalMode | No |
| Jump | No |
| Last | No |
| Le | Yes |
| LoadAnalysis | No |
| Lt | Yes |
| MakeRecord | Yes |
| MaxPgcnt | No |
| MemMax | No |
| Move | No |
| Multiply | Yes |
| MustBeInt | Yes |
| Ne | Yes |
| NewRowid | Yes |
| Next | No |
| NextAsync | Yes |
| NextAwait | Yes |
| Noop | No |
| Not | No |
| NotExists | Yes |
| NotFound | No |
| NotNull | Yes |
| Null | Yes |
| NullRow | Yes |
| Once | No |
| OpenAutoindex | No |
| OpenEphemeral | No |
| OpenPseudo | Yes |
| OpenRead | Yes |
| OpenReadAsync | Yes |
| OpenWrite | No |
| OpenWriteAsync | Yes |
| OpenWriteAwait | Yes |
| Or | No |
| Pagecount | No |
| Param | No |
| ParseSchema | No |
| Permutation | No |
| Prev | No |
| Program | No |
| ReadCookie | No |
| Real | Yes |
| RealAffinity | Yes |
| Remainder | No |
| ResetCount | No |
| ResultRow | Yes |
| Return | No |
| Rewind | Yes |
| RewindAsync | Yes |
| RewindAwait | Yes |
| RowData | No |
| RowId | Yes |
| RowKey | No |
| RowSetAdd | No |
| RowSetRead | No |
| RowSetTest | No |
| Rowid | Yes |
| SCopy | No |
| Savepoint | No |
| Seek | No |
| SeekGe | No |
| SeekGt | No |
| SeekLe | No |
| SeekLt | No |
| SeekRowid | Yes |
| Sequence | No |
| SetCookie | No |
| ShiftLeft | No |
| ShiftRight | No |
| SoftNull | Yes |
| Sort | No |
| SorterCompare | No |
| SorterData | Yes |
| SorterInsert | Yes |
| SorterNext | Yes |
| SorterOpen | Yes |
| SorterSort | Yes |
| String | No |
| String8 | Yes |
| Subtract | Yes |
| TableLock | No |
| ToBlob | No |
| ToInt | No |
| ToNumeric | No |
| ToReal | No |
| ToText | No |
| Trace | No |
| Transaction | No |
| VBegin | No |
| VColumn | No |
| VCreate | No |
| VDestroy | No |
| VFilter | No |
| VNext | No |
| VOpen | No |
| VRename | No |
| VUpdate | No |
| Vacuum | No |
| Variable | No |
| VerifyCookie | No |
| Yield | Yes |