Skip to main content

squonk_ast/dialect/
hive.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 Moderately AI Inc.
3
4//! The Hive / HiveQL dialect preset (ANSI-derived, deliberately conservative).
5//!
6//! Apache Hive's HiveQL diverges widely across its type, function, and statement surface, and
7//! — unlike the five shipped oracle-compared presets — this workspace has **no Hive oracle**,
8//! so over-acceptance cannot be measured. Conservatism is therefore the honesty bar: this
9//! preset derives from [`FeatureSet::ANSI`], the strict standard baseline, and enables only the
10//! Hive surface that already has a modelled, tested parser gate and clear documentary evidence
11//! — in the headline case the flag's *own* doc names Hive as a motivating dialect. Every other
12//! axis keeps its ANSI value; a reader can predict from this module exactly what Hive accepts
13//! beyond the standard, and unsupported Hive syntax is a clean reject routed to a focused
14//! follow-up ticket, never a silent over-accept.
15//!
16//! # What this preset adds over ANSI
17//!
18//! Two grammar gates carry the headline Hive surface:
19//!
20//! - [`sided_semi_anti_join`](JoinSyntax::sided_semi_anti_join) — the
21//!   `{LEFT|RIGHT} {SEMI|ANTI} JOIN` sided semi-/anti-join spelling, whose flag doc names
22//!   Spark/Hive/Databricks as the motivating family. Hive is the dialect that *originated* the
23//!   `LEFT SEMI JOIN`; the Databricks preset already turned this flag on, and Hive is the
24//!   second engine preset to enable it. The leading `LEFT`/`RIGHT` is already a reserved join
25//!   side, so no reserved-word interplay is needed (the preceding factor's alias can never
26//!   swallow it). See the over-acceptance deferral note below.
27//! - [`lateral_view_clause`](SelectSyntax::lateral_view_clause) — the
28//!   `LATERAL VIEW [OUTER] explode(col) t [AS a, b]` table-generating clause Hive
29//!   originated (LanguageManual LateralView: `fromClause: FROM baseTable (lateralView)*`).
30//!   The derived-table `LATERAL` factor stays off, so `LATERAL` leads only this clause
31//!   under the preset. See the `AS`-optional over-acceptance deferral note below.
32//!
33//! # The two lexical facts over ANSI
34//!
35//! - **Backtick identifier quoting.** Hive quotes identifiers with the backtick `` `name` ``
36//!   alone (its default `hive.support.quoted.identifiers=column` mode), and its `"…"` and `'…'`
37//!   are *both* string literals — HiveQL string literals may be written with single or double
38//!   quotes. So [`HIVE_IDENTIFIER_QUOTES`] lists only the backtick (unlike the
39//!   SQLite/Databricks/MSSQL bracket-or-double-quote sets, and unlike ANSI's `"…"`), and
40//!   [`double_quoted_strings`](StringLiteralSyntax::double_quoted_strings) is correspondingly
41//!   **on** so `"x"` lexes as a string, never an identifier — exactly the MySQL default
42//!   (`ANSI_QUOTES` off) lexis, and the same shape the BigQuery preset ships. The two facts are
43//!   coupled: `"` has a single claimant (the string scanner) precisely because it is absent
44//!   from the quote set, the [`DoubleQuoteStringVersusIdentifier`](super::LexicalConflict)
45//!   hazard the `const` assert below rules out. The backtick likewise has a single claimant —
46//!   no enabled expression grammar lexes a backtick.
47//! - **Case folding.** Hive resolves unquoted identifiers case-insensitively (its metastore
48//!   lowercases table and column names), so [`identifier_casing`](FeatureSet::identifier_casing)
49//!   is [`Casing::Lower`] — the value the [`Casing`] doc prescribes for the "case-preserving
50//!   storage, case-insensitive comparison" model it describes for MySQL/T-SQL columns. Hive is
51//!   uniformly case-insensitive (it lacks even the case-sensitive-table split that paragraph
52//!   flags as the single-fold known limitation), so the fit is exact. The interned text still
53//!   renders exactly as written; the fold is identity-only and never affects acceptance.
54//!
55//! # Deliberately deferred (conservative reject)
56//!
57//! - **`RIGHT`/`ANTI` sided joins.** Classic Hive documents only `LEFT SEMI JOIN` (and later
58//!   `LEFT ANTI JOIN`); the atomic [`sided_semi_anti_join`](JoinSyntax::sided_semi_anti_join) flag also admits the `RIGHT`-sided
59//!   spelling and the `ANTI` flavour across both sides — a known conservative-direction
60//!   over-acceptance a future side-refinement (or a Hive oracle) would tighten. This mirrors
61//!   the deferral the Databricks preset recorded for the same atomic flag; captured on the
62//!   owning ticket rather than split into a narrower gate that no measured boundary yet
63//!   justifies.
64//! - **`AS`-less lateral-view column aliases.** Hive's grammar requires the `AS` before a
65//!   lateral view's column aliases; Spark's spells it `AS?`, and the one atomic
66//!   [`lateral_view_clause`](SelectSyntax::lateral_view_clause) gate accepts the wider
67//!   Spark bound — a known conservative-direction over-acceptance for this preset, the
68//!   same class as the sided-join deferral above (see the [`LateralView`](crate::ast::LateralView)
69//!   acceptance-bound doc); captured on the owning ticket.
70//!
71//! Everything else Hive (the `STRUCT`/`ARRAY<…>`/`MAP<…>` complex type surface,
72//! `TRANSFORM`/`MAP`/`REDUCE` script operators, `DISTRIBUTE BY`/`SORT BY`/`CLUSTER BY` clauses,
73//! `TABLESAMPLE` bucketing, backslash string escapes, …) has no modelled gate and is a clean
74//! reject routed to follow-up tickets, never a silent over-accept.
75
76use super::{
77    AccessControlSyntax, AggregateCallSyntax, CallSyntax, CaretOperator, Casing,
78    ColumnDefinitionSyntax, CommentSyntax, ConstraintSyntax, CreateTableClauseSyntax,
79    DoubleAmpersand, ExistenceGuards, ExpressionSyntax, FeatureSet, GroupingSyntax,
80    IdentifierQuote, IdentifierSyntax, IndexAlterSyntax, JoinSyntax, KeywordOperators, KeywordSet,
81    MaintenanceSyntax, MutationSyntax, NullOrdering, NumericLiteralSyntax, OperatorSyntax,
82    ParameterSyntax, PipeOperator, PredicateSyntax, QueryTailSyntax, RESERVED_BARE_ALIAS,
83    RESERVED_COLUMN_NAME, RESERVED_FUNCTION_NAME, RESERVED_TYPE_NAME, STANDARD_BYTE_CLASSES,
84    SelectSyntax, SessionVariableSyntax, ShowSyntax, StatementDdlGates, StringFuncForms,
85    StringLiteralSyntax, TableExpressionSyntax, TableFactorSyntax, TargetSpelling,
86    TransactionSyntax, TypeNameSyntax, UtilitySyntax, ViewSequenceClauseSyntax,
87};
88use crate::precedence::{STANDARD_BINDING_POWERS, STANDARD_SET_OPERATION_BINDING_POWERS};
89
90/// Hive identifier quoting: the backtick `` `…` `` alone. Hive spells a quoted identifier
91/// `` `a` `` (its default `hive.support.quoted.identifiers=column` mode); its `"a"` and `'a'`
92/// are *both* string constants, so `"` is deliberately absent here (and
93/// [`StringLiteralSyntax::HIVE`] turns `double_quoted_strings` on so `"` unambiguously lexes a
94/// string) — the same backtick-only lexis MySQL uses under its default `ANSI_QUOTES`-off mode.
95pub const HIVE_IDENTIFIER_QUOTES: &[IdentifierQuote] = &[IdentifierQuote::Symmetric('`')];
96
97impl StringLiteralSyntax {
98    /// Hive string surface: the ANSI baseline plus `"…"` double-quoted string constants (HiveQL
99    /// string literals may be written with single *or* double quotes, reserving the backtick
100    /// for identifiers). Enabling this is what lets [`HIVE_IDENTIFIER_QUOTES`] drop `"` from the
101    /// quote set without stranding the byte. Every other string knob is conservatively ANSI —
102    /// Hive's backslash escape sequences have no Hive-citing flag doc or oracle here and are
103    /// deferred rather than guessed at (`backslash_escapes` stays off).
104    pub const HIVE: Self = Self {
105        double_quoted_strings: true,
106        escape_strings: false,
107        dollar_quoted_strings: false,
108        national_strings: false,
109        backslash_escapes: false,
110        unicode_strings: false,
111        bit_string_literals: false,
112        blob_literals: false,
113        charset_introducers: false,
114        same_line_adjacent_concat: false,
115    };
116}
117
118impl TableExpressionSyntax {
119    /// Hive table-expression surface: the ANSI baseline plus the sided
120    /// `{LEFT|RIGHT} {SEMI|ANTI} JOIN` family, whose flag doc names Hive as a motivating
121    /// dialect (Hive originated `LEFT SEMI JOIN`). The side-less DuckDB spelling
122    /// (`semi_anti_join`) stays off — it is a different engine family and needs `SEMI`/`ANTI`
123    /// bare-alias reservation modelling not done here. Every other table knob is conservatively
124    /// ANSI.
125    pub const HIVE: Self = Self {
126        only: false,
127        table_sample: false,
128        parenthesized_joins: true,
129        table_alias_column_lists: true,
130        join_using_alias: false,
131        index_hints: false,
132        table_hints: false,
133        partition_selection: false,
134        base_table_alias_column_lists: true,
135        string_literal_aliases: false,
136        aliased_parenthesized_join: true,
137        bare_table_alias_is_bare_label: false,
138        table_version: false,
139        table_json_path: false,
140        indexed_by: false,
141        prefix_colon_alias: false,
142    };
143}
144
145impl JoinSyntax {
146    /// The `HIVE` preset for join syntax.
147    pub const HIVE: Self = Self {
148        sided_semi_anti_join: true,
149        stacked_join_qualifiers: true,
150        full_outer_join: true,
151        natural_cross_join: false,
152        straight_join: false,
153        asof_join: false,
154        positional_join: false,
155        semi_anti_join: false,
156        apply_join: false,
157        recursive_search_cycle: false,
158        recursive_union_rejects_order_limit: false,
159        recursive_using_key: false,
160    };
161}
162
163impl TableFactorSyntax {
164    /// The `HIVE` preset for table factor syntax.
165    pub const HIVE: Self = Self {
166        lateral: false,
167        table_functions: false,
168        rows_from: false,
169        unnest: false,
170        unnest_with_offset: false,
171        table_function_ordinality: false,
172        special_function_table_source: true,
173        pivot: false,
174        unpivot: false,
175        show_ref: false,
176        from_values: false,
177        json_table: false,
178        xml_table: false,
179        table_expr_factor: false,
180        pivot_value_sources: false,
181        match_recognize: false,
182        open_json: false,
183    };
184}
185
186impl SelectSyntax {
187    /// Hive SELECT surface: the ANSI baseline plus the `LATERAL VIEW` table-generating
188    /// clause Hive originated (LanguageManual LateralView). The derived-table `LATERAL`
189    /// factor ([`TableFactorSyntax::HIVE`]) stays off, so `LATERAL` leads only this
190    /// clause under the preset. Every other SELECT knob is conservatively ANSI.
191    pub const HIVE: Self = Self {
192        lateral_view_clause: true,
193        distinct_on: false,
194        select_into: false,
195        empty_target_list: false,
196        qualify: false,
197        alias_string_literals: false,
198        bare_alias_string_literals: false,
199        union_by_name: false,
200        wildcard_modifiers: false,
201        wildcard_replace: false,
202        intersect_all: true,
203        except_all: true,
204        qualified_wildcard_alias: false,
205        from_first: false,
206        explicit_table: true,
207        parenthesized_query_operands: true,
208        values_rows_require_equal_arity: false,
209        values_row_constructor: true,
210        as_alias_rejects_reserved: false,
211        trailing_comma: false,
212        prefix_colon_alias: false,
213        connect_by_clause: false,
214    };
215}
216
217impl FeatureSet {
218    /// Hive / HiveQL as ANSI-derived dialect data (see the module docs for the full derivation
219    /// rationale and the conservatism bar).
220    pub const HIVE: Self = Self {
221        // Hive resolves unquoted identifiers case-insensitively (its metastore lowercases table
222        // and column names); `Casing::Lower` is the exact fit (Hive lacks even the
223        // case-sensitive-table split the `Casing` known-limitation paragraph flags). Identity
224        // only — the interned text still renders exactly as written, so this never affects
225        // acceptance.
226        identifier_casing: Casing::Lower,
227        // The lexical delta over ANSI: backtick-only identifier quoting (with `"` handed to the
228        // string scanner via `double_quoted_strings` below).
229        identifier_quotes: HIVE_IDENTIFIER_QUOTES,
230        default_null_ordering: NullOrdering::NullsLast,
231        // No reserved-set delta over ANSI — this conservative preset adds no keyword
232        // reservation (the sided-join gate rides the already-reserved LEFT/RIGHT join sides).
233        reserved_column_name: RESERVED_COLUMN_NAME,
234        reserved_function_name: RESERVED_FUNCTION_NAME,
235        reserved_type_name: RESERVED_TYPE_NAME,
236        reserved_bare_alias: RESERVED_BARE_ALIAS,
237        reserved_as_label: KeywordSet::EMPTY,
238        catalog_qualified_names: true,
239        byte_classes: STANDARD_BYTE_CLASSES,
240        binding_powers: STANDARD_BINDING_POWERS,
241        set_operation_powers: STANDARD_SET_OPERATION_BINDING_POWERS,
242        // `"…"` double-quoted strings (the coupled half of the backtick-only identifier lexis).
243        string_literals: StringLiteralSyntax::HIVE,
244        numeric_literals: NumericLiteralSyntax::ANSI,
245        parameters: ParameterSyntax::ANSI,
246        session_variables: SessionVariableSyntax::ANSI,
247        identifier_syntax: IdentifierSyntax::ANSI,
248        // The sided `{LEFT|RIGHT} {SEMI|ANTI} JOIN` family — the capstone this preset exposes.
249        table_expressions: TableExpressionSyntax::HIVE,
250        join_syntax: JoinSyntax::HIVE,
251        table_factor_syntax: TableFactorSyntax::HIVE,
252        expression_syntax: ExpressionSyntax::ANSI,
253        operator_syntax: OperatorSyntax::ANSI,
254        call_syntax: CallSyntax::ANSI,
255        string_func_forms: StringFuncForms::ANSI,
256        aggregate_call_syntax: AggregateCallSyntax::ANSI,
257        predicate_syntax: PredicateSyntax::ANSI,
258        pipe_operator: PipeOperator::StringConcat,
259        double_ampersand: DoubleAmpersand::Unsupported,
260        keyword_operators: KeywordOperators::Unsupported,
261        caret_operator: CaretOperator::Unsupported,
262        hash_bitwise_xor: false,
263        comment_syntax: CommentSyntax::ANSI,
264        mutation_syntax: MutationSyntax::ANSI,
265        statement_ddl_gates: StatementDdlGates::ANSI,
266        view_sequence_clause_syntax: ViewSequenceClauseSyntax::ANSI,
267        create_table_clause_syntax: CreateTableClauseSyntax::ANSI,
268        column_definition_syntax: ColumnDefinitionSyntax::ANSI,
269        constraint_syntax: ConstraintSyntax::ANSI,
270        index_alter_syntax: IndexAlterSyntax::ANSI,
271        existence_guards: ExistenceGuards::ANSI,
272        // The `LATERAL VIEW` table-generating clause — the second capstone this preset
273        // exposes; every other SELECT knob is conservatively ANSI.
274        select_syntax: SelectSyntax::HIVE,
275        query_tail_syntax: QueryTailSyntax::ANSI,
276        grouping_syntax: GroupingSyntax::ANSI,
277        utility_syntax: UtilitySyntax::ANSI,
278        transaction_syntax: TransactionSyntax::ANSI,
279        show_syntax: ShowSyntax::ANSI,
280        maintenance_syntax: MaintenanceSyntax::ANSI,
281        access_control_syntax: AccessControlSyntax::ANSI,
282        type_name_syntax: TypeNameSyntax::ANSI,
283        // No Hive-specific Tier-1 output spelling yet; render the portable ANSI canonical type
284        // names (a `TargetSpelling::Hive` is render work a later ticket owns).
285        target_spelling: TargetSpelling::Ansi,
286    };
287}
288
289/// Prefer [`FeatureSet::HIVE`] for struct update.
290pub const HIVE: FeatureSet = FeatureSet::HIVE;
291
292// Compile-time proof the Hive preset claims no shared tokenizer trigger twice. Beyond ANSI it
293// adds one lexical trigger — the backtick identifier opener — with a single claimant (no
294// enabled expression grammar lexes a backtick), and it hands `"` to the string scanner
295// (`double_quoted_strings` on) *while dropping `"` from the identifier quote set*, so `"` also
296// keeps a single claimant. The sided-join gate is contextual keyword grammar with no tokenizer
297// trigger. Kept as a ratchet so a future Hive delta that *does* add a contending trigger (e.g.
298// re-listing `"` as an identifier quote) fails the build here.
299const _: () = assert!(FeatureSet::HIVE.is_lexically_consistent());
300// The two sibling self-consistency registries are ratcheted the same way, so the
301// parse-entry `debug_assert!` folds all three to dead code for this preset: no refinement
302// flag rides an unset base, and no two features contend for one parser-position head.
303const _: () = assert!(FeatureSet::HIVE.has_satisfied_feature_dependencies());
304const _: () = assert!(FeatureSet::HIVE.has_no_grammar_conflict());
305
306#[cfg(test)]
307mod tests {
308    use super::*;
309
310    #[test]
311    fn hive_is_ansi_plus_the_two_gates_and_two_lexical_facts() {
312        // The preset is ANSI with a documented, closed set of divergent axes: the two lexical
313        // facts (case-folding, backtick-only quoting coupled with double-quoted strings), the
314        // enabled table-expression gate, and the enabled SELECT gate. Asserting the whole rest
315        // equals ANSI keeps the "ANSI-derived, every delta documented" claim honest against a
316        // future stray edit. Bind to locals so the const reads are not flagged by clippy's
317        // `assertions_on_constants`.
318        let ansi = FeatureSet::ANSI;
319        let hive = FeatureSet::HIVE;
320
321        // The two lexical facts.
322        assert_eq!(hive.identifier_casing, Casing::Lower);
323        assert_ne!(hive.identifier_casing, ansi.identifier_casing);
324        assert_eq!(hive.identifier_quotes, HIVE_IDENTIFIER_QUOTES);
325        assert_ne!(hive.identifier_quotes, ansi.identifier_quotes);
326        // The coupling: `"` is dropped from the quote set and handed to the string scanner.
327        assert!(hive.string_literals.double_quoted_strings);
328        assert!(
329            !hive
330                .identifier_quotes
331                .iter()
332                .any(|quote| quote.open() == '"')
333        );
334        // Backtick is the sole identifier quote; no bracket (unlike SQLite/MSSQL) and no `"`.
335        assert!(
336            hive.identifier_quotes
337                .iter()
338                .any(|quote| quote.open() == '`')
339        );
340        assert_eq!(hive.identifier_quotes.len(), 1);
341
342        // The one divergent string sub-preset (the double-quote coupling).
343        assert_eq!(hive.string_literals, StringLiteralSyntax::HIVE);
344        assert_ne!(hive.string_literals, ansi.string_literals);
345        // The divergent table-expression sub-preset.
346        assert_eq!(hive.table_expressions, TableExpressionSyntax::HIVE);
347        assert_eq!(hive.join_syntax, JoinSyntax::HIVE);
348        assert_ne!(hive.join_syntax, ansi.join_syntax);
349        // The divergent SELECT sub-preset (the LATERAL VIEW clause).
350        assert_eq!(hive.select_syntax, SelectSyntax::HIVE);
351        assert_ne!(hive.select_syntax, ansi.select_syntax);
352
353        // No reserved-set delta: every position is inherited verbatim from ANSI.
354        assert_eq!(hive.reserved_column_name, ansi.reserved_column_name);
355        assert_eq!(hive.reserved_function_name, ansi.reserved_function_name);
356        assert_eq!(hive.reserved_type_name, ansi.reserved_type_name);
357        assert_eq!(hive.reserved_bare_alias, ansi.reserved_bare_alias);
358        assert_eq!(hive.reserved_as_label, KeywordSet::EMPTY);
359
360        // Everything else is inherited verbatim from ANSI.
361        assert_eq!(hive.numeric_literals, ansi.numeric_literals);
362        assert_eq!(hive.parameters, ansi.parameters);
363        assert_eq!(hive.expression_syntax, ansi.expression_syntax);
364        assert_eq!(hive.session_variables, ansi.session_variables);
365        assert_eq!(hive.identifier_syntax, ansi.identifier_syntax);
366        assert_eq!(hive.operator_syntax, ansi.operator_syntax);
367        assert_eq!(hive.call_syntax, ansi.call_syntax);
368        assert_eq!(hive.predicate_syntax, ansi.predicate_syntax);
369        assert_eq!(hive.mutation_syntax, ansi.mutation_syntax);
370        assert_eq!(hive.statement_ddl_gates, ansi.statement_ddl_gates);
371        assert_eq!(
372            hive.create_table_clause_syntax,
373            ansi.create_table_clause_syntax
374        );
375        assert_eq!(hive.column_definition_syntax, ansi.column_definition_syntax);
376        assert_eq!(hive.constraint_syntax, ansi.constraint_syntax);
377        assert_eq!(hive.index_alter_syntax, ansi.index_alter_syntax);
378        assert_eq!(hive.existence_guards, ansi.existence_guards);
379        assert_eq!(hive.utility_syntax, ansi.utility_syntax);
380        assert_eq!(hive.type_name_syntax, ansi.type_name_syntax);
381        assert_eq!(hive.byte_classes, ansi.byte_classes);
382        assert_eq!(hive.binding_powers, ansi.binding_powers);
383        assert_eq!(hive.target_spelling, ansi.target_spelling);
384        assert_eq!(hive.default_null_ordering, ansi.default_null_ordering);
385    }
386
387    #[test]
388    fn hive_enables_exactly_the_two_gates_and_double_quote_string() {
389        // The capstones: the sided semi-/anti-join family, the LATERAL VIEW clause, and
390        // double-quoted strings are on, and each is off in the ANSI base it derives from.
391        // Forcing the flags back off recovers the ANSI sub-presets verbatim.
392        let ansi = FeatureSet::ANSI;
393        let hive = FeatureSet::HIVE;
394
395        assert!(hive.join_syntax.sided_semi_anti_join);
396        assert!(!ansi.join_syntax.sided_semi_anti_join);
397        // The side-less DuckDB spelling stays off (a different engine family).
398        assert!(!hive.join_syntax.semi_anti_join);
399        // The LATERAL VIEW clause; the derived-table LATERAL factor stays off, so
400        // `LATERAL` leads only the view clause under this preset.
401        assert!(hive.select_syntax.lateral_view_clause && !ansi.select_syntax.lateral_view_clause);
402        assert!(!hive.table_factor_syntax.lateral);
403        assert!(
404            hive.string_literals.double_quoted_strings
405                && !ansi.string_literals.double_quoted_strings
406        );
407        // The backtick opener is the lexical gate (an identifier-quote delta, not a bool).
408        assert!(
409            hive.identifier_quotes
410                .iter()
411                .any(|quote| quote.open() == '`')
412        );
413        assert!(
414            !ansi
415                .identifier_quotes
416                .iter()
417                .any(|quote| quote.open() == '`')
418        );
419
420        assert_eq!(
421            JoinSyntax {
422                sided_semi_anti_join: false,
423                ..hive.join_syntax
424            },
425            ansi.join_syntax,
426        );
427        assert_eq!(
428            SelectSyntax {
429                lateral_view_clause: false,
430                ..hive.select_syntax
431            },
432            ansi.select_syntax,
433        );
434        assert_eq!(
435            StringLiteralSyntax {
436                double_quoted_strings: false,
437                ..hive.string_literals
438            },
439            ansi.string_literals,
440        );
441    }
442
443    #[test]
444    fn hive_is_lexically_consistent_and_dependency_clean() {
445        // Both self-consistency registries must be clean: the backtick quote has a single
446        // claimant, `"` is handed to the string scanner (dropped from the quote set), and the
447        // sided-join gate rides no unset base flag.
448        let hive = FeatureSet::HIVE;
449        assert_eq!(hive.lexical_conflict(), None);
450        assert!(hive.is_lexically_consistent());
451        assert_eq!(hive.feature_dependencies(), None);
452        assert!(hive.has_satisfied_feature_dependencies());
453        assert_eq!(hive.grammar_conflict(), None);
454        assert!(hive.has_no_grammar_conflict());
455    }
456    #[test]
457    fn hive_closed_delta_axes_match_documented_set() {
458        crate::dialect::closed_delta::assert_closed_delta(
459            &FeatureSet::ANSI,
460            &FeatureSet::HIVE,
461            &[
462                "identifier_casing",
463                "identifier_quotes",
464                "string_literals",
465                "join_syntax",
466                "select_syntax",
467            ],
468        );
469    }
470}