Ver código fonte

docs: composite primary key rejection and SQLSTATE 23505

CREATE TABLE now rejects composite primary keys with SQLSTATE 0A000
instead of silently keeping the first column. UNIQUE violations over the
PostgreSQL wire protocol now return SQLSTATE 23505 with the constraint
name. Update the constraints and statements references to match.
Danilo Fragoso 1 dia atrás
pai
commit
04dfabe849

+ 3 - 3
src/content/docs/sql-reference/constraints.md

@@ -9,8 +9,8 @@ Constraints in PizzaSQL fall into two camps: the ones that are actually implemen
 
 ### PRIMARY KEY
 
-- A single column can be `PRIMARY KEY`, or a table-level `PRIMARY KEY (col, ...)`.
-- A table-level composite key uses **only the first named column** as the effective primary key; true composite keys are not supported.
+- A single column can be `PRIMARY KEY`. A table-level `PRIMARY KEY (col)` is also accepted.
+- A composite primary key (`PRIMARY KEY (a, b)`) is rejected at `CREATE TABLE` with SQLSTATE `0A000`; it is never silently reduced to the first column.
 - An **`INTEGER PRIMARY KEY`** column becomes an alias for the implicit rowid. Inserting without a value auto-assigns the next rowid; inserting with a value sets the rowid and advances the counter past it.
 - A **non-integer primary key** (e.g. `TEXT PRIMARY KEY`) is a normal column with a separate hidden rowid counter.
 - The primary key drives **duplicate detection** on `INSERT`, and therefore `INSERT OR REPLACE`/`OR IGNORE` and `ON CONFLICT DO NOTHING`/`DO UPDATE` — all of which are keyed on the primary key only.
@@ -36,7 +36,7 @@ Constraints in PizzaSQL fall into two camps: the ones that are actually implemen
 `UNIQUE` is enforced, but through validating scans rather than a durable uniqueness claim:
 
 - `CREATE UNIQUE INDEX` and inline/table-level `UNIQUE` constraints both materialize into a unique index definition.
-- The core write paths (`INSERT`, `UPDATE`, `DELETE`, and their `ON CONFLICT`/`OR` variants) validate non-`NULL` values against the table's unique indexes before persisting, rejecting duplicates with `UNIQUE constraint failed`.
+- The core write paths (`INSERT`, `UPDATE`, `DELETE`, and their `ON CONFLICT`/`OR` variants) validate non-`NULL` values against the table's unique indexes before persisting, rejecting duplicates with `UNIQUE constraint failed`. Over the PostgreSQL wire protocol the rejection is SQLSTATE `23505`, and the message names the violated index.
 - `CREATE UNIQUE INDEX` on a table that already contains duplicate non-`NULL` values is rejected and the index is not registered.
 - `NULL` values are exempt — multiple `NULL`s are allowed, matching SQLite.
 - Composite unique indexes are enforced, and integral numerics are canonicalized so `1` (integer) and `1.0` (real) collide the way SQLite's affinity does.

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

@@ -79,7 +79,7 @@ DELETE FROM table WHERE condition;
 CREATE TABLE [IF NOT EXISTS] table (
   column TYPE [PRIMARY KEY] [NOT NULL] [DEFAULT expr] [AUTOINCREMENT],
   ...,
-  [PRIMARY KEY (col, ...)],
+  [PRIMARY KEY (col)],
   [UNIQUE (col, ...)],
   [CHECK (expr)],
   [FOREIGN KEY (col) REFERENCES other (col)]
@@ -88,7 +88,7 @@ CREATE TABLE [IF NOT EXISTS] table (
 
 - `IF NOT EXISTS` silently succeeds if the table already exists.
 - `PRIMARY KEY`, `NOT NULL`, and `DEFAULT` have an effect; `AUTOINCREMENT` is accepted but adds no behavior. Inline and table-level `UNIQUE` constraints are materialized into unique indexes and enforced on the core write paths — see [Constraints](/sql-reference/constraints/). `CHECK` and `FOREIGN KEY` are still parsed and discarded.
-- A table-level `PRIMARY KEY (a, b)` uses the first named column as the primary key; composite keys are not truly supported.
+- A table-level composite `PRIMARY KEY (a, b)` is rejected at `CREATE TABLE` (SQLSTATE `0A000`) instead of being reduced to the first column.
 - `DEFAULT expr` is evaluated when the table is created, so it must be a constant expression. Signed numeric literals (`DEFAULT -1`, `DEFAULT +5`, `DEFAULT (-7)`) are accepted.
 - A bare `NULL` column specifier is accepted as a no-op (columns are nullable by default); `NOT NULL` still applies whenever it appears.
 - `AUTOINCREMENT` is accepted but has no extra behaviour over a plain `INTEGER PRIMARY KEY`.