use super::keyword::{
MYSQL_FUNCTION_ONLY_KEYWORDS, MYSQL_RESERVED_KEYWORDS, MYSQL_TYPE_FUNC_NAME_KEYWORDS,
};
use super::{
AccessControlSyntax, AggregateCallSyntax, CallSyntax, CaretOperator, Casing,
ColumnDefinitionSyntax, CommentSyntax, ConstraintSyntax, CreateTableClauseSyntax,
DoubleAmpersand, ExistenceGuards, ExpressionSyntax, FeatureSet, GroupingSyntax,
IdentifierQuote, IdentifierSyntax, IndexAlterSyntax, JoinSyntax, Keyword, KeywordOperators,
KeywordSet, MYSQL_BYTE_CLASSES, MaintenanceSyntax, MutationSyntax, NullOrdering,
NumericLiteralSyntax, OperatorSyntax, ParameterSyntax, PipeOperator, PredicateSyntax,
QueryTailSyntax, SelectSyntax, SessionVariableSyntax, ShowSyntax, StatementDdlGates,
StringFuncForms, StringLiteralSyntax, TableExpressionSyntax, TableFactorSyntax, TargetSpelling,
TransactionSyntax, TypeNameSyntax, UtilitySyntax, ViewSequenceClauseSyntax,
};
use crate::precedence::{
Assoc, BindingPower, BindingPowerTable, STANDARD_SET_OPERATION_BINDING_POWERS,
};
pub const MYSQL_IDENTIFIER_QUOTES: &[IdentifierQuote] = &[IdentifierQuote::Symmetric('`')];
pub const MYSQL_RESERVED_COLUMN_NAME: KeywordSet =
MYSQL_TYPE_FUNC_NAME_KEYWORDS.union(MYSQL_RESERVED_KEYWORDS);
pub const MYSQL_WINDOW_FUNCTION_KEYWORDS: KeywordSet = KeywordSet::from_keywords(&[
Keyword::RowNumber,
Keyword::Rank,
Keyword::DenseRank,
Keyword::PercentRank,
Keyword::CumeDist,
Keyword::Ntile,
Keyword::Lead,
Keyword::Lag,
Keyword::FirstValue,
Keyword::LastValue,
Keyword::NthValue,
]);
pub const MYSQL_RESERVED_FUNCTION_NAME: KeywordSet = MYSQL_RESERVED_KEYWORDS
.difference(MYSQL_WINDOW_FUNCTION_KEYWORDS)
.union(MYSQL_FUNCTION_ONLY_KEYWORDS);
pub const MYSQL_RESERVED_TYPE_NAME: KeywordSet =
MYSQL_TYPE_FUNC_NAME_KEYWORDS.union(MYSQL_RESERVED_KEYWORDS);
pub const MYSQL_RESERVED_BARE_ALIAS: KeywordSet =
MYSQL_TYPE_FUNC_NAME_KEYWORDS.union(MYSQL_RESERVED_KEYWORDS);
impl CommentSyntax {
pub const MYSQL_8_VERSION_BOUND: u32 = 80499;
pub const MYSQL: Self = Self {
line_comment_hash: true,
line_comment_ends_at_carriage_return: false,
nested_block_comments: false,
versioned_comments: Some(Self::MYSQL_8_VERSION_BOUND),
unterminated_block_comment_at_eof: false,
};
}
impl StringLiteralSyntax {
pub const MYSQL: Self = Self {
escape_strings: false,
dollar_quoted_strings: false,
national_strings: true,
double_quoted_strings: true,
backslash_escapes: true,
unicode_strings: false,
bit_string_literals: true,
blob_literals: true,
charset_introducers: true,
same_line_adjacent_concat: true,
};
}
impl NumericLiteralSyntax {
pub const MYSQL: Self = Self {
hex_integers: true,
octal_integers: false,
binary_integers: true,
underscore_separators: false,
radix_leading_underscore: false,
money_literals: false,
reject_trailing_junk: false,
};
}
impl ParameterSyntax {
pub const MYSQL: Self = Self {
positional_dollar: false,
positional_dollar_large: false,
anonymous_question: true,
named_colon: false,
named_at: false,
named_dollar: false,
numbered_question: false,
};
}
impl SessionVariableSyntax {
pub const MYSQL: Self = Self {
user_variables: true,
system_variables: true,
variable_assignment: true,
};
}
impl IdentifierSyntax {
pub const MYSQL: Self = Self {
non_ascii: super::NonAsciiIdentifierSyntax::Any,
dollar_in_identifiers: true,
string_literal_identifiers: false,
string_literal_table_names: false,
empty_quoted_identifiers: false,
};
}
impl TableExpressionSyntax {
pub const MYSQL: Self = Self {
only: false,
table_sample: false,
parenthesized_joins: true,
table_alias_column_lists: true,
join_using_alias: false,
index_hints: true,
table_hints: false,
partition_selection: true,
base_table_alias_column_lists: false,
string_literal_aliases: false,
aliased_parenthesized_join: false,
bare_table_alias_is_bare_label: false,
table_version: false,
table_json_path: false,
indexed_by: false,
prefix_colon_alias: false,
};
}
impl JoinSyntax {
pub const MYSQL: Self = Self {
stacked_join_qualifiers: true,
full_outer_join: false,
natural_cross_join: false,
straight_join: true,
asof_join: false,
positional_join: false,
semi_anti_join: false,
sided_semi_anti_join: false,
apply_join: false,
recursive_search_cycle: false,
recursive_union_rejects_order_limit: false,
recursive_using_key: false,
};
}
impl TableFactorSyntax {
pub const MYSQL: Self = Self {
lateral: false,
table_functions: false,
rows_from: false,
unnest: false,
unnest_with_offset: false,
table_function_ordinality: false,
special_function_table_source: false,
pivot: false,
unpivot: false,
show_ref: false,
from_values: false,
json_table: false,
xml_table: false,
table_expr_factor: false,
pivot_value_sources: false,
match_recognize: false,
open_json: false,
};
}
impl MutationSyntax {
pub const MYSQL: Self = Self {
insert_ignore: true,
insert_overwrite: false,
returning: false,
on_conflict: false,
on_duplicate_key_update: true,
multi_column_assignment: false,
update_tuple_value_row_arity: false,
where_current_of: false,
merge: false,
replace_into: true,
insert_set: true,
update_delete_tails: true,
joined_update_delete: true,
or_conflict_action: false,
insert_column_matching: false,
delete_using: true,
update_from: false,
delete_using_target_alias: false,
cte_before_insert: false,
cte_before_merge: false,
data_modifying_ctes: false,
merge_when_not_matched_by: false,
merge_insert_default_values: false,
merge_insert_overriding: false,
merge_insert_multirow: false,
merge_update_set_star: false,
merge_insert_star_by_name: false,
merge_error_action: false,
update_set_qualified_column: true,
};
}
impl StatementDdlGates {
pub const MYSQL: Self = Self {
colocation_groups: false,
create_trigger: false,
create_macro: false,
create_secret: false,
create_type: false,
create_virtual_table: false,
create_sequence: false,
extension_ddl: false,
transform_ddl: false,
alter_system: false,
tablespace_ddl: true,
logfile_group_ddl: true,
schemas: true,
schema_elements: false,
databases: true,
drop_database: true,
materialized_views: false,
routines: true,
or_replace: true,
create_or_replace_table: false,
compound_statements: true,
alter_database: false,
alter_database_options: true,
server_definition: true,
alter_instance: true,
spatial_reference_system: true,
resource_group: true,
alter_sequence: false,
alter_object_set_schema: false,
};
}
impl ViewSequenceClauseSyntax {
pub const MYSQL: Self = Self {
materialized_view_to: false,
create_sequence_cache: false,
temporary_views: false,
recursive_views: false,
view_definition_options: true,
};
}
impl CreateTableClauseSyntax {
pub const MYSQL: Self = Self {
table_options: true,
without_rowid_table_option: false,
strict_table_option: false,
storage_parameters: false,
on_commit: false,
create_table_as_with_data: false,
create_table_as_execute: false,
declarative_partitioning: false,
table_inheritance: false,
like_source_table: false,
statement_level_table_like: true,
unlogged_tables: false,
table_access_method: false,
without_oids: false,
typed_tables: false,
};
}
impl ColumnDefinitionSyntax {
pub const MYSQL: Self = Self {
generated_column_shorthand: true,
column_conflict_resolution_clause: false,
typeless_column_definitions: false,
typeless_generated_columns: false,
joined_autoincrement_attribute: false,
inline_primary_key_ordering: false,
named_column_collate_constraint: false,
identity_columns: false,
compact_identity_columns: false,
default_expression_requires_parens: true,
column_default_requires_b_expr: false,
column_collation: false,
column_storage: false,
};
}
impl ConstraintSyntax {
pub const MYSQL: Self = Self {
deferrable_constraints: false,
named_inline_non_check_constraints: false,
bare_constraint_name: false,
exclusion_constraints: false,
constraint_no_inherit_not_valid: false,
index_constraint_parameters: false,
constraint_column_collate_order: false,
referential_action_cascade_set: true,
check_constraint_subqueries: true,
};
}
impl IndexAlterSyntax {
pub const MYSQL: Self = Self {
rename_constraint: false,
alter_table_set_options: false,
drop_primary_key: true,
alter_column_add_identity: false,
index_storage_parameters: false,
drop_behavior: true,
index_drop_on_table: true,
index_concurrently: false,
index_using_method: false,
partial_index: false,
index_if_not_exists: false,
index_nulls_order: false,
alter_table_extended: true,
alter_nested_column_paths: false,
alter_existence_guards: false,
alter_column_set_data_type: false,
routine_arg_types: false,
routine_arg_defaults: false,
routine_arg_modes: false,
routine_language_string: false,
alter_table_multiple_actions: true,
};
}
impl ExistenceGuards {
pub const MYSQL: Self = Self {
if_exists: true,
view_if_not_exists: false,
create_database_if_not_exists: true,
};
}
impl ExpressionSyntax {
pub const MYSQL: Self = Self {
typecast_operator: false,
subscript: false,
slice_step: false,
collate: false,
at_time_zone: false,
semi_structured_access: false,
array_constructor: false,
multidim_array_literals: false,
collection_literals: false,
row_constructor: false,
struct_constructor: false,
field_selection: false,
field_wildcard: false,
typed_string_literals: true,
typed_interval_literal: false,
relaxed_interval_syntax: false,
mysql_interval_operator: true,
positional_column: false,
lambda_keyword: false,
};
}
impl OperatorSyntax {
pub const MYSQL: Self = Self {
operator_construct: false,
containment_operators: false,
json_arrow_operators: false,
jsonb_operators: false,
double_equals: false,
integer_divide_slash: false,
starts_with_operator: false,
is_general_equality: false,
truth_value_tests: true,
null_safe_equals: true,
lambda_expressions: false,
bitwise_operators: true,
quantified_comparisons: true,
quantified_comparison_lists: false,
quantified_arbitrary_operator: false,
custom_operators: false,
null_test_postfix: false,
postfix_operators: false,
};
}
impl CallSyntax {
pub const MYSQL: Self = Self {
named_argument: false,
utc_special_functions: true,
columns_expression: false,
extract_from_syntax: true,
try_cast: false,
restricted_cast_targets: true,
extract_string_field: false,
method_chaining: false,
sqljson_constructors_require_argument: false,
sqljson_expression_functions: false,
xml_expression_functions: false,
variadic_argument: false,
merge_action_function: false,
convert_function: true,
};
}
impl StringFuncForms {
pub const MYSQL: Self = Self {
substring_from_for: true,
substring_leading_for: false,
substring_similar: false,
substring_plain_call_requires_2_or_3_args: true,
substr_from_for: true,
position_in: true,
position_asymmetric_operands: true,
overlay_placing: false,
overlay_requires_placing: false,
trim_from: true,
trim_list_syntax: false,
collation_for_expression: false,
ceil_to_field: false,
floor_to_field: false,
match_against: true,
};
}
impl AggregateCallSyntax {
pub const MYSQL: Self = Self {
group_concat_separator: true,
within_group: false,
aggregate_filter: false,
filter_optional_where: false,
aggregate_args_require_adjacent_paren: true,
null_treatment: false,
aggregate_calls_reject_empty_arguments: true,
over_requires_windowable_function: true,
window_function_tail: true,
standalone_argument_order_by: false,
};
}
impl SelectSyntax {
pub const MYSQL: Self = Self {
distinct_on: false,
select_into: false,
empty_target_list: false,
qualify: false,
alias_string_literals: true,
bare_alias_string_literals: true,
union_by_name: false,
wildcard_modifiers: false,
wildcard_replace: false,
intersect_all: true,
except_all: true,
qualified_wildcard_alias: false,
from_first: false,
explicit_table: true,
parenthesized_query_operands: true,
values_rows_require_equal_arity: false,
values_row_constructor: false,
as_alias_rejects_reserved: true,
trailing_comma: false,
prefix_colon_alias: false,
lateral_view_clause: false,
connect_by_clause: false,
};
}
impl QueryTailSyntax {
pub const MYSQL: Self = Self {
fetch_first: false,
limit_offset_comma: true,
locking_clauses: true,
key_lock_strengths: false,
stacked_locking_clauses: false,
using_sample: false,
leading_offset: false,
limit_expressions: false,
limit_percent: false,
with_ties_requires_order_by: false,
pipe_syntax: false,
limit_by_clause: false,
settings_clause: false,
format_clause: false,
for_xml_json_clause: false,
};
}
impl GroupingSyntax {
pub const MYSQL: Self = Self {
grouping_sets: false,
with_rollup: true,
order_by_using: false,
group_by_all: false,
group_by_set_quantifier: false,
order_by_all: false,
};
}
impl UtilitySyntax {
pub const MYSQL: Self = Self {
kill: true,
handler_statements: true,
plugin_component_statements: true,
shutdown: true,
restart: true,
clone: true,
import_table: true,
help_statement: true,
binlog: true,
key_cache_statements: true,
rename_statement: true,
signal_diagnostics: true,
use_statement: true,
do_expression_list: true,
prepared_statements_from: true,
lock_tables: true,
lock_instance: true,
call: true,
call_bare_name: true,
flush: true,
purge_binary_logs: true,
replication_statements: true,
load_data: true,
copy: false,
copy_into: false,
stage_references: false,
comment_on: false,
comment_if_exists: false,
pragma: false,
attach: false,
use_qualified_name: false,
use_string_literal_name: false,
prepared_statements: false,
prepare_typed_parameters: false,
load_extension: false,
load_bare_name: false,
reset_scope: false,
detach_if_exists: false,
do_statement: false,
export_import_database: false,
update_extensions: false,
};
}
impl TransactionSyntax {
pub const MYSQL: Self = Self {
xa_transactions: true,
start_transaction: true,
start_transaction_block_optional: false,
transaction_work_keyword: true,
begin_transaction_keyword: false,
commit_transaction_keyword: false,
rollback_transaction_keyword: false,
transaction_name: false,
begin_transaction_modes: false,
transaction_savepoints: true,
set_transaction: true,
transaction_isolation_mode: true,
transaction_access_mode: true,
transaction_deferrable_mode: false,
start_transaction_isolation_mode: false,
start_transaction_deferrable_mode: false,
start_transaction_consistent_snapshot: true,
transaction_multiple_modes: true,
transaction_modes_require_commas: true,
transaction_modes_reject_duplicates: true,
abort_transaction_alias: false,
end_transaction_alias: false,
transaction_release: true,
transaction_chain: true,
release_savepoint_keyword_optional: false,
begin_transaction_mode: false,
};
}
impl ShowSyntax {
pub const MYSQL: Self = Self {
describe: true,
show_tables: true,
show_columns: true,
show_create_table: true,
show_routine_status: true,
show_admin: true,
describe_summarize: false,
session_statements: true,
set_value_reserved_words: KeywordSet::EMPTY,
set_value_on_keyword: false,
set_value_null_keyword: false,
show_functions: false,
show_verbose: false,
};
}
impl MaintenanceSyntax {
pub const MYSQL: Self = Self {
table_maintenance: true,
vacuum: false,
vacuum_analyze: false,
reindex: false,
analyze: false,
analyze_columns: false,
checkpoint: false,
checkpoint_database: false,
};
}
impl AccessControlSyntax {
pub const MYSQL: Self = Self {
alter_role_rename: false,
access_control_extended_objects: false,
user_role_management: true,
access_control_account_grants: true,
access_control: true,
};
}
impl TypeNameSyntax {
pub const MYSQL: Self = Self {
extended_scalar_type_names: true,
enum_type: true,
set_type: true,
numeric_modifiers: true,
integer_display_width: true,
composite_types: false,
varchar_requires_length: true,
zoned_temporal_types: false,
empty_type_parens: false,
character_set_annotation: true,
signed_type_modifier: false,
nullable_type: false,
low_cardinality_type: false,
fixed_string_type: false,
datetime64_type: false,
nested_type: false,
bit_width_integer_names: false,
liberal_type_names: false,
string_type_modifiers: false,
angle_bracket_types: false,
};
}
pub const MYSQL_BINDING_POWERS: BindingPowerTable = BindingPowerTable {
or: BindingPower {
left: 10,
right: 11,
assoc: Assoc::Left,
},
xor: BindingPower {
left: 15,
right: 16,
assoc: Assoc::Left,
},
and: BindingPower {
left: 20,
right: 21,
assoc: Assoc::Left,
},
comparison: BindingPower {
left: 40,
right: 41,
assoc: Assoc::Left,
},
range_predicate_override: None,
is_predicate_override: None,
double_equals: BindingPower {
left: 40,
right: 41,
assoc: Assoc::Left,
},
additive: BindingPower {
left: 50,
right: 51,
assoc: Assoc::Left,
},
multiplicative: BindingPower {
left: 60,
right: 61,
assoc: Assoc::Left,
},
exponent: BindingPower {
left: 65,
right: 66,
assoc: Assoc::Left,
},
string_concat: BindingPower {
left: 45,
right: 46,
assoc: Assoc::Left,
},
any_operator: BindingPower {
left: 45,
right: 46,
assoc: Assoc::Left,
},
json_get: BindingPower {
left: 45,
right: 46,
assoc: Assoc::Left,
},
bitwise_or: BindingPower {
left: 42,
right: 43,
assoc: Assoc::Left,
},
bitwise_and: BindingPower {
left: 44,
right: 45,
assoc: Assoc::Left,
},
bitwise_shift: BindingPower {
left: 47,
right: 48,
assoc: Assoc::Left,
},
bitwise_xor: BindingPower {
left: 65,
right: 66,
assoc: Assoc::Left,
},
prefix_bitwise_not: 80,
prefix_not: 30,
prefix_sign: 80,
at_time_zone: BindingPower {
left: 70,
right: 71,
assoc: Assoc::Left,
},
collate: BindingPower {
left: 74,
right: 75,
assoc: Assoc::Left,
},
subscript: BindingPower {
left: 84,
right: 85,
assoc: Assoc::Left,
},
typecast: BindingPower {
left: 88,
right: 89,
assoc: Assoc::Left,
},
field_selection: BindingPower {
left: 92,
right: 93,
assoc: Assoc::Left,
},
};
impl FeatureSet {
pub const MYSQL: Self = Self {
identifier_casing: Casing::Lower,
identifier_quotes: MYSQL_IDENTIFIER_QUOTES,
default_null_ordering: NullOrdering::NullsFirst,
reserved_column_name: MYSQL_RESERVED_COLUMN_NAME,
reserved_function_name: MYSQL_RESERVED_FUNCTION_NAME,
reserved_type_name: MYSQL_RESERVED_TYPE_NAME,
reserved_bare_alias: MYSQL_RESERVED_BARE_ALIAS,
reserved_as_label: KeywordSet::EMPTY,
catalog_qualified_names: false,
byte_classes: MYSQL_BYTE_CLASSES,
binding_powers: MYSQL_BINDING_POWERS,
set_operation_powers: STANDARD_SET_OPERATION_BINDING_POWERS,
string_literals: StringLiteralSyntax::MYSQL,
numeric_literals: NumericLiteralSyntax::MYSQL,
parameters: ParameterSyntax::MYSQL,
session_variables: SessionVariableSyntax::MYSQL,
identifier_syntax: IdentifierSyntax::MYSQL,
table_expressions: TableExpressionSyntax::MYSQL,
join_syntax: JoinSyntax::MYSQL,
table_factor_syntax: TableFactorSyntax::MYSQL,
expression_syntax: ExpressionSyntax::MYSQL,
operator_syntax: OperatorSyntax::MYSQL,
call_syntax: CallSyntax::MYSQL,
string_func_forms: StringFuncForms::MYSQL,
aggregate_call_syntax: AggregateCallSyntax::MYSQL,
predicate_syntax: PredicateSyntax::ANSI,
pipe_operator: PipeOperator::LogicalOr,
double_ampersand: DoubleAmpersand::LogicalAnd,
keyword_operators: KeywordOperators::MySql,
caret_operator: CaretOperator::BitwiseXor,
hash_bitwise_xor: false,
comment_syntax: CommentSyntax::MYSQL,
mutation_syntax: MutationSyntax::MYSQL,
statement_ddl_gates: StatementDdlGates::MYSQL,
view_sequence_clause_syntax: ViewSequenceClauseSyntax::MYSQL,
create_table_clause_syntax: CreateTableClauseSyntax::MYSQL,
column_definition_syntax: ColumnDefinitionSyntax::MYSQL,
constraint_syntax: ConstraintSyntax::MYSQL,
index_alter_syntax: IndexAlterSyntax::MYSQL,
existence_guards: ExistenceGuards::MYSQL,
select_syntax: SelectSyntax::MYSQL,
query_tail_syntax: QueryTailSyntax::MYSQL,
grouping_syntax: GroupingSyntax::MYSQL,
utility_syntax: UtilitySyntax::MYSQL,
transaction_syntax: TransactionSyntax::MYSQL,
show_syntax: ShowSyntax::MYSQL,
maintenance_syntax: MaintenanceSyntax::MYSQL,
access_control_syntax: AccessControlSyntax::MYSQL,
type_name_syntax: TypeNameSyntax::MYSQL,
target_spelling: TargetSpelling::Ansi,
};
}
pub const MYSQL: FeatureSet = FeatureSet::MYSQL;
const _: () = assert!(FeatureSet::MYSQL.is_lexically_consistent());
const _: () = assert!(FeatureSet::MYSQL.has_satisfied_feature_dependencies());
const _: () = assert!(FeatureSet::MYSQL.has_no_grammar_conflict());
#[cfg(test)]
mod tests {
use super::super::{
Keyword, RESERVED_BARE_ALIAS, RESERVED_COLUMN_NAME, RESERVED_FUNCTION_NAME,
RESERVED_TYPE_NAME,
};
use super::*;
use crate::ast::{BinaryOperator, EqualsSpelling, RegexpSpelling};
use crate::precedence::{STANDARD_BINDING_POWERS, Side};
#[test]
fn mysql_reserved_sets_diverge_from_the_shared_sets_in_both_directions() {
for keyword in [
Keyword::Rlike,
Keyword::Div,
Keyword::Xor,
Keyword::Zerofill,
] {
assert!(MYSQL_RESERVED_COLUMN_NAME.contains(keyword));
assert!(MYSQL_RESERVED_FUNCTION_NAME.contains(keyword));
assert!(MYSQL_RESERVED_TYPE_NAME.contains(keyword));
assert!(MYSQL_RESERVED_BARE_ALIAS.contains(keyword));
assert!(!RESERVED_COLUMN_NAME.contains(keyword));
assert!(!RESERVED_FUNCTION_NAME.contains(keyword));
assert!(!RESERVED_TYPE_NAME.contains(keyword));
assert!(!RESERVED_BARE_ALIAS.contains(keyword));
}
for keyword in [Keyword::Offset, Keyword::Symmetric] {
assert!(RESERVED_COLUMN_NAME.contains(keyword));
assert!(!MYSQL_RESERVED_COLUMN_NAME.contains(keyword));
assert!(!MYSQL_RESERVED_FUNCTION_NAME.contains(keyword));
assert!(!MYSQL_RESERVED_TYPE_NAME.contains(keyword));
assert!(!MYSQL_RESERVED_BARE_ALIAS.contains(keyword));
}
assert!(MYSQL_RESERVED_COLUMN_NAME.contains(Keyword::Left));
assert!(MYSQL_RESERVED_TYPE_NAME.contains(Keyword::Left));
assert!(MYSQL_RESERVED_BARE_ALIAS.contains(Keyword::Left));
assert!(!MYSQL_RESERVED_FUNCTION_NAME.contains(Keyword::Left));
}
#[test]
fn mysql_window_function_names_are_admitted_only_as_call_heads() {
for keyword in [
Keyword::RowNumber,
Keyword::Rank,
Keyword::DenseRank,
Keyword::PercentRank,
Keyword::CumeDist,
Keyword::Ntile,
Keyword::Lead,
Keyword::Lag,
Keyword::FirstValue,
Keyword::LastValue,
Keyword::NthValue,
] {
assert!(
MYSQL_RESERVED_KEYWORDS.contains(keyword),
"{keyword:?} is a fully reserved MySQL word",
);
assert!(
!MYSQL_RESERVED_FUNCTION_NAME.contains(keyword),
"{keyword:?} must be admissible as a call head",
);
assert!(
MYSQL_RESERVED_COLUMN_NAME.contains(keyword),
"{keyword:?} must stay reserved as a column name",
);
assert!(
MYSQL_RESERVED_TYPE_NAME.contains(keyword),
"{keyword:?} must stay reserved as a type name",
);
assert!(
MYSQL_RESERVED_BARE_ALIAS.contains(keyword),
"{keyword:?} must stay reserved as a bare/AS alias",
);
}
assert!(MYSQL_RESERVED_FUNCTION_NAME.contains(Keyword::Select));
}
#[test]
fn mysql_array_is_reserved_only_as_a_call_head() {
assert!(
MYSQL_RESERVED_FUNCTION_NAME.contains(Keyword::Array),
"array must be rejected as a call head",
);
assert!(
!MYSQL_RESERVED_COLUMN_NAME.contains(Keyword::Array),
"array must be admissible as a column name",
);
assert!(
!MYSQL_RESERVED_TYPE_NAME.contains(Keyword::Array),
"array must be admissible as a type name",
);
assert!(
!MYSQL_RESERVED_BARE_ALIAS.contains(Keyword::Array),
"array must be admissible as a bare/AS alias",
);
}
#[test]
fn mysql_binding_powers_differ_from_standard_in_comparison_assoc_and_bitwise_ranks() {
use crate::ast::NotEqSpelling;
let mut expected = STANDARD_BINDING_POWERS;
expected.comparison.assoc = Assoc::Left;
expected.double_equals.assoc = Assoc::Left;
expected.bitwise_or = BindingPower {
left: 42,
right: 43,
assoc: Assoc::Left,
};
expected.bitwise_and = BindingPower {
left: 44,
right: 45,
assoc: Assoc::Left,
};
expected.bitwise_shift = BindingPower {
left: 47,
right: 48,
assoc: Assoc::Left,
};
expected.bitwise_xor = BindingPower {
left: 65,
right: 66,
assoc: Assoc::Left,
};
expected.prefix_bitwise_not = 80;
assert_eq!(MYSQL_BINDING_POWERS, expected);
use crate::ast::BitwiseXorSpelling;
let or = MYSQL_BINDING_POWERS.binary(&BinaryOperator::BitwiseOr);
let and = MYSQL_BINDING_POWERS.binary(&BinaryOperator::BitwiseAnd);
let shift = MYSQL_BINDING_POWERS.binary(&BinaryOperator::BitwiseShiftLeft);
let add = MYSQL_BINDING_POWERS.binary(&BinaryOperator::Plus);
let mul = MYSQL_BINDING_POWERS.binary(&BinaryOperator::Multiply);
let xor =
MYSQL_BINDING_POWERS.binary(&BinaryOperator::BitwiseXor(BitwiseXorSpelling::Caret));
assert!(or.left < and.left, "`|` looser than `&`");
assert!(and.left < shift.left, "`&` looser than `<<`/`>>`");
assert!(shift.left < add.left, "shift looser than additive");
assert!(mul.left < xor.left, "`^` tighter than multiplicative");
for op in [
BinaryOperator::Eq(EqualsSpelling::Single),
BinaryOperator::NotEq(NotEqSpelling::AngleBracket),
BinaryOperator::Lt,
BinaryOperator::LtEq,
BinaryOperator::Gt,
BinaryOperator::GtEq,
BinaryOperator::Regexp(RegexpSpelling::Rlike),
BinaryOperator::Regexp(RegexpSpelling::Regexp),
] {
let bp = MYSQL_BINDING_POWERS.binary(&op);
assert_eq!(bp.assoc, Assoc::Left, "{op:?} should be left-associative");
assert_eq!(bp.left, 40, "{op:?} keeps the STANDARD left rank");
assert_eq!(bp.right, 41, "{op:?} keeps the STANDARD right rank");
}
assert_eq!(MYSQL_BINDING_POWERS.predicate().assoc, Assoc::Left);
assert!(!MYSQL_BINDING_POWERS.needs_parens(
&BinaryOperator::Lt,
&BinaryOperator::Eq(EqualsSpelling::Single),
Side::Left
));
assert!(MYSQL_BINDING_POWERS.needs_parens(
&BinaryOperator::Lt,
&BinaryOperator::Eq(EqualsSpelling::Single),
Side::Right
));
}
}