feat: ADR-0035 4d — CREATE [UNIQUE] INDEX / DROP INDEX

Advanced-mode SQL CREATE [UNIQUE] INDEX [IF NOT EXISTS] [<name>] ON
<T> (cols) -> SqlCreateIndex and DROP INDEX [IF EXISTS] <name> ->
SqlDropIndex, both reusing the ADR-0025 executors (do_add_index /
do_drop_index), like 4c reused do_drop_table.

- CREATE UNIQUE INDEX admitted in advanced mode (ADR-0025 Amendment 1):
  ADR-0025 deferred UNIQUE indexes for the simple-mode DSL, but advanced
  mode trusts the user like SQL does. Adds an additive IndexSchema.unique
  flag (project.yaml, serde-default, version stays 1); rebuild re-emits
  CREATE UNIQUE INDEX; the redundant-set guard keys on (columns, unique).
  Simple-mode `add unique index` stays deferred.
- IF [NOT] EXISTS on both forms reuses the 4c no-op-with-note skip
  (journalled, not snapshotted) via CreateIndexOutcome / DropIndexOutcome.
- Unnamed CREATE INDEX auto-named (ADR-0025 convention); the [UNIQUE]
  prefix is a concrete-keyword Choice and the optional name an on-led-first
  selector (the drop-index selector precedent) — trap-safe.
- create/drop each gain a second advanced node; the existing all-candidates
  dispatch handles it (locked by parse tests).
- Unique indexes marked [unique] in the structure view and items panel.
- do_add_index refuses internal __rdbms_* tables as "no such table",
  closing a latent exposure on both the simple `add index` and the new
  SQL CREATE INDEX surfaces (ADR-0025 Amendment 1).

Docs: ADR-0035 status + §13 4d + 4i; ADR-0025 Amendment 1; ADR README;
requirements.md Q1/C3. Plan: docs/plans/20260525-adr-0035-sql-ddl-4d.md.

Tests: 1834 passing / 0 failing / 0 skipped / 1 ignored; clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-25 18:41:02 +00:00
parent 44248fb8bb
commit 701217d29f
22 changed files with 1865 additions and 48 deletions
+16 -8
View File
@@ -585,16 +585,24 @@ pub static REGISTRY: &[(&CommandNode, CommandCategory)] = &[
(&data::SQL_UPDATE, CommandCategory::Advanced),
(&data::SQL_DELETE, CommandCategory::Advanced),
// Shared entry word `create` (ADR-0035 §2): the simple
// `ddl::CREATE` (above) and this advanced SQL node. The
// dispatcher tries SQL first in advanced mode and falls back to
// the `create table … with pk …` DSL node when the SQL shape
// does not match — the `insert` precedent.
// `ddl::CREATE` (above) and these advanced SQL nodes. The
// dispatcher tries the advanced candidates first in advanced mode
// and falls back to the `create table … with pk …` DSL node when no
// SQL shape matches — the `insert` precedent. 4d adds
// SQL_CREATE_INDEX, so `create` now has *two* advanced nodes;
// `decide` tries both (`create table …` → SQL_CREATE_TABLE,
// `create [unique] index …` → SQL_CREATE_INDEX).
(&ddl::SQL_CREATE_TABLE, CommandCategory::Advanced),
// Shared `drop` entry word: `ddl::DROP` (simple) and this advanced
// SQL node. SQL-first in advanced mode; `drop table [if exists] T`
// matches here while `drop column`/`drop relationship`/`drop index`
// fall back to the simple `drop` node.
(&ddl::SQL_CREATE_INDEX, CommandCategory::Advanced),
// Shared `drop` entry word: `ddl::DROP` (simple) and these advanced
// SQL nodes. SQL-first in advanced mode; `drop table [if exists] T`
// → SQL_DROP_TABLE, `drop index [if exists] <name>` → SQL_DROP_INDEX
// (4d — `drop` now has *two* advanced nodes; the dispatcher's
// `decide` tries all advanced candidates). `drop column`/`drop
// relationship`/`drop index on T(…)` fall back to the simple `drop`
// node.
(&ddl::SQL_DROP_TABLE, CommandCategory::Advanced),
(&ddl::SQL_DROP_INDEX, CommandCategory::Advanced),
];
/// Whether `entry` names an advanced-mode-only command (ADR-0030