sqlrite 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sqlrite-0.6.0 → sqlrite-0.7.0}/Cargo.lock +7 -7
- {sqlrite-0.6.0 → sqlrite-0.7.0}/Cargo.toml +2 -2
- {sqlrite-0.6.0 → sqlrite-0.7.0}/PKG-INFO +1 -1
- {sqlrite-0.6.0 → sqlrite-0.7.0}/README.md +5 -3
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/package.json +1 -1
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/sql-engine.md +42 -2
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/supported-sql.md +44 -13
- {sqlrite-0.6.0 → sqlrite-0.7.0}/pyproject.toml +1 -1
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/python/Cargo.toml +1 -1
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sqlrite-ask/Cargo.toml +1 -1
- sqlrite-0.7.0/src/sql/agg.rs +543 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/executor.rs +770 -28
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/mod.rs +1 -0
- sqlrite-0.7.0/src/sql/parser/select.rs +510 -0
- sqlrite-0.6.0/src/sql/parser/select.rs +0 -234
- {sqlrite-0.6.0 → sqlrite-0.7.0}/.github/workflows/ci.yml +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/.github/workflows/release-pr.yml +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/.github/workflows/release.yml +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/.github/workflows/rust.yml +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/.gitignore +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/CLAUDE.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/CODE_OF_CONDUCT.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/LICENSE +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/MAINTAINERS +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/Makefile +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/index.html +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/package-lock.json +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/src/App.svelte +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/src/app.css +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/src/main.ts +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/src/vite-env.d.ts +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/svelte.config.js +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/tsconfig.json +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/desktop/vite.config.ts +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/_index.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/architecture.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/ask-backend-examples.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/ask.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/design-decisions.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/desktop.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/embedding.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/file-format.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/fts.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/getting-started.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/mcp.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/pager.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/phase-7-plan.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/phase-8-plan.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/release-plan.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/release-secrets.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/roadmap.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/smoke-test.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/storage-model.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/docs/usage.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/README.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/c/Makefile +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/c/hello.c +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/go/go.mod +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/go/hello.go +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/hybrid-retrieval/README.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/hybrid-retrieval/hybrid_retrieval.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/nodejs/hello.mjs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/python/hello.py +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/rust/quickstart.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/wasm/Makefile +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/wasm/index.html +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/examples/wasm/server.mjs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/images/SQLRite - Desktop.png +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/images/SQLRite Data Structures.png +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/images/SQLRite Simple SQL Execution High Level Diagram.png +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/images/SQLRite Simple SQL INSERT Execution High Level Diagram (Insert Row).png +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/images/SQLRite Simple SQL INSERT Execution High Level Diagram.png +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/images/SQLRite_logo.png +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/images/architecture.png +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/rust-toolchain.toml +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/samples/AST.delete.example +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/samples/AST.insert.exemple +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/samples/AST.select.example +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/samples/AST.update.example +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/samples/CREATE TABLE sqlrite_schema.sql +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/samples/CREATE_TABLE with duplicate.sql +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/samples/CREATE_TABLE.sql +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/samples/INSERT.sql +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/scripts/bump-version.sh +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/README.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/ask.go +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/ask_test.go +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/conn.go +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/go.mod +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/rows.go +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/sqlrite.go +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/sqlrite_test.go +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/go/stmt.go +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/python/README.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/python/src/lib.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/python/tests/test_ask.py +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sdk/python/tests/test_sqlrite.py +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sqlrite-ask/README.md +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sqlrite-ask/src/lib.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sqlrite-ask/src/prompt.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sqlrite-ask/src/provider/anthropic.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sqlrite-ask/src/provider/mock.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sqlrite-ask/src/provider/mod.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/sqlrite-ask/tests/anthropic_http.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/ask/mod.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/ask/schema.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/connection.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/error.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/lib.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/main.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/meta_command/mod.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/repl/mod.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/db/database.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/db/mod.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/db/secondary_index.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/db/table.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/fts/bm25.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/fts/mod.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/fts/posting_list.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/fts/tokenizer.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/hnsw.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/allocator.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/cell.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/file.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/freelist.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/fts_cell.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/header.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/hnsw_cell.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/index_cell.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/interior_page.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/mod.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/overflow.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/page.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/pager.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/table_page.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/varint.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/pager/wal.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/parser/create.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/parser/insert.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/parser/mod.rs +0 -0
- {sqlrite-0.6.0 → sqlrite-0.7.0}/src/sql/tokenizer.rs +0 -0
|
@@ -3817,7 +3817,7 @@ dependencies = [
|
|
|
3817
3817
|
|
|
3818
3818
|
[[package]]
|
|
3819
3819
|
name = "sqlrite-ask"
|
|
3820
|
-
version = "0.
|
|
3820
|
+
version = "0.7.0"
|
|
3821
3821
|
dependencies = [
|
|
3822
3822
|
"serde",
|
|
3823
3823
|
"serde_json",
|
|
@@ -3828,7 +3828,7 @@ dependencies = [
|
|
|
3828
3828
|
|
|
3829
3829
|
[[package]]
|
|
3830
3830
|
name = "sqlrite-desktop"
|
|
3831
|
-
version = "0.
|
|
3831
|
+
version = "0.7.0"
|
|
3832
3832
|
dependencies = [
|
|
3833
3833
|
"serde",
|
|
3834
3834
|
"serde_json",
|
|
@@ -3840,7 +3840,7 @@ dependencies = [
|
|
|
3840
3840
|
|
|
3841
3841
|
[[package]]
|
|
3842
3842
|
name = "sqlrite-engine"
|
|
3843
|
-
version = "0.
|
|
3843
|
+
version = "0.7.0"
|
|
3844
3844
|
dependencies = [
|
|
3845
3845
|
"clap",
|
|
3846
3846
|
"env_logger",
|
|
@@ -3857,7 +3857,7 @@ dependencies = [
|
|
|
3857
3857
|
|
|
3858
3858
|
[[package]]
|
|
3859
3859
|
name = "sqlrite-ffi"
|
|
3860
|
-
version = "0.
|
|
3860
|
+
version = "0.7.0"
|
|
3861
3861
|
dependencies = [
|
|
3862
3862
|
"cbindgen",
|
|
3863
3863
|
"serde",
|
|
@@ -3867,7 +3867,7 @@ dependencies = [
|
|
|
3867
3867
|
|
|
3868
3868
|
[[package]]
|
|
3869
3869
|
name = "sqlrite-mcp"
|
|
3870
|
-
version = "0.
|
|
3870
|
+
version = "0.7.0"
|
|
3871
3871
|
dependencies = [
|
|
3872
3872
|
"clap",
|
|
3873
3873
|
"libc",
|
|
@@ -3878,7 +3878,7 @@ dependencies = [
|
|
|
3878
3878
|
|
|
3879
3879
|
[[package]]
|
|
3880
3880
|
name = "sqlrite-nodejs"
|
|
3881
|
-
version = "0.
|
|
3881
|
+
version = "0.7.0"
|
|
3882
3882
|
dependencies = [
|
|
3883
3883
|
"napi",
|
|
3884
3884
|
"napi-build",
|
|
@@ -3888,7 +3888,7 @@ dependencies = [
|
|
|
3888
3888
|
|
|
3889
3889
|
[[package]]
|
|
3890
3890
|
name = "sqlrite-python"
|
|
3891
|
-
version = "0.
|
|
3891
|
+
version = "0.7.0"
|
|
3892
3892
|
dependencies = [
|
|
3893
3893
|
"pyo3",
|
|
3894
3894
|
"sqlrite-engine",
|
|
@@ -27,7 +27,7 @@ resolver = "3"
|
|
|
27
27
|
# `package =` key so the import name stays `sqlrite` internally:
|
|
28
28
|
# sqlrite = { package = "sqlrite-engine", path = "…" }
|
|
29
29
|
name = "sqlrite-engine"
|
|
30
|
-
version = "0.
|
|
30
|
+
version = "0.7.0"
|
|
31
31
|
authors = ["Joao Henrique Machado Silva <joaoh82@gmail.com>"]
|
|
32
32
|
edition = "2024"
|
|
33
33
|
rust-version = "1.85"
|
|
@@ -138,4 +138,4 @@ fs2 = { version = "0.4", optional = true }
|
|
|
138
138
|
# crate publishes to crates.io, and a path-only dep without a
|
|
139
139
|
# version field fails the manifest verification step. See PR #58
|
|
140
140
|
# retrospective in docs/roadmap.md.
|
|
141
|
-
sqlrite-ask = { version = "0.
|
|
141
|
+
sqlrite-ask = { version = "0.7.0", path = "sqlrite-ask", optional = true }
|
|
@@ -157,7 +157,7 @@ sqlrite> DELETE FROM users WHERE age < 30;
|
|
|
157
157
|
| `CREATE TABLE` | `PRIMARY KEY`, `UNIQUE`, `NOT NULL`; duplicate-column detection; types `INTEGER`/`INT`/`BIGINT`/`SMALLINT`, `TEXT`/`VARCHAR`, `REAL`/`FLOAT`/`DOUBLE`/`DECIMAL`, `BOOLEAN`. Auto-creates `sqlrite_autoindex_<table>_<col>` for every PK + UNIQUE column |
|
|
158
158
|
| `CREATE [UNIQUE] INDEX` | Single-column, named indexes; `IF NOT EXISTS`; persists as a dedicated cell-based B-Tree. INTEGER + TEXT columns only |
|
|
159
159
|
| `INSERT INTO` | Explicit column list required; auto-ROWID for `INTEGER PRIMARY KEY`; multi-row `VALUES (…), (…)`; UNIQUE enforcement; clean type errors (no panics); NULL padding for omitted columns |
|
|
160
|
-
| `SELECT` | `*` or column list
|
|
160
|
+
| `SELECT` | `*` or column list with optional `AS alias`; `WHERE`; `DISTINCT`; `GROUP BY col[, col …]`; aggregate projections `COUNT(*)` / `COUNT([DISTINCT] col)` / `SUM` / `AVG` / `MIN` / `MAX`; single-column `ORDER BY [ASC\|DESC]` (also resolves alias and aggregate display names); `LIMIT n`. `WHERE col = literal` probes an index when one exists |
|
|
161
161
|
| `UPDATE` | Multi-column `SET`; `WHERE`; UNIQUE + type enforcement; arithmetic in assignments (`SET age = age + 1`) |
|
|
162
162
|
| `DELETE` | `WHERE` predicate or full-table delete |
|
|
163
163
|
| `BEGIN` / `COMMIT` / `ROLLBACK` | Real transactions, snapshot-based; WAL-backed commit; single-level (no savepoints); auto-rollback if `COMMIT`'s disk write fails |
|
|
@@ -166,12 +166,14 @@ Expressions in `WHERE` and `UPDATE`'s `SET` RHS:
|
|
|
166
166
|
|
|
167
167
|
- Comparisons — `=`, `<>`, `<`, `<=`, `>`, `>=`
|
|
168
168
|
- Null tests — `IS NULL`, `IS NOT NULL`
|
|
169
|
+
- Pattern matching — `LIKE`, `NOT LIKE`, `ILIKE` (`%` and `_` wildcards, `\`-escaped literals; case-insensitive ASCII to match SQLite's default)
|
|
170
|
+
- Set membership — `IN (list)`, `NOT IN (list)` (literal lists only; subquery form is not supported yet)
|
|
169
171
|
- Logical — `AND`, `OR`, `NOT` (SQL three-valued logic; NULL-as-false in `WHERE`)
|
|
170
172
|
- Arithmetic — `+`, `-`, `*`, `/`, `%` (integer ops stay integer; any `REAL` promotes to `f64`; divide/modulo by zero is a clean error)
|
|
171
173
|
- String concat — `||`
|
|
172
174
|
- Literals — integer + real numbers, `'single-quoted strings'`, `TRUE` / `FALSE`, `NULL`; parentheses for grouping
|
|
173
175
|
|
|
174
|
-
**Not yet supported** (common ones): joins, subqueries, CTEs, `
|
|
176
|
+
**Not yet supported** (common ones): joins, subqueries, CTEs, `HAVING`, `LIKE … ESCAPE '<char>'`, `IN (subquery)`, `DISTINCT` on `SUM`/`AVG`/`MIN`/`MAX`, GROUP BY on expressions, expressions in the projection list, `OFFSET`, multi-column `ORDER BY`, savepoints, `ALTER TABLE`, `DROP TABLE`, `DROP INDEX`. The [full list with context](docs/supported-sql.md#not-yet-supported) lives in the reference.
|
|
175
177
|
|
|
176
178
|
#### Meta commands
|
|
177
179
|
|
|
@@ -310,7 +312,7 @@ Lockstep versioning — one dispatch bumps every product to the same `vX.Y.Z`. T
|
|
|
310
312
|
|
|
311
313
|
**Possible extras** *(no committed phase)*
|
|
312
314
|
- Joins (`INNER`, `LEFT OUTER`, `CROSS` — SQLite does not support `RIGHT`/`FULL OUTER`)
|
|
313
|
-
- `
|
|
315
|
+
- `HAVING`, `IN (subquery)`, `BETWEEN`, `GLOB` / `REGEXP`, `GROUP_CONCAT`, window functions
|
|
314
316
|
- Composite and expression indexes (with cost analysis)
|
|
315
317
|
- Alternate storage engines — LSM/SSTable for write-heavy workloads alongside the B-Tree
|
|
316
318
|
- Benchmarks against SQLite
|
|
@@ -45,11 +45,13 @@ The `sqlparser` AST is designed to cover every SQL dialect, so its types are hug
|
|
|
45
45
|
|---|---|---|
|
|
46
46
|
| `Statement::CreateTable(CreateTable)` | `CreateQuery { table_name, columns: Vec<ParsedColumn> }` | [`create.rs`](../src/sql/parser/create.rs) |
|
|
47
47
|
| `Statement::Insert(Insert)` | `InsertQuery { table_name, columns, rows }` | [`insert.rs`](../src/sql/parser/insert.rs) |
|
|
48
|
-
| `Statement::Query(_)` | `SelectQuery { table_name, projection, selection, order_by, limit }` | [`select.rs`](../src/sql/parser/select.rs) |
|
|
48
|
+
| `Statement::Query(_)` | `SelectQuery { table_name, projection, selection, order_by, limit, distinct, group_by }` | [`select.rs`](../src/sql/parser/select.rs) |
|
|
49
49
|
|
|
50
50
|
`UPDATE` and `DELETE` don't have a dedicated internal struct — the executor pattern-matches the sqlparser types directly because there's less transformation needed.
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
`SelectQuery::projection` is now `Projection::All | Projection::Items(Vec<ProjectionItem>)`, where each item carries a `ProjectionKind::Column(name)` or `ProjectionKind::Aggregate(AggregateCall)` plus an optional `AS alias`. `AggregateCall` covers `COUNT(*)`, `COUNT([DISTINCT] col)`, `SUM` / `AVG` / `MIN` / `MAX` of a bare column. `group_by` is a `Vec<String>` of bare column names (empty = no GROUP BY); the parser validates that every non-aggregate projection item appears in `GROUP BY`.
|
|
53
|
+
|
|
54
|
+
Each parser module still rejects features we don't implement with `SQLRiteError::NotImplemented` — `JOIN`, `HAVING`, `DISTINCT ON (...)`, `GROUP BY` on expressions, `LIKE … ESCAPE '<char>'`, `IN (subquery)`, `OFFSET`, multi-table DELETE, tuple assignment targets, etc. These errors carry the feature name in the message so the user knows what isn't there.
|
|
53
55
|
|
|
54
56
|
## Statement dispatch
|
|
55
57
|
|
|
@@ -90,6 +92,9 @@ match query {
|
|
|
90
92
|
|---|---|
|
|
91
93
|
| Logical | `AND`, `OR`, `NOT` |
|
|
92
94
|
| Comparison | `=`, `<>`, `<`, `<=`, `>`, `>=` |
|
|
95
|
+
| Null tests | `IS NULL`, `IS NOT NULL` |
|
|
96
|
+
| Pattern | `LIKE`, `NOT LIKE`, `ILIKE` (`%`, `_`, `\`-escape; case-insensitive ASCII) |
|
|
97
|
+
| Set | `IN (list)`, `NOT IN (list)` (literal lists only) |
|
|
93
98
|
| Arithmetic | `+`, `-`, `*`, `/`, `%` |
|
|
94
99
|
| String | `\|\|` |
|
|
95
100
|
| Unary | `+`, `-`, `NOT` |
|
|
@@ -139,6 +144,41 @@ Returns top-k from the inverted index in `O(query-term-count × k log k)`. The p
|
|
|
139
144
|
|
|
140
145
|
The full canonical FTS reference is in [`docs/fts.md`](fts.md).
|
|
141
146
|
|
|
147
|
+
### Aggregation phase
|
|
148
|
+
|
|
149
|
+
When a SELECT contains an aggregate projection or a GROUP BY clause, the
|
|
150
|
+
rowid-shaped optimizations don't compose with grouping (every row
|
|
151
|
+
contributes to its group), so the executor takes a separate path:
|
|
152
|
+
|
|
153
|
+
1. Filter by `WHERE` exactly as before — including the index-probe fast
|
|
154
|
+
path — to get the matching rowid set.
|
|
155
|
+
2. For each matching rowid, derive a **group key** as a
|
|
156
|
+
`Vec<DistinctKey>` (one entry per `GROUP BY` column; empty key for
|
|
157
|
+
queries with aggregates but no `GROUP BY`).
|
|
158
|
+
3. Update one `AggState` per (group, aggregate-projection-slot) —
|
|
159
|
+
`AggState` lives in [`src/sql/agg.rs`](../src/sql/agg.rs) and tracks
|
|
160
|
+
the SQLite numeric type rules (`SUM` stays `INTEGER` until a `REAL`
|
|
161
|
+
input or `i64` overflow promotes it; `AVG` is always `REAL`; `MIN`/`MAX`
|
|
162
|
+
reuse the executor's total order; `COUNT(DISTINCT col)` uses a
|
|
163
|
+
`HashSet<DistinctKey>`).
|
|
164
|
+
4. Emit one output row per group, in projection order — bare-column
|
|
165
|
+
slots emit the captured group-key value, aggregate slots emit
|
|
166
|
+
`AggState::finalize()`.
|
|
167
|
+
5. Apply DISTINCT (post-projection dedup), then ORDER BY (resolved
|
|
168
|
+
against the *output* row by alias, bare column name, or aggregate
|
|
169
|
+
display form), then LIMIT.
|
|
170
|
+
|
|
171
|
+
Aggregate function names (`COUNT`/`SUM`/`AVG`/`MIN`/`MAX`) used in WHERE
|
|
172
|
+
or any other scalar position get a friendly error redirecting the user
|
|
173
|
+
to the projection list (since `HAVING` isn't supported yet). DISTINCT
|
|
174
|
+
on `SUM`/`AVG`/`MIN`/`MAX` is rejected at parse time; only
|
|
175
|
+
`COUNT(DISTINCT col)` is in v1.
|
|
176
|
+
|
|
177
|
+
`LIKE` / `ILIKE` use a hand-rolled iterative two-pointer matcher in
|
|
178
|
+
`agg.rs::like_match` (no regex dep). `IN (list)` follows SQLite's
|
|
179
|
+
three-valued logic for NULL on either side, which collapses to "row
|
|
180
|
+
excluded" under WHERE's NULL-as-false rule.
|
|
181
|
+
|
|
142
182
|
## Two-pass pattern for UPDATE and DELETE
|
|
143
183
|
|
|
144
184
|
Both `execute_update` and `execute_delete` use the same pattern to satisfy Rust's aliasing rules:
|
|
@@ -148,35 +148,63 @@ Hex literals, blob literals, and date/time functions are not supported.
|
|
|
148
148
|
## `SELECT`
|
|
149
149
|
|
|
150
150
|
```sql
|
|
151
|
-
SELECT {* |
|
|
151
|
+
SELECT [DISTINCT] {* | <projection_item>[, <projection_item>, ...]}
|
|
152
152
|
FROM <table>
|
|
153
153
|
[WHERE <expr>]
|
|
154
|
-
[
|
|
154
|
+
[GROUP BY <col>[, <col>, ...]]
|
|
155
|
+
[ORDER BY <expr> [ASC|DESC]]
|
|
155
156
|
[LIMIT <non-negative-integer>];
|
|
156
157
|
```
|
|
157
158
|
|
|
159
|
+
`<projection_item>` is one of:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
<column> -- bare column reference
|
|
163
|
+
COUNT(*) -- counts every row, including all-NULL ones
|
|
164
|
+
COUNT([DISTINCT] <column>) -- counts non-NULL values, optionally deduping
|
|
165
|
+
{SUM | AVG | MIN | MAX}(<column>) -- aggregate over a single column
|
|
166
|
+
<projection_item> AS <alias> -- optional column alias
|
|
167
|
+
```
|
|
168
|
+
|
|
158
169
|
### What works
|
|
159
170
|
|
|
160
|
-
- **Projection**: `*` (all columns in declaration order)
|
|
161
|
-
- **`WHERE`**: any [expression](#expressions). Evaluated per row; NULL-as-false in WHERE context (three-valued logic collapsed to two-valued for filtering). Includes **`IS NULL`** / **`IS NOT NULL`** for explicit null tests.
|
|
162
|
-
- **`
|
|
163
|
-
- **`
|
|
171
|
+
- **Projection**: `*` (all columns in declaration order), a bare column list, or an explicit list mixing bare columns and aggregate calls. Each item can carry an optional `AS alias` (the alias becomes the output column header and is recognized by `ORDER BY`).
|
|
172
|
+
- **`WHERE`**: any [expression](#expressions). Evaluated per row; NULL-as-false in WHERE context (three-valued logic collapsed to two-valued for filtering). Includes **`IS NULL`** / **`IS NOT NULL`** for explicit null tests, **`LIKE` / `NOT LIKE` / `ILIKE`** for pattern matching, and **`IN (list) / NOT IN (list)`** for set-membership against literal lists.
|
|
173
|
+
- **`DISTINCT`**: `SELECT DISTINCT` deduplicates result rows after projection (and after aggregation, when both apply). `NULL` values compare equal to other `NULL`s for dedupe, matching SQL's DISTINCT semantic.
|
|
174
|
+
- **`GROUP BY`**: one or more bare column names. Every non-aggregate item in the projection must appear in the `GROUP BY` list (the parser rejects the violation with a clear message). `GROUP BY <col>` without any aggregate behaves like an implicit `DISTINCT <col>`.
|
|
175
|
+
- **Aggregates** (SQLR-3): `COUNT(*)`, `COUNT(col)`, `COUNT(DISTINCT col)`, `SUM(col)`, `AVG(col)`, `MIN(col)`, `MAX(col)`. `SUM` over an integer column stays `INTEGER` until a `REAL` input arrives or the running sum overflows `i64` (one-time promotion to `REAL`). `AVG` always returns `REAL` (or `NULL` on empty / all-NULL groups). `MIN` / `MAX` skip NULLs and use the same total order as `ORDER BY`. Aggregates over an empty table or empty group return `0` for `COUNT(*)` / `COUNT(col)` and `NULL` for the rest.
|
|
176
|
+
- **`ORDER BY`**: single sort key, `ASC` (default) or `DESC`. For non-aggregating queries the key is any expression — including function calls — so KNN queries like `ORDER BY vec_distance_l2(embedding, [...]) LIMIT k` work end-to-end *(Phase 7b)*. For aggregating queries the key resolves against the *output* row by name: a bare identifier matches an alias or a `GROUP BY` column, and a function call like `COUNT(*)` matches an aggregate projection by its canonical display form. Sort key types must match across rows.
|
|
177
|
+
- **`LIMIT`**: non-negative integer literal. `LIMIT 0` is valid (returns zero rows). When `DISTINCT` is in play, `LIMIT` is applied after deduplication so it counts unique rows.
|
|
164
178
|
|
|
165
179
|
### Index probing
|
|
166
180
|
|
|
167
|
-
The executor includes a tiny optimizer: if the `WHERE` is exactly `<indexed_col> = <literal>` or `<literal> = <indexed_col>`, it probes the index and scans only matching rows. Mixed predicates (`WHERE a = 1 AND b > 2`), range predicates (`WHERE a > 1`), and OR-combined predicates fall back to a full table scan.
|
|
181
|
+
The executor includes a tiny optimizer: if the `WHERE` is exactly `<indexed_col> = <literal>` or `<literal> = <indexed_col>`, it probes the index and scans only matching rows. Mixed predicates (`WHERE a = 1 AND b > 2`), range predicates (`WHERE a > 1`), and OR-combined predicates fall back to a full table scan. Aggregating queries (`GROUP BY` / aggregate functions) skip the rowid-shape optimizations (HNSW / FTS / bounded-heap top-k) since every matching row contributes to its group.
|
|
182
|
+
|
|
183
|
+
### `LIKE` semantics
|
|
184
|
+
|
|
185
|
+
- `%` matches any (possibly empty) char sequence; `_` matches exactly one char. `\` escapes the next character so `\%` matches a literal percent. Outside `\%` / `\_` / `\\`, a backslash is itself a literal — matching SQLite's loose default.
|
|
186
|
+
- Case folding is **ASCII-only and on by default**, mirroring SQLite's default `PRAGMA case_sensitive_like = OFF`. `LIKE 'a%'` matches both `Apple` and `apple`. Non-ASCII characters compare by code point (no Unicode case folding).
|
|
187
|
+
- `LIKE … ESCAPE '<char>'` is not supported. `LIKE ANY (...)` is not supported.
|
|
188
|
+
- `NULL LIKE 'pattern'` evaluates to `NULL`; in a `WHERE` that excludes the row.
|
|
189
|
+
|
|
190
|
+
### `IN` semantics
|
|
191
|
+
|
|
192
|
+
- Only the literal-list form is supported: `WHERE x IN (1, 2, 3)` and `WHERE x NOT IN (...)`.
|
|
193
|
+
- Three-valued logic: if the LHS is `NULL`, the result is `NULL`; if the RHS list contains a `NULL` and no other entry matches, the result is `NULL`. In a `WHERE` both cases collapse to "row excluded", matching SQLite.
|
|
194
|
+
- `IN (subquery)`, `IN UNNEST(...)`, and `BETWEEN` are not supported yet.
|
|
168
195
|
|
|
169
196
|
### What doesn't work
|
|
170
197
|
|
|
171
198
|
- **Joins** of any kind (`INNER`, `LEFT OUTER`, `CROSS`, comma-join)
|
|
172
199
|
- **Subqueries**, CTEs (`WITH`), views
|
|
173
|
-
- **`
|
|
174
|
-
- **`DISTINCT`**
|
|
175
|
-
- **`
|
|
176
|
-
-
|
|
177
|
-
- **
|
|
200
|
+
- **`HAVING`** — pre-aggregation `WHERE` works; post-aggregation filtering does not yet
|
|
201
|
+
- **`DISTINCT`** on `SUM` / `AVG` / `MIN` / `MAX` (only `COUNT(DISTINCT col)` is supported)
|
|
202
|
+
- **`GROUP BY` on expressions** — bare column names only in v1
|
|
203
|
+
- **`LIKE … ESCAPE '<char>'`**, **`IN (subquery)`**, **`BETWEEN`**, **`GLOB`**, **`REGEXP`**
|
|
204
|
+
- **Expressions in the projection list** beyond aggregate calls (`SELECT age + 1 FROM users` is still rejected; aggregates are the one allowed expression form)
|
|
205
|
+
- **Multi-column `ORDER BY`**, `NULLS FIRST/LAST` (single sort key only)
|
|
178
206
|
- **`OFFSET`**
|
|
179
|
-
- **
|
|
207
|
+
- **Window functions** (`OVER (...)`, `FILTER (WHERE ...)`, `WITHIN GROUP`)
|
|
180
208
|
|
|
181
209
|
Any of the above reaches the executor as a parsed AST node that execution doesn't handle, producing either `NotImplemented` or a more specific error (e.g., `joins are not supported`).
|
|
182
210
|
|
|
@@ -286,6 +314,9 @@ Expressions work inside `WHERE` (both in `SELECT`, `UPDATE`, `DELETE`) and on th
|
|
|
286
314
|
| Category | Operators |
|
|
287
315
|
|---|---|
|
|
288
316
|
| Comparison | `=`, `<>`, `<`, `<=`, `>`, `>=` |
|
|
317
|
+
| Null tests | `IS NULL`, `IS NOT NULL` |
|
|
318
|
+
| Pattern | `LIKE`, `NOT LIKE`, `ILIKE` (`%`, `_`, `\`-escape; case-insensitive ASCII) |
|
|
319
|
+
| Set | `IN (list)`, `NOT IN (list)` (literal lists only) |
|
|
289
320
|
| Logical | `AND`, `OR`, `NOT` |
|
|
290
321
|
| Arithmetic | `+`, `-`, `*`, `/`, `%` |
|
|
291
322
|
| String | `\|\|` (concatenation) |
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sqlrite"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.0"
|
|
8
8
|
description = "Python bindings for SQLRite — a small, embeddable SQLite clone written in Rust."
|
|
9
9
|
authors = [{ name = "Joao Henrique Machado Silva", email = "joaoh82@gmail.com" }]
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# Published to crates.io as `sqlrite-ask`. Joins the lockstep release
|
|
11
11
|
# wave (`sqlrite-ask-vX.Y.Z` tag) — see `docs/release-plan.md`.
|
|
12
12
|
name = "sqlrite-ask"
|
|
13
|
-
version = "0.
|
|
13
|
+
version = "0.7.0"
|
|
14
14
|
authors = ["Joao Henrique Machado Silva <joaoh82@gmail.com>"]
|
|
15
15
|
edition = "2024"
|
|
16
16
|
rust-version = "1.85"
|