Skip to main content

ReplicationRenderer

Trait ReplicationRenderer 

Source
pub trait ReplicationRenderer: SqlRenderer {
Show 18 methods // Provided methods fn session_prerequisites(&self) -> Vec<String> { ... } fn session_prerequisites_for(&self, computes_key: bool) -> Vec<String> { ... } fn sid_external_artifact(&self) -> Option<SidExternalArtifact> { ... } fn sid_library_source(&self) -> Option<SidLibrarySource> { ... } fn sid_prerequisites(&self) -> String { ... } fn sid_prerequisite_statements(&self) -> Vec<String> { ... } fn sid_pure_sql_fallback(&self) -> Option<String> { ... } fn sid_pure_sql_fallback_in(&self, schemas: &[&str]) -> Option<String> { ... } fn sid_prerequisite_kind(&self) -> SidPrerequisiteKind { ... } fn sid_prerequisite_home(&self) -> SidPrerequisiteHome { ... } fn sid_validation_query( &self, schema: Option<&str>, null_sid: i64, ) -> String { ... } fn render_data_extract( &self, qualified: &str, columns: &str, file_path: &str, format: &str, where_clause: &str, _batch_size: Option<usize>, ) -> String { ... } fn render_data_load( &self, qualified: &str, file_path: &str, _format: &str, ) -> String { ... } fn render_checksum_query(&self, qualified: &str) -> String { ... } fn parquet_export_warning(&self) -> Option<&str> { ... } fn sid_deployment_warning(&self) -> Option<&str> { ... } fn replication_target_warnings(&self) -> Vec<String> { ... } fn truncate_caveat(&self) -> Option<&str> { ... }
}
Expand description

Rendering methods for replication operations: SID generation, data extraction, data loading, and checksum validation.

Defaults produce ANSI-safe SQL so extension dialects (e.g., SQLite) work without implementing every method.

Provided Methods§

Source

fn session_prerequisites(&self) -> Vec<String>

Statements every generated script runs before its first real statement, in this order, in the same session.

Some engines decide how a literal is read from session settings rather than from the statement. Where that is true, a cast that is ordinary everywhere else fails on the first row of the first load until the session has been told how to read it — a date literal parsed by a session-wide format is the measured case. There is nowhere else to put such a statement: it belongs to the connection, not to any object.

§What belongs here

Settings that change how the engine reads what follows and are lost when the session ends: how literals parse, how identifiers fold, which time zone a timestamp is stamped in, how strings compare.

§What does not

Anything that creates something. A function, an extension, an assembly, a table — none of those is a session setting, and putting one here means running it again on every connection. Those are Self::sid_prerequisites where they install the key function, and ordinary DDL otherwise.

Each string is one statement without its terminator; the script that emits them adds whatever this engine ends a statement with. Every statement must be safe to run again — a script that runs twice runs these twice.

The default is empty, and an engine that reads nothing off the session leaves it that way: nothing is emitted, and its scripts are byte for byte what they were.

Source

fn session_prerequisites_for(&self, computes_key: bool) -> Vec<String>

The session’s settings for one design, which may need fewer than Self::session_prerequisites names.

A setting that only a key needs — loading the extension that computes it — is wasted on a design that computes no key, and on a machine that never installed the extension it is a stop. computes_key says whether the design’s schema calls the key function; the prerequisites step installs the key’s function under the same condition, so the two agree.

The default hands back Self::session_prerequisites whole, which is right for an engine whose settings never depend on the key.

Source

fn sid_external_artifact(&self) -> Option<SidExternalArtifact>

Does an external artifact already carry the name generate_sid on this platform, and what is it?

None — the default, and the honest answer for most engines — means razeri itself defines the key function here: the body is Razeri’s one surrogate-key derivation with the platform’s own hash inlined, composed from the platform name alone, so there is nothing for a dialect to spell.

Some(…) names what the bundle’s prerequisites step installs: SQL Server’s CLR assembly, MySQL/MariaDB’s C UDF, Snowflake’s emitted JavaScript UDF, Databricks’ emitted Python UDF. The derivation is inside the artifact rather than in any SQL razeri emits, so what a dialect states is the artifact’s identity, matched against the very prerequisites text that installs it. This is an identity, not a body — see SidExternalArtifact.

A platform that can be given no function at all answers None here too and says so through Self::sid_prerequisite_kind (SidPrerequisiteKind::Refused). Razeri’s conformance checks require that refusal to be said out loud: where no artifact is declared and razeri emits no helper either, a dialect that has simply declared nothing is reported, which is the distinction SidPrerequisiteKind::Undeclared exists to keep.

Source

fn sid_library_source(&self) -> Option<SidLibrarySource>

The source of a library the operator compiles, where the key function arrives that way — shipped in the deploy bundle as a file of its own, so the build is one line.

SQLite answers it: its SQL has no CREATE FUNCTION, and its client loads a compiled extension into each connection it opens. MySQL and MariaDB answer it too: their server loads a compiled function from its plugin directory. The default is None: nothing ships as a separate source file.

Source

fn sid_prerequisites(&self) -> String

Returns prerequisite SQL/instructions for SID deployment.

For platforms that require extensions or external libraries (PostgreSQL pg_xxhash, SQL Server CLR, MariaDB C UDF), this returns the deployment script. Default: empty (no prerequisites needed).

Source

fn sid_prerequisite_statements(&self) -> Vec<String>

The executable statements inside Self::sid_prerequisites, in order — razeri’s own text, split on razeri’s own declared boundary.

This exists so a deploy path or a test harness can install what razeri emits rather than a transcription of it — a hand-written copy is a second implementation that drifts, and a second splitter would be a second definition of the boundary.

A dialect that does not write SID_PREREQUISITE_STATEMENT_DELIMITER declares no executable statements, and gets an empty vector. That is the honest answer for every arm whose prerequisite is an operator’s compile step (MariaDB’s and MySQL’s .so) and for the platforms with no prerequisite at all — it is not a promise that a caller can run the prose.

Leading comment and blank lines are dropped from each segment, so the prose that explains a statement travels with it in the script and does not travel to the engine. Comments inside a statement survive: they are part of the statement the operator would paste.

The trailing terminator is dropped here, once. A ; is how the script reads to a human pasting the whole file, and is not part of a single statement over a REST statement API — Snowflake’s and Databricks’ both take exactly one. Stripping it in each consumer instead would put the same rule in the cloud arms and in the bundle executor, which is the shape this method exists to prevent. sid_prerequisites()’ text is unchanged and keeps its semicolons.

Source

fn sid_pure_sql_fallback(&self) -> Option<String>

A prerequisite script that installs the same key function without compiling anything — where the platform has one, and None where it does not.

The default is None: most platforms have exactly one prerequisite and Self::sid_prerequisites is it. A dialect answers Some only where two honest routes to the same number exist and the choice belongs to whoever deploys rather than to whoever designed — the case being a managed PostgreSQL service (RDS, Aurora, Cloud SQL), where nobody has a shell on the server host and so the compiled extension the ordinary step names can never be built.

§What answering Some promises

The same number, byte for byte. Not a near-enough hash and not a different algorithm: the surrogate-key rule is one hash and one derivation everywhere, so a key minted through this route and a key minted through the compiled one are the same BIGINT and a warehouse can be moved between them without re-keying a row. A dialect that cannot promise that answers None and lets the ordinary step refuse.

It is a deploy-time choice and nothing about it reaches a design: the text swaps into prerequisites.sql alone, schema.sql is unchanged, and every call site still calls the one public name.

Source

fn sid_pure_sql_fallback_in(&self, schemas: &[&str]) -> Option<String>

Self::sid_pure_sql_fallback, installed in every schema a design writes into.

schemas names them, in the order the design first writes to each, spelled as the rendered SQL spells them. A deploy bundle asks this rather than the plain method, because it knows the schemas and the plain method does not.

The default ignores the list and answers the plain method. That is right wherever an installed function is visible from every schema: a function on the session’s search path, or one with a schema of its own that every call names.

Override it where a routine resolves a bare function name in the schema that owns the routine, and a key function created by plain SQL has to live in that same schema. There one definition is not enough: the answer installs the function once in each schema on the list, and makes each schema first if it is not there yet, because this step runs before schema.sql does. An empty list means the session’s current schema, which is what the plain method answers.

Source

fn sid_prerequisite_kind(&self) -> SidPrerequisiteKind

Which of SidPrerequisiteKind’s shapes this platform’s prerequisite is.

Derived from what the dialect already says, so the classification cannot drift from the text it classifies:

sid_prerequisitessid_prerequisite_statementskind
empty—Undeclared
prose and statementsnon-emptySqlInstallable
prose onlyemptyOperatorArtifact
§Silence is Undeclared, never None

The two answers the derivation cannot reach are the two that are positive claims about an engine:

  • None says the platform’s own builtin returns the canonical number. That is a measurement, not an absence, and a dialect claiming it overrides this method and cites the arm that measured it;
  • Refused says no SQL can ever install the function here, which a platform with a native hash and a lazy dialect author would also spell as silence.

It is the same asymmetry DdlRenderer::representable_timestamp_ceiling documents on its own None: not measured and nothing to worry about are opposite facts that read identically when a default supplies them.

Source

fn sid_prerequisite_home(&self) -> SidPrerequisiteHome

Where Self::sid_prerequisites puts what it installs, so that a key function created in some other schema can call it by name.

The default is SidPrerequisiteHome::Ambient: whatever the prerequisite creates, it creates wherever the deploy runs, and every call site names it bare. That is the right answer on every engine whose prerequisite installs nothing with a schema — a session load, a server-wide library, a function whose name has no qualifier — and it leaves those dialects’ scripts exactly as they were.

Answer SidPrerequisiteHome::Schema where a routine on this engine resolves an unqualified name in the schema that OWNS it. There, the one hash a whole warehouse shares needs a fixed address, because every layer schema holds its own copy of the key function, each calls the one hash, and at most one of those schemas is the one the deploy signed in as.

See SidPrerequisiteHome::Schema for what answering it obliges the dialect’s own prerequisite text to do.

Source

fn sid_validation_query(&self, schema: Option<&str>, null_sid: i64) -> String

Returns a validation query to verify the SID function is operational.

Default: schema-qualified SELECT generate_sid('test').

Source

fn render_data_extract( &self, qualified: &str, columns: &str, file_path: &str, format: &str, where_clause: &str, _batch_size: Option<usize>, ) -> String

Renders an extract/export SQL statement for the given table.

The format parameter is one of: "csv", "parquet", "json_lines", "native".

Default: ANSI SELECT ... FROM ... WHERE ... (no COPY).

Source

fn render_data_load( &self, qualified: &str, file_path: &str, _format: &str, ) -> String

Renders a load/import SQL statement for the given table.

The format parameter is one of: "csv", "parquet", "json_lines", "native".

Default: ANSI comment placeholder.

Source

fn render_checksum_query(&self, qualified: &str) -> String

Renders a checksum validation query for data comparison.

Default: SELECT COUNT(*) AS cnt FROM <table> (no checksum).

Source

fn parquet_export_warning(&self) -> Option<&str>

Warning about Parquet export limitations on this platform.

Default: None (no warning needed).

Source

fn sid_deployment_warning(&self) -> Option<&str>

Warning about SID function deployment requirements on this platform.

Default: None (no special deployment needed).

Source

fn replication_target_warnings(&self) -> Vec<String>

General replication caveats for this platform as a target.

Default: empty (no platform-specific caveats).

Source

fn truncate_caveat(&self) -> Option<&str>

Warning about TRUNCATE behavior on this platform.

Default: None (TRUNCATE works normally).

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§