1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
// Copyright (C) 2026 Gabriel Shea
// Licensed under either of the Apache License, Version 2.0 or the MIT
// license, at your option.
//! # 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:
//!
//! 1. [`SqlRenderer`] — core SQL rendering (the four required methods)
//! 2. [`ExpressionRenderer`] — expressions, with ANSI defaults
//! 3. [`DdlRenderer`] — DDL, with ANSI defaults
//! 4. [`DmlRenderer`] — DML, with ANSI defaults
//! 5. [`ProcedureRenderer`] — stored procedures and functions
//! 6. [`FormulaRenderer`] — formulas, with ANSI defaults
//! 7. [`TaskRenderer`] — scheduled tasks
//! 8. [`ReplicationRenderer`] — data extraction, loading and key-function deployment
//! 9. [`StorageRenderer`] — partitioning, compression and index strategy
//! 10. [`DialectCapabilities`] — 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_procedure`] takes the
//! companion table a load sets rows aside in, so one call to a retention
//! procedure reaches both tables.
//! - [`ExpressionRenderer::render_parse_datetime`] renders the parse of a
//! value the source spells its own way into a date or a timestamp.
//! - [`SqlRenderer::delimited_file_relation_in_encoding`] reads 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_query`] asks a running warehouse
//! what it holds, one row per column.
//! - [`SqlRenderer::render_catalog_object_times_query`] asks when each object
//! was created, where the engine records it at all.
//! - [`SqlRenderer::catalog_system_schemas`] names the schemas a
//! whole-warehouse scan passes over, and
//! [`SqlRenderer::catalog_scope_predicate`] is the `WHERE` clause both
//! catalog queries share.
//! - [`ExpressionRenderer::render_parse_number`] renders the reading of a
//! value the source writes its own way into a number.
//! - [`StorageRenderer::slice_replacement_is_procedure_body`] says 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_query`] states how to ask a
//! running server its version, and
//! [`DialectCapabilities::parse_server_version`] reads the answer.
//! - [`ExpressionRenderer::render_read_only_refusal`] stops with a sentence
//! from a statement that only reads, where the engine has one.
//! - [`ProcedureRenderer::render_call_for_each_row`] calls 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.17.0 changes
//!
//! - [`DelimitedFile`] carries how a file is written — its `delimiter`, a
//! [`FileDelimiter`], its `quote`, its `header` and its `encoding` — and
//! is built with [`DelimitedFile::new`] and the `with_` methods.
//! - The default [`SqlRenderer::delimited_file_relation_for`] reads only a
//! plain file ([`DelimitedFile::is_plain`]) and answers `None` for any
//! other.
//!
//! ### What 0.16.0 adds to the method set
//!
//! - [`DdlRenderer::replaces_a_view_that_is_read`] and
//! [`DdlRenderer::render_view_replacement`], with [`ViewReplacement`],
//! [`ViewReader`] and [`ReaderKind`]: a view other objects read, on an
//! engine that will not replace it in place.
//! - [`SqlRenderer::is_reserved_word`] and [`SqlRenderer::render_alias`],
//! over [`reserved_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_extract`] and
//! [`FormulaRenderer::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_call`] replaces
//! `partition_extend_call_before_write`, answering an [`ExtendCall`] that
//! says where the call runs ([`ExtendRuns`]).
//! - [`EntityRef::role`] replaces `is_identity_table`, a [`TableRole`].
//! - New, with a default: [`DialectCapabilities::type_limits`], answering
//! [`TypeLimits`].
//! - [`data_type::TimeDataType::precision`] is an `Option<u8>`, and a
//! timestamp's 0 is whole seconds.
//! - [`number_format::read_with_safe_cast`] and
//! [`number_format::read_with_digit_check`] take a
//! [`number_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_expression`] takes a [`sid::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_unit`] and
//! [`FormulaRenderer::render_bitwise_operator`].
//! - [`TaskRenderer::render_create_task`], [`TaskRenderer::render_bulk_load`]
//! and [`SqlRenderer::render_procedure_log`] answer `Option<String>`.
/// This crate's version, as a plugin was compiled against it.
///
/// A plugin loaded from a directory is refused unless it was built against
/// the same version, from the same source, as the razeri that loads it.
pub const VERSION: &str = env!;
/// A fingerprint of this crate's source. Two builds carrying the same version
/// over different source have different fingerprints.
pub const SOURCE_FINGERPRINT: u64 =
match u64from_str_radix ;
pub use *;
pub use BulkLoadForm;
pub use *;
pub use *;
pub use ;
pub use ;
pub use DialectFamily;
pub use ;
pub use *;
pub use ;
pub use *;
pub use ;
pub use *;
pub use ;
pub use ProcedureLogLevel;
pub use *;
pub use *;
pub use *;
pub use ;
pub use *;
pub use sid_expression;
pub use *;
pub use StoragePlatform;
pub use *;
pub use *;
pub use ;
pub use ;