Expand description
§razeri-plugin-contract
The contract a Razeri dialect plugin is written against.
This crate and razeri-plugin-api are the two open crates in Razeri’s
workspace. Everything a plugin author needs in order to describe and
render a database platform lives here; nothing else does. It depends on
serde and on nothing else at all, which is what lets a plugin be built,
published and consumed outside this repository.
§What is in here
The rendering hierarchy — ten traits, layered so that a new dialect implements four required methods and inherits ANSI-standard behaviour for the rest:
SqlRenderer— core SQL rendering (the four required methods)ExpressionRenderer— expressions, with ANSI defaultsDdlRenderer— DDL, with ANSI defaultsDmlRenderer— DML, with ANSI defaultsProcedureRenderer— stored procedures and functionsFormulaRenderer— formulas, with ANSI defaultsTaskRenderer— scheduled tasksReplicationRenderer— data extraction, loading and key-function deploymentStorageRenderer— partitioning, compression and index strategyDialectCapabilities— what the platform’s SQL can and cannot do
The vocabulary those traits speak: DataType and DataTypeRef, the
storage_strategy::StoragePlan a StorageRenderer translates, the
StoragePlatform a storage plugin names, and DialectFamily, the
platform’s own identity.
The spelling a source gives a day — date_format. One import
arrives with 1/1/2015 in one column and 2015-01-01T00:00:00Z in the
next; the design states the spelling, this crate reads it once into a list
of directives, and each engine translates that list into its own pattern
language through ExpressionRenderer::render_parse_datetime. A directive
an engine cannot spell is refused by name.
The way a source writes an amount — number_format. A file writes a
price $2,899.99 , where the symbol, the thousands mark and the space
around it are not part of the number. The design states the picture, this
crate reads it once into the marks that are not part of the value, and each
engine takes those marks out and converts what is left through
ExpressionRenderer::render_parse_number. An engine that states nothing
is refused by name rather than guessed for.
The questions asked of a warehouse that is already there —
SqlRenderer::render_catalog_columns_query and
SqlRenderer::render_catalog_object_times_query. A design says what
would be built; how much of a running warehouse was built is a question
only that warehouse answers, so each engine spells the two queries that
ask it and names the schemas a whole-warehouse scan passes over through
SqlRenderer::catalog_system_schemas. None is a complete answer to
either query: an engine with no catalog to read is named rather than
reported as an empty warehouse.
The version of an engine — EngineVersion. A platform is an engine
at a version: postgres, or postgres@17. A dialect declares the versions
it answers for, and states how to ask a running server its version through
DialectCapabilities::server_version_query, so a deploy script can refuse
a server older than the bundle before anything runs.
The fan-out an engine states — flatten. One row holding an array
becomes one row per element, and every engine spells that differently, so
the dialect answers with the whole shape rather than filling in a template.
The decisions a dialect states rather than a core crate deciding for it,
starting with SidSpelling — how this engine spells a surrogate key —
and continuing with ProcedureForm and ScalarFunctionForm, the
routine grammars it speaks, MergeShape, how it upserts, and
EvolutionAnswers, what it keeps when a table that already holds rows
changes shape.
The surrogate key’s composition — sid turns a SidSpelling into
the key expression an engine runs. It is here rather than in the product
because a dialect author who cannot render their own key expression cannot
run it either, and “the same key on every engine” is then a claim nobody
outside this repository can check.
The named routine grammars, spelled — routine_render. A dialect
whose engine has stored procedures in a grammar of its own renders the whole
CREATE itself, and “PL/pgSQL with one tweak” need not mean writing the
whole thing from nothing. These three functions write out the grammar a
dialect is nearly the same as, so it can start there and say what differs.
§What is deliberately not in here
Razeri’s design model, and the renderers that turn it into Razeri’s own output. A plugin says what its engine spells; Razeri composes. That division is why one contract crate can be open while the product is not.
The routine grammars are the one thing on both sides of that line, and they are here because they belong to the engines rather than to Razeri’s design: a plugin author who cannot read the grammar next to theirs has to guess at it.
§How this crate is versioned
While the major version is zero:
- a change to a trait’s method set bumps the minor version — a method added, removed or renamed, whether or not it carries a default body;
- documentation and fixes bump the patch version.
The rule is about who decides when a plugin’s behaviour changes. Cargo flows a patch release to every plugin pinned at the minor the next time it builds, and flows a minor release to nobody. A defaulted method costs an existing plugin no line of code, and it still changes what that plugin says: an engine that has not implemented the new method now answers the default, and its users meet whatever Razeri does with that answer — a refusal they had never seen, arriving because somebody else released. So a new method is opted into, and the plugin author chooses the day.
This is stricter than semantic versioning requires of a zero-major crate, deliberately: the looser reading saves a version number and spends a plugin author’s afternoon.
§What 0.5.0 adds to the method set
StorageRenderer::render_partition_retain_proceduretakes the companion table a load sets rows aside in, so one call to a retention procedure reaches both tables.ExpressionRenderer::render_parse_datetimerenders the parse of a value the source spells its own way into a date or a timestamp.SqlRenderer::delimited_file_relation_in_encodingreads a delimited file whose bytes are not UTF-8, where the engine states a way to.
§What 0.6.0 adds to the method set
SqlRenderer::render_catalog_columns_queryasks a running warehouse what it holds, one row per column.SqlRenderer::render_catalog_object_times_queryasks when each object was created, where the engine records it at all.SqlRenderer::catalog_system_schemasnames the schemas a whole-warehouse scan passes over, andSqlRenderer::catalog_scope_predicateis theWHEREclause both catalog queries share.ExpressionRenderer::render_parse_numberrenders the reading of a value the source writes its own way into a number.StorageRenderer::slice_replacement_is_procedure_bodysays whether the slice replacement this engine rendered runs on its own or only inside a procedure. Left alone, the shape of the answer is read instead.
§What 0.11.0 adds to the method set
DialectCapabilities::server_version_querystates how to ask a running server its version, andDialectCapabilities::parse_server_versionreads the answer.ExpressionRenderer::render_read_only_refusalstops with a sentence from a statement that only reads, where the engine has one.ProcedureRenderer::render_call_for_each_rowcalls a procedure once for every row of a query, where the engine has a statement that loops.
Beside the method set, EngineVersion is new: a version of an engine,
read from 17, 8.4, 2022 or 23ai, and split_platform reads
postgres@17 into the engine and the version.
Beside the 0.6.0 method set, sid::normalize_trim is now public: the TRIM in
an engine’s own spelling, which the reading of a written amount starts from.
§What 0.18.0 changes
DdlRenderer::render_copy_tablecopies a table, every row it holds, into a new table beside it:CREATE TABLE … AS SELECT * FROM …by default, with the clauseSqlRenderer::render_table_suffixanswers for a plain table beforeAS.
§What 0.17.0 changes
DelimitedFilecarries how a file is written — itsdelimiter, aFileDelimiter, itsquote, itsheaderand itsencoding— and is built withDelimitedFile::newand thewith_methods.- The default
SqlRenderer::delimited_file_relation_forreads only a plain file (DelimitedFile::is_plain) and answersNonefor any other.
§What 0.16.0 adds to the method set
DdlRenderer::replaces_a_view_that_is_readandDdlRenderer::render_view_replacement, withViewReplacement,ViewReaderandReaderKind: a view other objects read, on an engine that will not replace it in place.SqlRenderer::is_reserved_wordandSqlRenderer::render_alias, overreserved_words: a short name Razeri writes inside a statement, quoted where the engine reserves the word.FormulaRenderer::supports_split,FormulaRenderer::supports_regexp_like,FormulaRenderer::supports_regexp_extractandFormulaRenderer::supports_ordered_string_agg: a function the engine lacks, refused by name.ColumnEvolution::RequireColumn: requiring a column once every row holds a value.
§What 0.15.0 changes in the method set
StorageRenderer::partition_extend_callreplacespartition_extend_call_before_write, answering anExtendCallthat says where the call runs (ExtendRuns).EntityRef::rolereplacesis_identity_table, aTableRole.- New, with a default:
DialectCapabilities::type_limits, answeringTypeLimits. data_type::TimeDataType::precisionis anOption<u8>, and a timestamp’s 0 is whole seconds.number_format::read_with_safe_castandnumber_format::read_with_digit_checktake anumber_format::ClassTest, and read flat.
§What 0.14.0 changes in the method set
- The key’s composers hash the value as stored, and a composite escapes
each part:
sid::sid_expressiontakes asid::Backslash. - New, each with a default:
SqlRenderer::bulk_load_form,SqlRenderer::render_refresh_statistics,SqlRenderer::update_from_takes_a_source_naming_the_targets_columns,SqlRenderer::render_view_options,SqlRenderer::render_join_options,DdlRenderer::render_table_storage_options,DdlRenderer::render_drop_column,DdlRenderer::render_drop_view,DdlRenderer::render_create_table_if_absent,DialectCapabilities::begin_leaves_the_commit_to_the_client,DialectCapabilities::catalogue_reach,DialectCapabilities::text_limits,DialectCapabilities::keeps_a_time_zone,ExpressionRenderer::render_not_an_iso_day,ExpressionRenderer::render_comparable,ExpressionRenderer::text_length_unitandFormulaRenderer::render_bitwise_operator. TaskRenderer::render_create_task,TaskRenderer::render_bulk_loadandSqlRenderer::render_procedure_loganswerOption<String>.
Re-exports§
pub use bulk_load_form::BulkLoadForm;pub use comment::BLOCK_COMMENT_HANG;pub use comment::block_comment;pub use comment::comment_line_flags;pub use comment::comment_lines_apart;pub use comment::cron_in_comment;pub use data_type::DataType;pub use data_type::DataTypeRef;pub use date_format::DateFormat;pub use date_format::DateFormatError;pub use date_format::FormatDirective;pub use date_format::FormatPart;pub use dialect_family::DialectFamily;pub use engine_version::EngineVersion;pub use engine_version::EngineVersionError;pub use engine_version::split_platform;pub use flatten::Flatten;pub use flatten::FlattenField;pub use flatten::FlattenRequest;pub use large_object::HeldAs;pub use large_object::TextLengthUnit;pub use number_format::Negatives;pub use number_format::NumberFormat;pub use number_format::NumberFormatError;pub use procedure_log_level::ProcedureLogLevel;pub use routine_render::render_procedure_as;pub use routine_render::render_scalar_function_as;pub use routine_render::render_table_function_as;pub use sid::sid_expression;pub use storage_platform::StoragePlatform;pub use value_text::CanonicalText;pub use value_text::DOUBLE_DIGITS;pub use value_text::FLOAT_TEXT_FUNCTION;pub use value_text::FloatArithmetic;pub use value_text::FloatParts;pub use value_text::SINGLE_DIGITS;pub use value_text::SINGLE_FLOAT_TEXT_FUNCTION;pub use value_text::TextFunctions;pub use value_text::UTC_OFFSET;pub use value_text::ValueTextFunctions;pub use value_text::computed_float_text;pub use value_text::float_text;pub use value_text::float_text_function;pub use value_text::in_short_lines;pub use value_text::rtrim_fraction;pub use value_text::signed_float_text;pub use value_text::truth_text;pub use view_replacement::ReaderKind;pub use view_replacement::ViewReader;pub use view_replacement::ViewReplacement;pub use agnostic::*;pub use capabilities::*;pub use constraint_enforcement::*;pub use evolution::*;pub use formula_renderer::*;pub use merge_shape::*;pub use renderer::*;pub use replication::*;pub use routine_form::*;pub use routine_spec::*;pub use sid_spelling::*;pub use storage_renderer::*;pub use task_renderer::*;
Modules§
- agnostic
- Agnostic dialect and ANSI data-type rendering.
- bulk_
load_ form - Which bulk-load statement an engine speaks, among the ones Razeri writes.
- capabilities
- Boolean capability flags with conservative defaults.
- comment
- How a comment is written into generated SQL.
- constraint_
enforcement - Whether this engine actually checks the constraints it accepts — the dialect’s answer, and the one place the rendered DDL and the docs read it from.
- data_
type - Generic data types for cross-database compatibility.
- date_
format - How a source spells a day — the format a design states, read once and handed to every engine as a list rather than as text.
- dialect_
family - Dialect Family Definitions
- engine_
version - A version of an engine, and the platform name that carries one.
- evolution
- Changing a table that already holds rows — what this engine keeps through such a change, and the statement it takes to make one.
- flatten
- One row holding an array becomes one row per element — the vocabulary an engine answers a fan-out in.
- formula_
renderer - Formula-level rendering extensions with ANSI defaults.
- large_
object - A value an engine may hold as a large object: how a load compares one, and the unit a length is counted in.
- merge_
shape - How this engine performs an upsert — a shape the dialect describes, not a switch it flips.
- number_
format - How a source writes an amount — the picture a design states, read once and handed to every engine as a small set of facts rather than as text.
- procedure_
log_ level - How loud a message a procedure body writes is.
- renderer
- Layered rendering traits for SQL generation.
- replication
- Replication rendering traits with ANSI defaults.
- reserved_
words - The words the SQL standard reserves, the default answer to
SqlRenderer::is_reserved_word. - routine_
form - Which routine grammar this engine speaks — the dialect’s answer, not a core crate’s guess about its name.
- routine_
render - The named routine grammars, rendered where a plugin can reach them.
- routine_
spec - The routine Razeri composed, handed to a dialect that spells its own grammar.
- sid
- The one derivation of a surrogate key, composed from the vocabulary a dialect states.
- sid_
spelling - How this engine spells a surrogate key — the one thing about the key a dialect decides.
- storage_
platform - Storage platform enumeration for raw file management.
- storage_
renderer - Storage rendering trait for partition, compression, and index strategies.
- storage_
strategy - Agnostic storage strategy types: partition, compression, index.
- task_
renderer - Task and schedule rendering extensions.
- value_
text - A value written as text reads the same on every engine.
- view_
replacement - Replacing a view that other objects read.
Constants§
- SOURCE_
FINGERPRINT - A fingerprint of this crate’s source. Two builds carrying the same version over different source have different fingerprints.
- VERSION
- This crate’s version, as a plugin was compiled against it.