ALTER TABLE
Schema evolution is catalog-only: channels are independent columnar
streams, so nothing is ever rewritten. Adding a column, changing its
read-time mechanics or renaming it is a metadata edit that takes effect
immediately; only DROP touches data — it purges the channel's stream.
ALTER TABLE telemetry ADD COLUMN door BOOL FILL HOLD STALENESS 60 s;
ALTER TABLE telemetry ALTER COLUMN speed SET FILL NONE SET STALENESS 30 s;
ALTER TABLE telemetry RENAME COLUMN speed TO velocity;
ALTER TABLE telemetry DROP COLUMN old_sensor;
ADD COLUMN
Declares a new channel — same type and attribute syntax as
CREATE TABLE. Existing rows simply read null for
it; no backfill, no table rewrite, no locking. (Ingesting an unknown
field over ILP auto-registers the channel too;
ADD COLUMN is how you declare one with FILL HOLD/staleness.)
ALTER COLUMN SET
SET INDEX ON|OFF declares (or retires) a text/bytes column's
secondary exact index. Folds and
compactions index partitions written from then on; older partitions stay
unindexed until compaction rewrites them or the data is re-imported —
until coverage is complete, equality probes fall back to the scan.
SET FILL HOLD|NONE and SET STALENESS <duration>|INFINITE change
read-time behavior only — fill never touches disk, so the new policy
applies to all existing data on the next query.
SET CALCULATED ON|OFF marks a column as pipeline-written (see
Calculated Fields). A calculated
column's reads collapse a rewrite at the same (entity, ts) to the
newest write — a recompute is a correction, not a second observation.
ADD COLUMN <name> <type> CALCULATED declares one directly; the rule
engine does this for you when you define a calculated field.
RENAME COLUMN
Names live in the catalog; the engine addresses channels by id. A rename moves no data and is visible to the next statement.
DROP COLUMN
Removes the declaration and purges the channel's stream: its in-memory delta, its registry entry and its on-disk segments. The channel id is never reused, so re-adding a column with the same name starts empty — old values cannot resurface.
SET FLEXIBLE / SET STRICT
A table-level toggle for schema-on-write:
ALTER TABLE devices SET FLEXIBLE; -- an INSERT may name a new column; it is added
ALTER TABLE devices SET STRICT; -- unknown columns are refused again (the default)
FLEXIBLE infers a new column's type from the first value written to
it. STRICT only governs future writes — columns already added stay.
SET SYNC
Opt a timeseries table into the sync feed:
ALTER TABLE sensor SET SYNC; -- start stamping x_seq on every fragment
ALTER TABLE sensor SET SYNC OFF; -- stop; stamped history stays honest
Enabling (and re-enabling) bumps the table's sync epoch, so a cursor from a previous life is told to resync instead of silently missing the gap. Rows tables refuse this — they are sync-native already; kv tables have no feed by design.
SET RETENTION
Rewire a timeseries table's drop horizon in place:
ALTER TABLE telemetry SET RETENTION 90 d; -- partitions older than the window are dropped
ALTER TABLE telemetry SET RETENTION OFF; -- keep forever again
Catalog-only: the merge worker reads the table's definition on every
GC pass, so the new window takes effect on the next cycle without a
restart — shrinking the window starts dropping expired partitions,
growing it simply stops. Rows and kv tables refuse it (kv has ttl,
a rows table keeps current state), as does a MUTABLE table.
No type changes
ALTER COLUMN ... TYPE does not exist, by design: data on disk already
has a shape. The representation-safe conversions, bool/int ↔ f64,
are catalog relabels — ask for one by dropping and re-adding only if the
history is disposable, or keep the column as f64.
entity and ts are implicit on every table and cannot be added,
renamed or dropped.