Schema
Schema evolution and database-level stats. See the Tables hub for the full RPC list.
| Operation | Surface |
|---|---|
AlterTable | dodil.tables.v1.Tables/AlterTable — typed AlterSpec or ALTER TABLE SQL |
| Schema introspection | DESCRIBE "<table>" via Execute — see Lifecycle |
| Database stats | dodil.tables.v1.Tables/GetDatabaseStats, or DESCRIBE DATABASE <db> |
DescribeTableandListPartitionsare not RPCs. Neither appears indodil-tables/proto/api/tables.proto. Schema comes fromDESCRIBE; storage, residency and WAL numbers come fromGetDatabaseStats, which aggregates per database (optionally per table). There is no per-partition file-count API.
AlterTable
AlterTableRequest carries a oneof ddl — a typed AlterSpec or a raw ALTER TABLE SQL string. The typed spec only carries add_columns. Drops and retypes are reachable only through the SQL arm.
What is supported
| Form | Behaviour |
|---|---|
ADD COLUMN <c> <type> [NOT NULL] [DEFAULT <expr>] | Real Delta schema change. Existing rows read as NULL (or the default). Multiple in one statement work. |
DROP COLUMN <c> | Logical — the name is recorded on the HTAP sidecar and every schema-derived surface subtracts it. Delta data is untouched, so it is reversible and needs no rewrite. |
ALTER COLUMN <c> SET DATA TYPE <type> | Logical, widening only — recorded on the sidecar, read egress CASTs, writes keep the physical type. |
ADD CONSTRAINT … CHECK (…) | Real and enforced (v0.1.31): validated against the CHECK grammar at DDL (unenforceable forms → 0A000), stored on the table, enforced at every write (23514) from the next statement. |
ADD CONSTRAINT … FOREIGN KEY / UNIQUE | Accepted as an advisory no-op with a NOTICE (“NOT ENFORCED”) so Django/Rails/Alembic migrations proceed. The enforced uniqueness form is CREATE UNIQUE INDEX; referential integrity is the app’s. |
DROP CONSTRAINT <name> | Removes a stored CHECK by name; a never-stored name (an FK in a downgrade) is a silent no-op. |
The widening set is closed: short → int, short → long, short → double, int → long, int → double, long → double, float → double. Anything else is refused with "… is not a supported WIDENING (allowed: short→int→long, int/long/float→double); narrowing or incompatible retypes need a table rewrite".
What is refused
RENAME COLUMNandRENAME TABLE— and every otherALTER TABLEform:"ALTER TABLE form not supported by warehouse_alter_table v1: ADD COLUMN and DROP COLUMN are implemented".ALTER COLUMNother thanSET DATA TYPE(SET DEFAULT,DROP NOT NULL, …) —"ALTER COLUMN form not supported … only SET DATA TYPE".- Dropping or retyping a primary-key column —
"cannot drop a PRIMARY KEY column"/"cannot retype a PRIMARY KEY column". - Dropping a column that does not exist, or is already dropped — both error rather than no-op.
- An
ALTER TABLEthat carries nothing to do —"ALTER TABLE carries nothing to do (add/drop/retype)". The one exception is a constraint-only statement, which short-circuits to success. - Adding a column whose
DEFAULTdoes not type-check — validated at DDL time, before the Delta log is touched, not on the first insert.
For a rename, or a narrowing retype, recreate the table with CREATE TABLE … AS SELECT.
Request
SQL
-- add
ALTER TABLE events ADD COLUMN session_id VARCHAR;
ALTER TABLE events ADD COLUMN device VARCHAR DEFAULT 'unknown';
-- logical drop
ALTER TABLE events DROP COLUMN legacy_flag;
-- widening retype (int → long)
ALTER TABLE events ALTER COLUMN retry_count SET DATA TYPE BIGINT;Response
message AlterTableResponse {
string table_name = 1;
int64 version = 2;
repeated string columns_added = 3;
// TOTAL column count after the alter, NOT the number added.
uint32 column_count = 4;
}{
"table_name": "events",
"version": 43,
"columns_added": ["session_id", "device"],
"column_count": 7
}A pure drop or pure retype is sidecar-only: columns_added is empty and version is the table’s unchanged Delta version.
Database stats
GetDatabaseStats is the aggregate read — the three truth-dimensions of a database (storage, residency, freshness) plus the reservation and the dead-letter count. It is short-TTL cached, so it never hammers the serving path. DESCRIBE DATABASE <db> reads the same collector.
Request
SQL
DESCRIBE DATABASE "acme--kb-prod";Response
message DatabaseStats {
string db_id = 1;
// STORAGE — summed Delta add-action bytes + catalog row counts.
uint64 stored_bytes = 2;
uint32 table_count = 3;
repeated TableStats tables = 4; // only when include_tables
// RESIDENCY — summed across the readers serving this db.
uint64 ram_resident_bytes = 5;
uint64 disk_resident_bytes = 6;
ReservationInfo reservation = 7;
// WAL — the freshness truth.
uint64 wal_segments = 8;
uint64 wal_entries_estimate = 9;
string wal_high_ulid = 10; // empty = fully drained
// Dead-lettered rows awaiting attention (0 = clean).
uint64 rejected_rows = 11;
uint64 collected_ms_ago = 12; // 0 = just collected
}
message TableStats {
string table = 1;
int64 row_count = 2; // -1 when never drained (unknown)
uint64 size_bytes = 3;
int64 delta_version = 4;
uint64 wal_backlog_entries = 5;
bool fully_resident = 6;
uint64 rejected_rows = 7;
}{
"db_id": "acme--kb-prod",
"stored_bytes": "184729302",
"table_count": 2,
"ram_resident_bytes": "67108864",
"disk_resident_bytes": "184729302",
"wal_segments": "3",
"wal_entries_estimate": "128",
"wal_high_ulid": "01JX7QK9E4...",
"rejected_rows": "0",
"collected_ms_ago": "0"
}Key fields:
wal_high_ulid— empty means fully drained, which is exactly the frontier condition under whicheventual ≡ strongand the plane takes the analytical fast path. A non-empty value means reads are being served STRONG.wal_segments/wal_entries_estimate— how much un-drained history sits in front of Delta. Both go to zero shortly after aCompact.rejected_rows— dead-lettered rows dropped by schema validation. Non-zero means writes are silently losing data; investigate before trusting counts.row_countof-1means the table has never been drained, so the catalog has no count — not that it is empty.
See also
- Create —
CreateTable·CreateTablePipeline - Lifecycle —
SHOW TABLES·DESCRIBE·TRUNCATE·DropTable - Maintenance —
Compactdrains the WAL;OptimizeTablecompacts small files - Core Concepts → Table — type signature + the fifteen-type vocabulary
- CLI Guide —
dodil data table describe