Ver Fonte

document CTEs, window functions, and unique upserts

Update the compatibility matrix, overview, statements, and internals pages for the newly supported SQL surface, and add Vikunja to the experimental backend evidence.
Danilo Fragoso há 19 horas atrás
pai
commit
ccac7249f4

+ 1 - 1
src/content/docs/internals/architecture.md

@@ -53,7 +53,7 @@ PizzaSQL opens a pool of connections to PizzaKV and serializes each SQL-level op
 ## Key design choices and their consequences
 
 - **Row storage**: rows are encoded with a versioned binary codec (legacy JSON fallback), which keeps the engine simple and flexible but means full scans decode the entire table. The dominant cost of a full scan is row decoding, not the key-value read.
-- **Hand-written parser**: no parser generator; the grammar is explicit and limited (which is why features like CTEs and window functions are simply absent).
+- **Hand-written parser**: no parser generator; the grammar is explicit and limited. CTEs and `ROW_NUMBER()` are supported, but many PostgreSQL constructs are absent by design.
 - **SQLite affinity**: dynamic typing rather than a strict type system (see [Data types](/sql-reference/data-types/)).
 - **No planner**: index use is a single heuristic, not a cost-based decision (see [Query lifecycle](/internals/query-lifecycle/)).
 

+ 1 - 1
src/content/docs/internals/query-lifecycle.md

@@ -7,7 +7,7 @@ This page traces a single statement from bytes to result. It explains *why* cert
 
 ## 1. Lex and parse
 
-The SQL string is tokenized and parsed into an AST. Both steps are pure and fail fast with a syntax error for anything the grammar doesn't cover (CTEs, window functions, `RETURNING`, etc.). A statement that parses is guaranteed to be one the engine at least *recognizes*, even if it later turns out to be only partially implemented.
+The SQL string is tokenized and parsed into an AST. Both steps are pure and fail fast with a syntax error for anything the grammar doesn't cover (`RETURNING`, `WITHOUT ROWID`, triggers, etc.). A statement that parses is guaranteed to be one the engine at least *recognizes*, even if it later turns out to be only partially implemented.
 
 Over the PostgreSQL protocol, a multi-statement batch is parsed *in full before execution begins*, so an unsupported trailing statement doesn't leave earlier writes half-committed.
 

+ 25 - 8
src/content/docs/sql-reference/compatibility.md

@@ -49,6 +49,7 @@ Unsupported syntax normally returns an error. The items above are called out sep
 | `WHERE` | Supported | Supported | Supported |
 | `DISTINCT` | Supported | Supported | Supported |
 | `ORDER BY`, `LIMIT`, and `OFFSET` | Supported | Supported | Supported |
+| `ORDER BY ... NULLS FIRST/LAST` | Supported | Supported | Supported |
 | `GROUP BY` and `HAVING` | Supported; permissive SQLite-style grouping | Supported | Supported; stricter grouping rules |
 | `INNER JOIN` | Supported | Supported | Supported |
 | `LEFT JOIN` | Supported | Supported | Supported |
@@ -63,9 +64,9 @@ Unsupported syntax normally returns an error. The items above are called out sep
 | Subqueries in `FROM` | Supported | Supported | Supported |
 | `UNION` and `UNION ALL` | Supported | Supported | Supported |
 | `INTERSECT` and `EXCEPT` | Supported; distinct form only | Supported | Supported, including `ALL` |
-| Common table expressions (`WITH`) | Unsupported | Supported | Supported |
-| Recursive common table expressions | Unsupported | Supported | Supported |
-| Window functions | Unsupported | Supported | Supported |
+| Common table expressions (`WITH`) | Supported | Supported | Supported |
+| Recursive common table expressions | Supported | Supported | Supported |
+| Window functions | Partial; `ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)` only | Supported | Supported |
 
 ## Writes
 
@@ -76,8 +77,8 @@ Unsupported syntax normally returns an error. The items above are called out sep
 | `UPDATE` | Supported | Supported | Supported |
 | `DELETE` | Supported | Supported | Supported |
 | `INSERT OR IGNORE`, `REPLACE`, and related SQLite conflict modes | Supported | Supported | Different syntax |
-| `ON CONFLICT DO NOTHING` | Partial; primary-key conflicts only | Supported for unique constraints | Supported for unique constraints |
-| `ON CONFLICT DO UPDATE` | Partial; primary-key conflicts only | Supported for unique constraints | Supported for unique constraints |
+| `ON CONFLICT DO NOTHING` | Supported for primary-key and unique-index targets | Supported for unique constraints | Supported for unique constraints |
+| `ON CONFLICT DO UPDATE` | Supported for primary-key and unique-index targets, including `excluded` | Supported for unique constraints | Supported for unique constraints |
 | `RETURNING` | Unsupported | Supported since 3.35 | Supported |
 | `TRUNCATE` | Unsupported | Unsupported | Supported |
 
@@ -147,7 +148,7 @@ PizzaSQL accepts many familiar type names but does not implement PostgreSQL's st
 | `last_insert_rowid()`, `changes()`, `total_changes()` | Supported; session-local | Supported | Unsupported |
 | PostgreSQL date and time functions | Unsupported | Unsupported | Supported |
 | JSON functions | Unsupported | Available with SQLite JSON support | Supported |
-| Window functions | Unsupported | Supported | Supported |
+| Window functions | Partial; `ROW_NUMBER()` only | Supported | Supported |
 
 ## Transactions
 
@@ -208,9 +209,13 @@ The PizzaSQL repository includes the SQLite SQLLogicTest corpus and a custom run
 
 Compatibility claims should therefore be tied to explicit automated tests, not only to the presence or size of the corpus.
 
-## Experimental Gogs backend evidence
+## Experimental backend evidence
 
-An experimental Gogs fork drives PizzaSQL through a custom `pgx`-backed `database/sql` driver that emits SQLite-dialect SQL over the PostgreSQL wire. This is a **local source-build exercise, not a deployed or production configuration**, and transport TLS remains unavailable. Its opt-in smoke test passes end to end against local engine binaries, covering:
+Both of these are **local source-build exercises, not deployed or production configurations**, and transport TLS remains unavailable. They are the concrete integration targets for the SQLite dialect and PostgreSQL wire protocol.
+
+### Gogs
+
+An experimental Gogs fork drives PizzaSQL through a custom `pgx`-backed `database/sql` driver that emits SQLite-dialect SQL over the PostgreSQL wire. Its opt-in smoke test passes end to end against local engine binaries, covering:
 
 - Full fresh-start schema installation and table creation through GORM and XORM, migrations seeding, and XORM `Sync2`.
 - The install flow end to end: `GET /install` returns `200`, `POST /install` redirects with `302`, and the admin user is inserted and reachable through `/user/login`.
@@ -220,6 +225,18 @@ An experimental Gogs fork drives PizzaSQL through a custom `pgx`-backed `databas
 
 This is **not** evidence of complete Gogs compatibility or of the Git LFS transfer path — actual Git LFS upload, SSH, and push have not been tested yet, and the full Gogs test suite has not passed against PizzaSQL.
 
+### Vikunja
+
+An experimental Vikunja fork uses the same driver shape (a `database/sql` driver plus an XORM dialect mapping) but exercises a larger schema and different queries. Its full migration suite ran against a local engine, and registration, login, project CRUD, and task CRUD — create, update, list, delete, and the notification path — worked through the HTTP API. Supporting it required engine work for:
+
+- Non-recursive and recursive common table expressions.
+- `ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)`.
+- `ORDER BY ... NULLS FIRST/LAST`.
+- `ON CONFLICT (cols) DO UPDATE` on unique indexes, including `excluded`.
+- Correlated `EXISTS` in a single-table `WHERE`.
+
+There is no committed automated Vikunja integration test yet, so this is a manual validation rather than a repeatable gate.
+
 ## Advice for porting
 
 1. Use explicit `INNER`, `LEFT`, and `CROSS` joins with `ON` conditions.

+ 1 - 2
src/content/docs/sql-reference/overview.md

@@ -56,8 +56,7 @@ EXPLAIN ...; EXPLAIN QUERY PLAN ...;
 
 PizzaSQL is intentionally small. These features are not implemented at all — they will be rejected by the parser, not silently mishandled:
 
-- **Common table expressions** — no `WITH ... AS (...)`.
-- **Window functions** — no `OVER (...)`, `ROW_NUMBER()`, `PARTITION BY`.
+- **Window functions** — only `ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)`; other window functions and frame clauses are not implemented.
 - **`RETURNING`** — `INSERT`/`UPDATE`/`DELETE` do not return rows.
 - **`WITHOUT ROWID`** tables.
 - **Triggers**, **stored procedures**, **prepared SQL in the engine** (the PG driver handles parameters client-side).

+ 1 - 1
src/content/docs/sql-reference/statements.md

@@ -170,4 +170,4 @@ DETACH DATABASE alias;
 
 ## Not supported
 
-These are rejected at parse time: `WITH` (CTEs), window functions, `RETURNING`, `WITHOUT ROWID`, `TRUNCATE`, `UPSERT` (beyond the `OR`/`ON CONFLICT` forms), triggers, and `CREATE SCHEMA`/roles.
+These are rejected at parse time: `RETURNING`, `WITHOUT ROWID`, `TRUNCATE`, `UPSERT` (beyond the `OR`/`ON CONFLICT` forms), triggers, and `CREATE SCHEMA`/roles. Window functions other than `ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)` are also rejected.