pub trait DialectCapabilities: DdlRenderer {
Show 58 methods
// Provided methods
fn merge_shape(&self) -> MergeShape { ... }
fn catalogue_reach(&self) -> CatalogueReach { ... }
fn evolution_answers(&self) -> EvolutionAnswers { ... }
fn supports_returning(&self) -> bool { ... }
fn server_version_query(&self) -> Option<&str> { ... }
fn parse_server_version(&self, answer: &str) -> Option<EngineVersion> { ... }
fn supports_cte(&self) -> bool { ... }
fn supports_recursive_cte(&self) -> bool { ... }
fn supports_window_functions(&self) -> bool { ... }
fn supports_qualify(&self) -> bool { ... }
fn supports_groups_frame(&self) -> bool { ... }
fn supports_nulls_ordering(&self) -> bool { ... }
fn supports_identity(&self) -> bool { ... }
fn supports_sequences(&self) -> bool { ... }
fn supports_schemas(&self) -> bool { ... }
fn routine_is_callable_across_schemas(&self) -> bool { ... }
fn supports_bulk_load(&self) -> bool { ... }
fn supports_stored_procedures(&self) -> bool { ... }
fn supports_stored_functions(&self) -> bool { ... }
fn supports_table_functions(&self) -> bool { ... }
fn supports_tasks(&self) -> bool { ... }
fn supports_partitioning(&self) -> bool { ... }
fn supports_materialized_views(&self) -> bool { ... }
fn supports_generated_columns(&self) -> bool { ... }
fn supports_json(&self) -> bool { ... }
fn supports_unsigned_integers(&self) -> bool { ... }
fn supports_arrays(&self) -> bool { ... }
fn renders_nested_type_natively(&self, data_type: &DataType) -> bool { ... }
fn compares_nested_values(&self, data_type: &DataType) -> bool { ... }
fn groups_nested_values(&self, data_type: &DataType) -> bool { ... }
fn supports_boolean(&self) -> bool { ... }
fn default_schema(&self) -> &'static str { ... }
fn max_identifier_length(&self) -> usize { ... }
fn max_columns(&self) -> usize { ... }
fn max_parameters(&self) -> usize { ... }
fn decimal_limits(&self) -> Option<DecimalLimits> { ... }
fn text_limits(&self) -> Option<TextLimits> { ... }
fn type_limits(&self) -> Option<TypeLimits> { ... }
fn keeps_a_time_zone(&self) -> bool { ... }
fn supports_function_overloading(&self) -> bool { ... }
fn supports_merge_star_syntax(&self) -> bool { ... }
fn schema_namespace_keyword(&self) -> &'static str { ... }
fn supports_hash_comments(&self) -> bool { ... }
fn batch_separator(&self) -> Option<&'static str> { ... }
fn supports_multi_statement_transactions(&self) -> bool { ... }
fn begin_transaction_keyword(&self) -> &'static str { ... }
fn commit_transaction_keyword(&self) -> &'static str { ... }
fn begin_leaves_the_commit_to_the_client(&self) -> bool { ... }
fn truncate_commits_implicitly(&self) -> bool { ... }
fn refusal_stops_the_statement(&self) -> bool { ... }
fn delimited_file_reads_null_word_as_missing(&self) -> bool { ... }
fn supports_partition_function(&self) -> bool { ... }
fn supports_partition_split_merge(&self) -> bool { ... }
fn supports_columnstore_index(&self) -> bool { ... }
fn columnstore_is_table_engine(&self) -> bool { ... }
fn supports_clustering_key(&self) -> bool { ... }
fn supports_table_compression(&self) -> bool { ... }
fn partition_requires_pk_includes_field(&self) -> bool { ... }
}Expand description
Level 6 — Boolean capability flags with conservative defaults.
These flags tell the rendering layer what syntax features the platform supports.
Defaults are false / conservative, so unknown platforms produce safe ANSI SQL.
§A fact is stated once
Thirteen facts about the statements an engine takes are asked both here and
of the renderer a statement is written with, and they are stated only on
the renderer: ten on SqlRenderer —
supports_on_conflict, supports_insert_overwrite, supports_update_from,
supports_named_windows, supports_compound_assignment,
supports_window_frame_exclude, supports_merge_not_matched_by_source,
merge_not_matched_keyword, uses_alter_table_update and
supports_multi_table_insert — and three on DdlRenderer —
supports_cascade_drop, supports_sync_drop and supports_force_drop.
This trait requires DdlRenderer, and so SqlRenderer,
so a reader holding only the capabilities still asks
capabilities.supports_on_conflict() and hears the renderer’s answer. There
is no second answer to keep equal, and stating one here does not compile:
use razeri_plugin_contract::{DataType, DdlRenderer, DialectCapabilities, SqlRenderer};
struct MyDb;
impl SqlRenderer for MyDb {
fn render_data_type(&self, _dt: &DataType) -> String { "TEXT".into() }
fn quote_identifier(&self, name: &str) -> String { format!("\"{name}\"") }
fn qualify_name(&self, _schema: Option<&str>, name: &str) -> String { name.into() }
fn render_current_timestamp(&self) -> String { "CURRENT_TIMESTAMP".into() }
}
impl DdlRenderer for MyDb {}
impl DialectCapabilities for MyDb {
// The renderer is where this is said.
fn supports_on_conflict(&self) -> bool { true }
}Ask one of the thirteen by its path as SqlRenderer::supports_on_conflict(&d)
or DdlRenderer::supports_cascade_drop(&d); a path through this trait does
not reach a method it inherits.
Provided Methods§
Sourcefn merge_shape(&self) -> MergeShape
fn merge_shape(&self) -> MergeShape
How this engine performs the upsert Razeri’s generated load is.
See MergeShape. The default is a refusal, because the honest answer
for an engine nobody has measured is that Razeri does not know how to
load it — not that it spells its upsert the way MySQL does.
Sourcefn catalogue_reach(&self) -> CatalogueReach
fn catalogue_reach(&self) -> CatalogueReach
How much of the deployed schema a reconciliation can compare with the design here.
Razeri’s schema check reads the engine’s catalogue in one query: the
ANSI information_schema.columns, a FULL OUTER JOIN against the
design’s own columns, and a table value constructor with a derived
column list, (VALUES ('a'), ('b')) AS designed (column_name). See
CatalogueReach. The default is
CatalogueReach::Nothing with a sentence saying Razeri has not
written this engine’s catalogue query: an engine nobody has measured
gets no check, and a warning that says why, rather than a query that
fails.
Sourcefn evolution_answers(&self) -> EvolutionAnswers
fn evolution_answers(&self) -> EvolutionAnswers
What this engine keeps when a table that already holds rows changes shape.
See EvolutionAnswers. The default answers nothing, which Razeri
reads as nobody has measured this engine — so a change Razeri cannot
otherwise prove keeps every value is reported as one that does not, and
an operator gets a warning they can read instead of a surprise.
Sourcefn supports_returning(&self) -> bool
fn supports_returning(&self) -> bool
Whether the platform supports RETURNING / OUTPUT clauses.
Sourcefn server_version_query(&self) -> Option<&str>
fn server_version_query(&self) -> Option<&str>
How to ask a running server its version, or None where this
engine has no version a user chooses, or nobody has written the
question.
The query answers one row whose first word is the version in the
spelling this dialect declares (17, 8.4, 23ai); anything after it
is the server’s own words, which a refusal prints. A generated deploy
script sends it after login and before the schema, and refuses a server
older than the version the bundle was rendered for, naming both. The
default is None, and a script that has no question asks none.
Sourcefn parse_server_version(&self, answer: &str) -> Option<EngineVersion>
fn parse_server_version(&self, answer: &str) -> Option<EngineVersion>
The version in one answer to Self::server_version_query, or
None when the answer holds none.
Parameters:
answer: the one row the query answered, as text.
The default reads the first word, which is what a deploy script reads too; override it only to read more of the answer than that.
Sourcefn supports_cte(&self) -> bool
fn supports_cte(&self) -> bool
Whether the platform supports Common Table Expressions (WITH).
Sourcefn supports_recursive_cte(&self) -> bool
fn supports_recursive_cte(&self) -> bool
Whether the platform supports recursive CTEs.
Sourcefn supports_window_functions(&self) -> bool
fn supports_window_functions(&self) -> bool
Whether the platform supports window functions.
Sourcefn supports_qualify(&self) -> bool
fn supports_qualify(&self) -> bool
Whether the platform supports QUALIFY clause.
Sourcefn supports_groups_frame(&self) -> bool
fn supports_groups_frame(&self) -> bool
Whether the platform supports GROUPS frame type in window functions.
Sourcefn supports_nulls_ordering(&self) -> bool
fn supports_nulls_ordering(&self) -> bool
Whether the platform supports NULLS FIRST/LAST in ORDER BY.
Sourcefn supports_identity(&self) -> bool
fn supports_identity(&self) -> bool
Whether the platform supports IDENTITY columns.
Sourcefn supports_sequences(&self) -> bool
fn supports_sequences(&self) -> bool
Whether the platform supports sequences (CREATE SEQUENCE).
Sourcefn supports_schemas(&self) -> bool
fn supports_schemas(&self) -> bool
Whether the platform supports schema namespacing.
Sourcefn routine_is_callable_across_schemas(&self) -> bool
fn routine_is_callable_across_schemas(&self) -> bool
Can a routine created in one schema be called from a routine created in another, with nothing else done?
True nearly everywhere, and true by default: a schema on most engines is a namespace, and naming an object in another namespace is all that reaching it takes.
Answer false where a schema is also an owner and reaching across one
costs a privilege granted per object. On Oracle a schema IS a user; a
routine runs with its owner’s privileges, so a function created in
acme_core calling one created in acme_raw compiles with errors —
ORA-60535: invalid identifier, measured — however exactly it spells
the name.
Razeri reads no answer from it: every layer schema that computes a key
holds its own copy of the key function on every engine, so a layer can
move to another database without the others, and no key function calls
another layer’s whatever this says. The one routine a key function may
call outside its own schema is the hash a prerequisite installs once,
and where that lives is
ReplicationRenderer::sid_prerequisite_home,
whose install carries its own grant.
Sourcefn supports_bulk_load(&self) -> bool
fn supports_bulk_load(&self) -> bool
Whether the platform supports bulk load (COPY, BULK INSERT, etc.).
Sourcefn supports_stored_procedures(&self) -> bool
fn supports_stored_procedures(&self) -> bool
Whether a generated load is written as a stored procedure on this engine.
Razeri asks this before it writes a load as a procedure, and asks
SqlRenderer::procedure_form
how to spell one. The default is false, and a load is then written as
plain statements. A dialect that answers procedure_form with
ProcedureForm::Custom answers true here, or its procedures are
never asked for; one that answers ProcedureForm::Unsupported leaves
this false. The conformance report holds the two to each other.
Sourcefn supports_stored_functions(&self) -> bool
fn supports_stored_functions(&self) -> bool
Whether the platform stores functions at all — a routine the schema creates and later calls by name, in any spelling.
Nearly every engine razeri reaches has one: CREATE FUNCTION on
PostgreSQL, MySQL, MariaDB, Snowflake, SQL Server and Databricks,
a MACRO on DuckDB, a lambda CREATE FUNCTION on ClickHouse.
SQLite answers false, and it is the reason this question is asked
out loud. SQLite has no CREATE FUNCTION statement in any spelling
and no CREATE PROCEDURE either — a function there is registered by the
program that opens the database, so nothing written into a schema script
can create one. Inheriting the PostgreSQL form wrote
CREATE OR REPLACE FUNCTION … LANGUAGE SQL RETURN … into schema.sql,
which SQLite answers with near "CREATE": syntax error part way
through the script, so the build refuses in front of the script instead.
The default is true, matching Self::supports_table_functions and
for the same reason: refusing is the destructive answer, so a refusal
fires only where an engine is KNOWN to have no form, never because a
dialect forgot to answer. That reverses the conservative-false default
this trait uses for flags that add syntax — here false is the
unusual claim, and it is made deliberately, one dialect at a time.
Sourcefn supports_table_functions(&self) -> bool
fn supports_table_functions(&self) -> bool
Whether the platform has a table-valued function — a routine a query selects FROM, returning columns rather than one value.
Most engines have one in some spelling: RETURNS TABLE(…) on
PostgreSQL, Snowflake and Databricks, an inline TVF on SQL Server, a
table MACRO on DuckDB, a parameterized view on ClickHouse.
MySQL and MariaDB answer false, and they are the reason this
question exists. A stored function there returns exactly one value;
there is no clause that returns a relation, in any spelling. Rendering
RETURNS TABLE for them produced ERROR 1064 … syntax error in the
middle of a schema script (measured on MySQL 8.4 and MariaDB 11.4),
so the build refuses in front of the script instead.
The default is true: a refusal fires only where an engine is KNOWN to
have no form, never because a dialect forgot to answer.
Sourcefn supports_tasks(&self) -> bool
fn supports_tasks(&self) -> bool
Whether the platform supports tasks / scheduled jobs.
Sourcefn supports_partitioning(&self) -> bool
fn supports_partitioning(&self) -> bool
Whether the platform supports native table partitioning.
Sourcefn supports_materialized_views(&self) -> bool
fn supports_materialized_views(&self) -> bool
Whether the platform supports materialized views.
Sourcefn supports_generated_columns(&self) -> bool
fn supports_generated_columns(&self) -> bool
Whether the platform supports generated/computed columns.
Sourcefn supports_json(&self) -> bool
fn supports_json(&self) -> bool
Whether the platform supports JSONB or native JSON type.
Sourcefn supports_unsigned_integers(&self) -> bool
fn supports_unsigned_integers(&self) -> bool
Whether the platform supports unsigned integers natively.
Sourcefn supports_arrays(&self) -> bool
fn supports_arrays(&self) -> bool
Whether the platform supports arrays natively.
Sourcefn renders_nested_type_natively(&self, data_type: &DataType) -> bool
fn renders_nested_type_natively(&self, data_type: &DataType) -> bool
Whether this engine has a type of its own for a nested type, or stores it as something else.
A nested column is an array, a map or a record. Some engines have all three; some have one; some have none and hold the value as JSON or as text. Razeri never refuses the column — the design is portable and it is the storage that degrades — but it does say so once, naming the engine, the columns and what each became.
The default is false, which is the honest answer for an engine nobody
has answered for: the reader is told what the column became rather than
left to assume the type survived.
Parameters:
data_type: the nested type in question.
Sourcefn compares_nested_values(&self, data_type: &DataType) -> bool
fn compares_nested_values(&self, data_type: &DataType) -> bool
Whether this engine can tell two values of a nested type apart.
Change detection asks whether an arriving value differs from the
standing one. For a scalar every engine answers with <>. For a nested
value they do not agree: some compare arrays, maps and records directly,
some refuse the comparison outright, and some hold the value as text and
compare the text. A column this returns false for is left out of
change detection and named in a note, rather than compared with an
operator the engine will reject.
The default is false — an unanswered engine leaves the column
unwatched and says so, which is the failure that can be read.
Parameters:
data_type: the nested type in question.
Sourcefn groups_nested_values(&self, data_type: &DataType) -> bool
fn groups_nested_values(&self, data_type: &DataType) -> bool
Whether this engine can collapse rows on a nested column — group by it, or select distinct over it.
A load reads its staged rows through one collapsed form so that a row
stated twice, identically, is one arriving row rather than a conflict.
The plain spelling of that collapse is SELECT DISTINCT over every
column, and grouping is what DISTINCT is: an engine that will not
group a value of a nested type will not take the column in a DISTINCT
either.
It is a separate question from Self::compares_nested_values, and the
two engines that answer them differently are the reason it is asked
separately: BigQuery compares two records with = and refuses to group
on one.
Where the answer is false the collapse is written as a GROUP BY over
the other columns with crate::SqlRenderer::render_any_value around
this one.
The default is true: SELECT DISTINCT over every column is the plain
spelling, and an engine says otherwise only where somebody has found
that it refuses.
Asked only of a nested type — an array, a map or a record. The answer for anything else is not read.
Parameters:
data_type: the nested type in question.
Sourcefn supports_boolean(&self) -> bool
fn supports_boolean(&self) -> bool
Whether the platform supports native BOOLEAN type (vs BIT).
Sourcefn default_schema(&self) -> &'static str
fn default_schema(&self) -> &'static str
The default schema name for this platform.
Sourcefn max_identifier_length(&self) -> usize
fn max_identifier_length(&self) -> usize
Maximum identifier length for this platform.
Sourcefn max_columns(&self) -> usize
fn max_columns(&self) -> usize
Maximum number of columns in a table (approximate).
Sourcefn max_parameters(&self) -> usize
fn max_parameters(&self) -> usize
Maximum query parameters (approximate, 0 = unlimited).
Sourcefn decimal_limits(&self) -> Option<DecimalLimits>
fn decimal_limits(&self) -> Option<DecimalLimits>
The widest exact decimal a column on this platform holds, where it has been measured against the engine.
A type over it is refused by name rather than rendered: the engine
would refuse the CREATE TABLE anyway, later and in its own words.
The default is None, which means not measured here, not no
limit. An engine with no limit at all says so in its own doc comment
and still answers None.
Sourcefn text_limits(&self) -> Option<TextLimits>
fn text_limits(&self) -> Option<TextLimits>
What a text column on this platform holds, where it has been
measured against the engine or read from its documentation (see
TextLimits).
The default is None, which means not recorded here, not no
limit. Measure the longest varchar(n) your engine creates — one
more is refused at CREATE TABLE — and say how it counts it.
Sourcefn type_limits(&self) -> Option<TypeLimits>
fn type_limits(&self) -> Option<TypeLimits>
What this engine’s other columns hold — the digits of a second a
timestamp and a time of day keep, and the longest char(n),
binary(n) and varbinary(n) (see TypeLimits).
A type over a stated limit is refused by name before anything is
rendered. The default is None: nothing is stated, and nothing is
refused for this engine, which then refuses the CREATE TABLE later in
its own words. Measure each the way the varchar is measured — the most
your engine creates, one more refused — and leave None in a field
your engine stores with no limit.
Sourcefn keeps_a_time_zone(&self) -> bool
fn keeps_a_time_zone(&self) -> bool
Whether this engine has a type that keeps a time zone, for a
timestamptz column: a moment that keeps its offset, or one read in
the session’s zone. The default is true. An engine with no such type
answers false, and a timestamptz column is refused by name rather
than stored as a clock time two hours off the moment the file named.
Sourcefn supports_function_overloading(&self) -> bool
fn supports_function_overloading(&self) -> bool
Whether DROP FUNCTION requires parameter types for overloaded functions.
Sourcefn supports_merge_star_syntax(&self) -> bool
fn supports_merge_star_syntax(&self) -> bool
Whether the platform supports UPDATE SET * / INSERT * in MERGE.
Sourcefn schema_namespace_keyword(&self) -> &'static str
fn schema_namespace_keyword(&self) -> &'static str
The SQL keyword for the schema-level namespace.
Most platforms use SCHEMA (CREATE SCHEMA IF NOT EXISTS ...).
ClickHouse uses DATABASE (CREATE DATABASE IF NOT EXISTS ...).
Sourcefn supports_hash_comments(&self) -> bool
fn supports_hash_comments(&self) -> bool
Whether the platform supports # as a single-line comment delimiter.
Default: false. A dialect whose engine accepts # as a single-line
comment delimiter overrides this.
Sourcefn batch_separator(&self) -> Option<&'static str>
fn batch_separator(&self) -> Option<&'static str>
Batch separator keyword required between DDL statements in a script.
SQL Server / T-SQL requires GO between CREATE FUNCTION, CREATE VIEW,
and CREATE PROCEDURE statements. Other platforms return None and use
double-newlines between statements.
Sourcefn supports_multi_statement_transactions(&self) -> bool
fn supports_multi_statement_transactions(&self) -> bool
Whether several statements in a script can be committed or discarded together as one unit.
A generated load is a sequence of writes that only make sense finished.
An SCD-2 load, for instance, closes the standing version into _history
and then re-opens _current on the new attributes; a process that dies
between the two leaves a closed version that _current still holds open,
and because _history is keyed on (surrogate, version start), the next
load writes the same key again and the engine refuses it. Every load
after the crash fails until somebody deletes that row by hand.
Wrapping the load in one transaction is what makes the crash a no-op
instead. This flag says whether the platform offers that at all. It
defaults to true because a transaction spanning several statements is
core SQL and nearly every engine has it; a platform that does not
overrides it, and the load script then says plainly that the operator
owns the boundary.
Sourcefn begin_transaction_keyword(&self) -> &'static str
fn begin_transaction_keyword(&self) -> &'static str
How this platform opens a transaction.
The ANSI spelling, which MySQL and MariaDB also use. DuckDB,
SQLite, SQL Server and Snowflake say BEGIN TRANSACTION;
PostgreSQL and Citus say BEGIN.
Sourcefn commit_transaction_keyword(&self) -> &'static str
fn commit_transaction_keyword(&self) -> &'static str
How this platform commits one.
COMMIT everywhere razeri reaches except SQL Server, which spells it
COMMIT TRANSACTION.
Sourcefn begin_leaves_the_commit_to_the_client(&self) -> bool
fn begin_leaves_the_commit_to_the_client(&self) -> bool
Whether this engine’s begin statement leaves the commit to the client.
On most engines begin_transaction_keyword
opens a transaction that holds every statement after it until the
commit, whatever the client does. On some it only names the
transaction — Oracle’s and SAP HANA’s SET TRANSACTION READ WRITE —
and a driver that commits each statement on its own still does, so a
load run that way keeps what it wrote when it stops part way.
Razeri’s own deploy scripts drive clients whose commit is off. Answer
true where the engine needs that of the client, and the bundle tells
whoever runs a load another way — a scheduler running the task list —
to turn its client’s commit off. The default is false.
Sourcefn truncate_commits_implicitly(&self) -> bool
fn truncate_commits_implicitly(&self) -> bool
Whether emptying a table with TRUNCATE ends the open transaction.
On some engines TRUNCATE TABLE commits everything before it and
cannot be rolled back: MySQL and MariaDB, which treat it as a
schema change, and Oracle, SAP HANA, BigQuery and Redshift. A
generated load empties its staging table only as its last statement,
after every write it makes, so on those engines the clear commits the
load with it and each load stands on its own; a load that stops before
it leaves nothing behind. Everywhere else TRUNCATE is an ordinary
statement inside the transaction.
Sourcefn refusal_stops_the_statement(&self) -> bool
fn refusal_stops_the_statement(&self) -> bool
Whether a load’s refusal stops the statement that asks it.
A generated load stops itself by building a sentence about the rows it
refuses and asking the engine for
ExpressionRenderer::render_refusal
of it: the engine refuses and quotes the sentence back in its error.
Most engines do. MySQL and MariaDB answer the default refusal, a
conversion to a number, with a warning and 0, and Spark answers
NULL where ANSI mode is off. There the load stops on a second
statement instead, in the engine’s own words and without the sentence,
so a deploy script reads the refused rows back and prints them itself.
The default is true, the answer of every engine whose refusal stops.
Sourcefn delimited_file_reads_null_word_as_missing(&self) -> bool
fn delimited_file_reads_null_word_as_missing(&self) -> bool
Whether this engine’s file reader may read a field holding just the
word NULL as a missing value rather than as the four letters.
A design names the words that mean “no value” in each file, and a
binding that names none calls NULL missing, which every engine then
agrees on. A file that keeps NULL as text cannot be read that way
here, so the bundle names the file, and a reconciliation does not
compare the characters of a text column holding the word. The default
is false: the engine keeps the text, as every engine’s own file
reader does except MySQL’s and MariaDB’s LOAD DATA.
Sourcefn supports_partition_function(&self) -> bool
fn supports_partition_function(&self) -> bool
Whether the platform supports a server-side partition function definable
at design time (T-SQL PARTITION FUNCTION, PostgreSQL PARTITION BY,
MySQL PARTITION BY, ClickHouse PARTITION BY).
Snowflake / DuckDB return false because micro-partitioning is automatic
and not user-definable.
Sourcefn supports_partition_split_merge(&self) -> bool
fn supports_partition_split_merge(&self) -> bool
Whether the platform supports adding/removing partition boundaries on a
live table (T-SQL ALTER PARTITION FUNCTION SPLIT/MERGE RANGE,
PostgreSQL ATTACH/DETACH PARTITION, MySQL REORGANIZE PARTITION).
Sourcefn supports_columnstore_index(&self) -> bool
fn supports_columnstore_index(&self) -> bool
Whether the platform supports a columnstore index (T-SQL clustered/non-clustered
columnstore; ClickHouse via MergeTree engine; not natively in PostgreSQL / MySQL).
Sourcefn columnstore_is_table_engine(&self) -> bool
fn columnstore_is_table_engine(&self) -> bool
Whether the platform realizes a columnstore as a table storage engine
rather than an index (MariaDB ENGINE=ColumnStore). This is deliberately
distinct from Self::supports_columnstore_index: a design that asks for
index: { kind: clustered_columnstore } is honoured on such a platform by
selecting the engine, but it must NOT inherit the T-SQL
index machinery — the composite-PK demotion to UNIQUE NONCLUSTERED keys
off supports_columnstore_index, and an engine-columnstore keeps its
ordinary primary key. So the two capabilities are separate axes: “supports
columnstore at all” is the disjunction of them.
Sourcefn supports_clustering_key(&self) -> bool
fn supports_clustering_key(&self) -> bool
Whether the platform has a clustering-key concept distinct from primary key
(Snowflake CLUSTER BY, Delta Liquid Clustering / Z-ORDER, ClickHouse ORDER BY).
Sourcefn supports_table_compression(&self) -> bool
fn supports_table_compression(&self) -> bool
Whether the platform supports user-controllable table compression
(T-SQL DATA_COMPRESSION = PAGE/ROW/COLUMNSTORE, MySQL ROW_FORMAT=COMPRESSED,
ClickHouse CODEC(ZSTD), Delta delta.compressionCodec).
Sourcefn partition_requires_pk_includes_field(&self) -> bool
fn partition_requires_pk_includes_field(&self) -> bool
Whether the platform requires every column referenced by the partition key to also appear in the table’s PRIMARY KEY (or any UNIQUE constraint).
PostgreSQL enforces this with SQLSTATE 0A000 (“unique constraint on
partitioned table must include all partitioning columns”). T-SQL,
MySQL, ClickHouse, Snowflake, and DuckDB do not impose this
restriction.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".