pub enum SidPrerequisiteKind {
None,
SqlInstallable,
OperatorArtifact,
Refused,
EmittedInSchema,
Undeclared,
}Expand description
What a platform’s SID prerequisite actually asks of whoever deploys.
The bundle’s prerequisites step has to emit a different shape for each of these, and the deploy script a different behaviour: one runs SQL, one verifies and refuses, one refuses outright, one says there is nothing to do. Sniffing that out of the prose at each call site would put the rule in the generator, the script writer and the runner — three readings of one fact, which is exactly how one derivation becomes two.
The default derives it from what the dialect already says, so a dialect that
overrides nothing is still classified correctly and only a platform the
derivation cannot reach (Refused, None)
has to override.
Variants§
None
Nothing to install: the engine’s own hash already IS the canonical number (XXH64 seed 0), reachable from SQL razeri emits.
A positive claim, and therefore never a default. Saying this means
razeri has measured that the platform’s builtin returns XXH64 seed 0 —
not that nobody has said otherwise. A dialect that has declared nothing
gets Undeclared instead, for the same reason
DdlRenderer::representable_timestamp_ceiling’s None means no
measured ceiling rather than holds everything.
The derivation cannot reach this variant. A dialect claiming it
overrides ReplicationRenderer::sid_prerequisite_kind and cites the
measurement, as Razeri’s own ClickHouse dialect does.
SqlInstallable
Razeri emits statements that install it, and a deploy script can run
them unattended: INSTALL/LOAD (DuckDB), CREATE FUNCTION
(Snowflake’s JavaScript UDF, Databricks’ Python one).
The test is “can a script finish this with no human on the host”. It is
not “is the statement SQL”: CREATE EXTENSION is SQL and only
registers a shared object somebody compiled first, which is why
PostgreSQL and Citus are OperatorArtifact
and not this.
OperatorArtifact
An artifact the operator builds and places before any SQL can
reference it — MariaDB’s and MySQL’s .so, PostgreSQL’s and
Citus’s pg_xxhash. Razeri emits the source
or the build recipe as prose; it cannot compile anything, and it will not
pretend to.
The deploy path’s obligation here is the prerequisites verb: verify,
then
refuse — ask the engine for the function and stop in front of schema
when it is not there, rather than deploying a warehouse whose keys it
cannot compute.
Refused
The platform cannot be made to compute razeri’s key from SQL at all, and no artifact an operator drops in changes that.
Redshift is the case: its prerequisites.sql says why. A platform with
no CREATE FUNCTION whose client can load a compiled library is not
this case — SQLite ships its key function as a library the operator
compiles, an OperatorArtifact.
The answer is a named refusal carried in the bundle, checked before any data moves. Never a silent fall-back expression: a number that looks like a key and is not razeri’s writes keys no other deployment can reproduce.
EmittedInSchema
Nothing to install here, because razeri’s own key function travels in
schema.sql instead — one definition in every namespace whose
objects call it, created beside those objects, so a namespace deploys
on its own.
BigQuery is the case and the reason is name resolution, not taste: a
bare generate_sid('test') is “Function not found: generate_sid; Did
you mean generate_uuid?” there — no search path, no session schema, no
default dataset inside a procedure body — so every call site must name
the dataset the function was created in, and a prerequisites script has
no dataset to create it in. The definition therefore rides schema.sql,
where the domain’s namespace is known.
It is not None. That variant is the positive claim
“the engine’s own hash IS the canonical number”, which is false here:
BigQuery has no XXH64 in any spelling and the key is a razeri-owned
JavaScript UDF. What the two share is only the deploy behaviour —
nothing to run before schema.sql — and sharing a behaviour is not
sharing a claim.
Undeclared
Razeri has no measured answer for this platform — the honest default, and the one a dialect gets by saying nothing.
§Why this variant exists
A derivation that answered None here would turn “this
dialect declared nothing” into the positive claim “its own hash is
razeri’s number” — a claim that has been false on real engines. Silence
and safety must never read the same, so silence gets its own variant.
§What it means to a deploy path
The same as OperatorArtifact: verify, then
refuse. Safe-by-default is the only defensible reading of “razeri does
not know” — the contract allows an emitted UDF or a named refusal and
explicitly not a local approximation, and proceeding on an unmeasured
platform is neither.
A dialect that genuinely needs no prerequisite says so by overriding
ReplicationRenderer::sid_prerequisite_kind to
None, with its measurement cited.