use sql_dialect_fmt_syntax::SyntaxKind::*;
use crate::parser::{ContextualKeyword, Parser};
use super::{
at_block_start, at_stmt_terminator, balanced_parens, balanced_token_run_until, block_stmt,
call_stmt, column_list, dml, expr, name_ref, query_expr, type_name,
};
const CREATE_MODIFIER_CONTEXTUAL_WORDS: &[ContextualKeyword] = &[
ContextualKeyword::Materialized,
ContextualKeyword::Local,
ContextualKeyword::Global,
];
const NAMED_OBJECT_CONTEXTUAL_WORDS: &[ContextualKeyword] = &[
ContextualKeyword::Schema,
ContextualKeyword::Database,
ContextualKeyword::Stage,
ContextualKeyword::Sequence,
ContextualKeyword::Stream,
ContextualKeyword::Dynamic,
ContextualKeyword::Semantic,
ContextualKeyword::File,
ContextualKeyword::Tag,
];
const SEMANTIC_VIEW_CLAUSE_CONTEXTUAL_WORDS: &[ContextualKeyword] = &[
ContextualKeyword::Tables,
ContextualKeyword::Relationships,
ContextualKeyword::Facts,
ContextualKeyword::Dimensions,
ContextualKeyword::Metrics,
ContextualKeyword::AiSqlGeneration,
ContextualKeyword::AiQuestionCategorization,
ContextualKeyword::AiVerifiedQueries,
];
const SEMANTIC_VIEW_CONTEXTUAL_WORDS: &[ContextualKeyword] = &[
ContextualKeyword::Tables,
ContextualKeyword::Relationships,
ContextualKeyword::Facts,
ContextualKeyword::Dimensions,
ContextualKeyword::Metrics,
ContextualKeyword::Public,
ContextualKeyword::Private,
ContextualKeyword::Primary,
ContextualKeyword::Key,
ContextualKeyword::References,
ContextualKeyword::Synonyms,
ContextualKeyword::Labels,
ContextualKeyword::AiSqlGeneration,
ContextualKeyword::AiQuestionCategorization,
ContextualKeyword::AiVerifiedQueries,
ContextualKeyword::Question,
ContextualKeyword::VerifiedAt,
ContextualKeyword::OnboardingQuestion,
ContextualKeyword::VerifiedBy,
ContextualKeyword::Tag,
];
const DDL_CONSTRAINT_START_CONTEXTUAL_WORDS: &[ContextualKeyword] = &[
ContextualKeyword::Constraint,
ContextualKeyword::Primary,
ContextualKeyword::Unique,
ContextualKeyword::Foreign,
ContextualKeyword::Check,
];
const DDL_CONTEXTUAL_WORDS: &[ContextualKeyword] = &[
ContextualKeyword::Default,
ContextualKeyword::Primary,
ContextualKeyword::Key,
ContextualKeyword::Unique,
ContextualKeyword::Foreign,
ContextualKeyword::References,
ContextualKeyword::Constraint,
ContextualKeyword::Check,
ContextualKeyword::Collate,
ContextualKeyword::Comment,
ContextualKeyword::Cluster,
ContextualKeyword::Clone,
ContextualKeyword::Cascade,
ContextualKeyword::Restrict,
ContextualKeyword::Materialized,
ContextualKeyword::Masking,
ContextualKeyword::Policy,
ContextualKeyword::Access,
ContextualKeyword::Tag,
ContextualKeyword::AllowedValues,
ContextualKeyword::Propagate,
ContextualKeyword::ExemptOtherPolicies,
];
fn if_exists_clause(p: &mut Parser) {
if p.at(IF_KW) {
p.bump(IF_KW);
p.eat(NOT_KW);
p.eat(EXISTS_KW);
}
}
pub(super) fn create_stmt(p: &mut Parser) {
let m = p.start();
p.bump(CREATE_KW);
if p.at(OR_KW) {
p.bump(OR_KW);
if p.at(REPLACE_KW) {
p.bump(REPLACE_KW);
} else {
p.expect(ALTER_KW);
}
}
while !at_object_kind(p) && !at_stmt_terminator(p) && !at_create_body(p) {
if p.nth_any_contextual(0, CREATE_MODIFIER_CONTEXTUAL_WORDS) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
}
if p.at(VIEW_KW) {
create_view(p);
} else if p.at(TABLE_KW) {
create_table(p);
} else if p.at(PROCEDURE_KW) || p.at(FUNCTION_KW) {
create_routine(p);
} else if at_policy_object_kind(p) {
create_policy(p);
} else if at_named_object_kind(p) {
create_object(p);
} else {
create_other(p);
}
m.complete(p, CREATE_STMT);
}
fn at_object_kind(p: &Parser) -> bool {
p.at(TABLE_KW)
|| p.at(VIEW_KW)
|| p.at(PROCEDURE_KW)
|| p.at(FUNCTION_KW)
|| at_policy_object_kind(p)
|| at_named_object_kind(p)
}
fn at_named_object_kind(p: &Parser) -> bool {
p.at(TASK_KW) || p.at(WAREHOUSE_KW) || p.nth_any_contextual(0, NAMED_OBJECT_CONTEXTUAL_WORDS)
}
fn at_policy_object_kind(p: &Parser) -> bool {
(p.nth_contextual(0, ContextualKeyword::Masking)
&& p.nth_contextual(1, ContextualKeyword::Policy))
|| (p.at(ROW_KW)
&& p.nth_contextual(1, ContextualKeyword::Access)
&& p.nth_contextual(2, ContextualKeyword::Policy))
}
fn create_object(p: &mut Parser) {
object_kind_words(p);
if_exists_clause(p);
if p.at_name() {
name_ref(p);
}
if p.at(L_PAREN) {
column_def_list(p);
}
p.eat(WITH_KW); object_property_region(p);
if at_create_body(p) {
p.bump(AS_KW);
create_body(p);
}
}
fn object_kind_words(p: &mut Parser) {
if p.nth_contextual(0, ContextualKeyword::File) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.nth_contextual(0, ContextualKeyword::Format) {
p.bump_as(CONTEXTUAL_KEYWORD); }
} else if p.nth_contextual(0, ContextualKeyword::Dynamic) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.at(TABLE_KW) {
p.bump(TABLE_KW);
}
} else if p.nth_contextual(0, ContextualKeyword::Semantic) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.at(VIEW_KW) {
p.bump(VIEW_KW);
}
} else if p.nth_contextual(0, ContextualKeyword::Tag) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else if p.at_keyword() {
p.bump_any();
} else {
p.bump_as(CONTEXTUAL_KEYWORD);
}
}
fn create_policy(p: &mut Parser) {
policy_kind_words(p);
if_exists_clause(p);
if p.at_name() {
name_ref(p);
}
while !at_stmt_terminator(p) {
bump_ddl_word(p);
}
}
fn policy_kind_words(p: &mut Parser) {
if p.nth_contextual(0, ContextualKeyword::Masking) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.nth_contextual(0, ContextualKeyword::Policy) {
p.bump_as(CONTEXTUAL_KEYWORD); }
} else {
p.bump(ROW_KW);
if p.nth_contextual(0, ContextualKeyword::Access) {
p.bump_as(CONTEXTUAL_KEYWORD); }
if p.nth_contextual(0, ContextualKeyword::Policy) {
p.bump_as(CONTEXTUAL_KEYWORD); }
}
}
fn object_property_region(p: &mut Parser) {
while !at_create_body(p) && !at_stmt_terminator(p) {
if p.dialect().supports_semantic_view() && at_semantic_view_clause_start(p) {
semantic_view_clause(p);
} else if p.at(ON_KW) {
stream_source(p);
} else if p.at(AFTER_KW) {
task_after(p);
} else if p.at(WHEN_KW) {
let m = p.start();
p.bump(WHEN_KW);
expr(p);
m.complete(p, OBJECT_PROPERTY);
} else {
object_property(p);
}
}
}
fn semantic_view_clause(p: &mut Parser) {
let m = p.start();
if p.at(WITH_KW) {
p.bump(WITH_KW);
if p.nth_contextual(0, ContextualKeyword::Tag) {
p.bump_as(CONTEXTUAL_KEYWORD);
}
if p.at(L_PAREN) {
semantic_view_paren_list(p);
}
} else if p.at(COPY_KW) {
p.bump(COPY_KW);
p.eat(GRANTS_KW);
} else {
semantic_view_word(p);
if p.at(L_PAREN) {
semantic_view_paren_list(p);
} else if !at_semantic_view_clause_start(p)
&& !p.at(SEMICOLON)
&& !p.at_eof()
&& !at_create_body(p)
{
semantic_view_word(p);
}
}
m.complete(p, SEMANTIC_VIEW_CLAUSE);
}
fn at_semantic_view_clause_start(p: &Parser) -> bool {
p.nth_any_contextual(0, SEMANTIC_VIEW_CLAUSE_CONTEXTUAL_WORDS)
|| (p.at(WITH_KW) && p.nth_contextual(1, ContextualKeyword::Tag))
|| (p.at(COPY_KW) && p.nth_at(1, GRANTS_KW))
}
fn semantic_view_paren_list(p: &mut Parser) {
p.bump(L_PAREN);
if !p.at(R_PAREN) {
semantic_view_item(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
semantic_view_item(p);
}
}
p.expect(R_PAREN);
}
fn semantic_view_item(p: &mut Parser) {
let m = p.start();
balanced_token_run_until(p, |p| p.at(COMMA) || p.at(R_PAREN), semantic_view_word);
m.complete(p, SEMANTIC_VIEW_ITEM);
}
fn semantic_view_word(p: &mut Parser) {
if is_semantic_view_contextual_word(p) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
}
fn is_semantic_view_contextual_word(p: &Parser) -> bool {
p.nth_any_contextual(0, SEMANTIC_VIEW_CONTEXTUAL_WORDS)
}
fn object_property(p: &mut Parser) {
let m = p.start();
let is_allowed_values = p.nth_contextual(0, ContextualKeyword::AllowedValues);
if is_allowed_values {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any(); }
if p.eat(EQ) {
if p.at(L_PAREN) {
balanced_parens(p); } else if !at_create_body(p) && !at_stmt_terminator(p) {
p.bump_any(); }
while at_property_value_tail(p) {
p.bump_any();
}
} else if is_allowed_values {
while at_allowed_values_tail(p) {
p.bump_any();
}
} else {
while at_property_value_tail(p) {
p.bump_any();
}
}
m.complete(p, OBJECT_PROPERTY);
}
fn at_allowed_values_tail(p: &Parser) -> bool {
if p.at(COMMA) {
return true;
}
let starts_new_property = p.nth_at(1, EQ);
!starts_new_property
&& !p.at(SEMICOLON)
&& !p.at(ON_KW)
&& !p.at(AFTER_KW)
&& !p.at(WHEN_KW)
&& !at_create_body(p)
&& !p.at_eof()
&& (p.at(STRING) || p.at(INT_NUMBER) || p.at(FLOAT_NUMBER))
}
fn at_property_value_tail(p: &Parser) -> bool {
if p.at(WITH_KW) || p.at(BY_KW) {
return true;
}
let starts_new_property = p.nth_at(1, EQ);
!starts_new_property
&& !p.at(SEMICOLON)
&& !p.at(ON_KW)
&& !p.at(AFTER_KW)
&& !p.at(WHEN_KW)
&& !at_create_body(p)
&& !p.at_eof()
&& (p.at(INT_NUMBER) || p.at(FLOAT_NUMBER) || p.at(STRING) || p.at(VARIABLE))
}
fn stream_source(p: &mut Parser) {
let m = p.start();
p.bump(ON_KW);
if p.at(TABLE_KW) || p.at(VIEW_KW) {
p.bump_any();
} else if p.nth_contextual(0, ContextualKeyword::Stage) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else if p.at_keyword() {
p.bump_any();
}
if p.at_name() {
name_ref(p);
}
if p.nth_contextual(0, ContextualKeyword::At) || p.nth_contextual(0, ContextualKeyword::Before)
{
p.bump_as(CONTEXTUAL_KEYWORD);
if p.at(L_PAREN) {
balanced_parens(p);
}
}
m.complete(p, STREAM_SOURCE);
}
fn task_after(p: &mut Parser) {
let m = p.start();
p.bump(AFTER_KW);
if p.at_name() {
name_ref(p);
while p.eat(COMMA) {
if p.at_name() {
name_ref(p);
} else {
break;
}
}
}
m.complete(p, TASK_AFTER);
}
fn create_body(p: &mut Parser) {
if p.at(SELECT_KW)
|| p.at(WITH_KW)
|| p.at(VALUES_KW)
|| (p.at(L_PAREN) && (p.nth_at(1, SELECT_KW) || p.nth_at(1, WITH_KW)))
{
query_expr(p);
} else if p.at(INSERT_KW) {
dml::insert_stmt(p);
} else if p.at(UPDATE_KW) {
dml::update_stmt(p);
} else if p.at(DELETE_KW) {
dml::delete_stmt(p);
} else if p.at(MERGE_KW) {
dml::merge_stmt(p);
} else if p.at(CALL_KW) {
call_stmt(p);
} else if at_block_start(p) {
block_stmt(p);
} else if !at_stmt_terminator(p) {
let m = p.start();
expr(p);
m.complete(p, EXPR_STMT);
}
}
fn create_other(p: &mut Parser) {
while !at_stmt_terminator(p) {
if at_create_query_body(p) {
p.bump(AS_KW);
query_expr(p);
return;
}
p.bump_any();
}
}
fn at_create_query_body(p: &Parser) -> bool {
p.at(AS_KW)
&& (p.nth_at(1, SELECT_KW)
|| p.nth_at(1, WITH_KW)
|| p.nth_at(1, VALUES_KW)
|| (p.nth_at(1, L_PAREN)
&& (p.nth_at(2, SELECT_KW) || p.nth_at(2, WITH_KW) || p.nth_at(2, VALUES_KW))))
}
fn at_create_body(p: &Parser) -> bool {
p.at(AS_KW)
&& (p.nth_at(1, SELECT_KW)
|| p.nth_at(1, WITH_KW)
|| p.nth_at(1, VALUES_KW)
|| p.nth_at(1, INSERT_KW)
|| p.nth_at(1, UPDATE_KW)
|| p.nth_at(1, DELETE_KW)
|| p.nth_at(1, MERGE_KW)
|| p.nth_at(1, CALL_KW)
|| p.nth_at(1, BEGIN_KW)
|| p.nth_at(1, L_PAREN))
}
fn create_routine(p: &mut Parser) {
p.bump_any(); name_ref(p);
if p.at(L_PAREN) {
column_def_list(p); }
let mut seen_returns = false;
while !at_routine_body(p) && !at_stmt_terminator(p) {
if !seen_returns && p.at(RETURNS_KW) {
routine_returns_clause(p);
seen_returns = true;
} else if p.at(LANGUAGE_KW) {
routine_language_clause(p);
} else {
p.bump_any();
}
}
if at_routine_body(p) {
p.bump(AS_KW);
if p.at(DOLLAR_STRING) || p.at(STRING) {
p.bump_any(); } else if at_block_start(p) {
block_stmt(p);
}
} else {
p.error("expected a routine body (AS $$ … $$, AS '…', or AS BEGIN … END)");
}
}
fn routine_returns_clause(p: &mut Parser) {
let m = p.start();
p.bump(RETURNS_KW);
if p.at(TABLE_KW) {
p.bump(TABLE_KW);
if p.at(L_PAREN) {
balanced_parens(p);
}
} else if !p.at(LANGUAGE_KW) && p.at_name() {
type_name(p);
} else {
p.error("expected a routine return type");
}
if p.eat(NOT_KW) {
p.expect(NULL_KW);
}
m.complete(p, ROUTINE_RETURNS_CLAUSE);
}
fn routine_language_clause(p: &mut Parser) {
let m = p.start();
p.bump(LANGUAGE_KW);
if p.at_name() || p.at_keyword() {
p.bump_any();
} else {
p.error("expected a routine language");
}
m.complete(p, ROUTINE_LANGUAGE_CLAUSE);
}
fn at_routine_body(p: &Parser) -> bool {
p.at(AS_KW)
&& (p.nth_at(1, DOLLAR_STRING)
|| p.nth_at(1, STRING)
|| p.nth_at(1, DECLARE_KW)
|| (p.nth_at(1, BEGIN_KW)
&& !p.nth_at(2, SEMICOLON)
&& !p.nth_contextual(2, ContextualKeyword::Transaction)
&& !p.nth_contextual(2, ContextualKeyword::Work)))
}
fn create_view(p: &mut Parser) {
p.bump(VIEW_KW);
if_exists_clause(p);
name_ref(p);
if p.at(L_PAREN) {
column_list(p);
}
while !p.at(AS_KW) && !p.at(SELECT_KW) && !p.at(WITH_KW) && !at_stmt_terminator(p) {
bump_ddl_word(p);
}
p.eat(AS_KW);
if p.at(SELECT_KW) || p.at(WITH_KW) || p.at(VALUES_KW) || p.at(L_PAREN) {
query_expr(p);
}
}
fn create_table(p: &mut Parser) {
p.bump(TABLE_KW);
if_exists_clause(p);
name_ref(p);
if p.at(L_PAREN) {
column_def_list(p);
}
if p.dialect().supports_delta_table_options()
&& (p.nth_contextual(0, ContextualKeyword::Shallow)
|| p.nth_contextual(0, ContextualKeyword::Deep))
&& p.nth_contextual(1, ContextualKeyword::Clone)
{
p.bump_as(CONTEXTUAL_KEYWORD);
}
if p.nth_contextual(0, ContextualKeyword::Clone) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.at_name() {
name_ref(p);
}
}
while !p.at(AS_KW) && !at_stmt_terminator(p) {
if p.dialect().supports_delta_table_options() && at_databricks_table_option(p) {
databricks_table_option(p);
} else {
bump_ddl_word(p);
}
}
if p.eat(AS_KW) {
query_expr(p);
}
}
fn at_databricks_table_option(p: &Parser) -> bool {
p.at(USING_KW)
|| p.nth_contextual(0, ContextualKeyword::Location)
|| p.nth_contextual(0, ContextualKeyword::Tblproperties)
|| p.nth_contextual(0, ContextualKeyword::Options)
|| (p.nth_contextual(0, ContextualKeyword::Partitioned) && p.nth_at(1, BY_KW))
|| (p.nth_contextual(0, ContextualKeyword::Cluster) && p.nth_at(1, BY_KW))
}
fn databricks_table_option(p: &mut Parser) {
let m = p.start();
if p.at(USING_KW) {
p.bump(USING_KW);
if p.at_name() {
name_ref(p);
} else if !at_databricks_table_option_stop(p) {
p.bump_any();
}
} else if p.nth_contextual(0, ContextualKeyword::Location) {
p.bump_as(CONTEXTUAL_KEYWORD);
if !at_databricks_table_option_stop(p) {
p.bump_any();
}
} else if p.nth_contextual(0, ContextualKeyword::Tblproperties)
|| p.nth_contextual(0, ContextualKeyword::Options)
{
p.bump_as(CONTEXTUAL_KEYWORD);
if p.at(L_PAREN) {
balanced_parens(p);
} else {
databricks_table_option_tail(p);
}
} else if p.nth_contextual(0, ContextualKeyword::Partitioned)
|| p.nth_contextual(0, ContextualKeyword::Cluster)
{
p.bump_as(CONTEXTUAL_KEYWORD);
p.expect(BY_KW);
if p.at(L_PAREN) {
balanced_parens(p);
} else {
databricks_table_option_tail(p);
}
} else {
bump_ddl_word(p);
}
m.complete(p, OBJECT_PROPERTY);
}
fn databricks_table_option_tail(p: &mut Parser) {
while !at_databricks_table_option_stop(p) && !at_databricks_table_option(p) {
if p.at(L_PAREN) {
balanced_parens(p);
} else {
bump_ddl_word(p);
}
}
}
fn at_databricks_table_option_stop(p: &Parser) -> bool {
p.at(AS_KW) || at_stmt_terminator(p)
}
fn column_def_list(p: &mut Parser) {
let m = p.start();
p.bump(L_PAREN);
if !p.at(R_PAREN) {
column_def(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
column_def(p);
}
}
p.expect(R_PAREN);
m.complete(p, COLUMN_DEF_LIST);
}
fn column_def(p: &mut Parser) {
let m = p.start();
let starts_with_constraint = p.nth_any_contextual(0, DDL_CONSTRAINT_START_CONTEXTUAL_WORDS);
if !starts_with_constraint && !p.at(COMMA) && !p.at(R_PAREN) && !p.at_eof() {
p.bump_any(); }
balanced_token_run_until(p, |p| p.at(COMMA) || p.at(R_PAREN), bump_ddl_word);
m.complete(p, COLUMN_DEF);
}
fn bump_ddl_word(p: &mut Parser) {
if p.at_keyword() {
p.bump_any(); } else if is_ddl_contextual_word(p) {
p.bump_as(CONTEXTUAL_KEYWORD); } else {
p.bump_any();
}
}
fn is_ddl_contextual_word(p: &Parser) -> bool {
p.nth_any_contextual(0, DDL_CONTEXTUAL_WORDS)
}
pub(super) fn drop_stmt(p: &mut Parser) {
let m = p.start();
p.bump(DROP_KW);
if !at_stmt_terminator(p) {
p.bump_any();
}
if_exists_clause(p);
if p.at_name() {
name_ref(p);
}
while !at_stmt_terminator(p) {
bump_ddl_word(p);
}
m.complete(p, DROP_STMT);
}
const ALTER_ACTION_LEAD_CONTEXTUAL_WORDS: &[ContextualKeyword] = &[
ContextualKeyword::Add,
ContextualKeyword::Modify,
ContextualKeyword::Rename,
ContextualKeyword::Unset,
ContextualKeyword::Suspend,
ContextualKeyword::Resume,
ContextualKeyword::Swap,
ContextualKeyword::Refresh,
];
const ALTER_RUN_CONTEXTUAL_WORDS: &[ContextualKeyword] = &[
ContextualKeyword::Column,
ContextualKeyword::Columns,
ContextualKeyword::To,
ContextualKeyword::Search,
ContextualKeyword::Optimization,
ContextualKeyword::Tblproperties,
ContextualKeyword::Options,
];
fn at_alter_object_kind(p: &Parser) -> bool {
p.at(TABLE_KW)
|| p.at(VIEW_KW)
|| p.at(WAREHOUSE_KW)
|| p.at(TASK_KW)
|| p.nth_contextual(0, ContextualKeyword::Session)
|| p.nth_contextual(0, ContextualKeyword::Schema)
|| p.nth_contextual(0, ContextualKeyword::Database)
|| (p.nth_contextual(0, ContextualKeyword::Materialized) && p.nth_at(1, VIEW_KW))
|| (p.nth_contextual(0, ContextualKeyword::Dynamic) && p.nth_at(1, TABLE_KW))
}
pub(super) fn alter_stmt(p: &mut Parser) {
let m = p.start();
p.bump(ALTER_KW);
if at_alter_object_kind(p) {
alter_object_kind_words(p);
if_exists_clause(p);
if p.at_name() && !at_alter_action_start(p, 0) {
name_ref(p);
}
alter_actions(p);
} else {
while !at_stmt_terminator(p) {
p.bump_any();
}
}
m.complete(p, ALTER_STMT);
}
fn alter_object_kind_words(p: &mut Parser) {
if p.nth_contextual(0, ContextualKeyword::Materialized) {
p.bump_as(CONTEXTUAL_KEYWORD); p.bump(VIEW_KW);
} else if p.nth_contextual(0, ContextualKeyword::Dynamic) {
p.bump_as(CONTEXTUAL_KEYWORD); p.bump(TABLE_KW);
} else if p.at_keyword() {
p.bump_any(); } else {
p.bump_as(CONTEXTUAL_KEYWORD); }
}
fn at_alter_action_start(p: &Parser, n: usize) -> bool {
p.nth_at(n, DROP_KW)
|| p.nth_at(n, ALTER_KW)
|| p.nth_at(n, SET_KW)
|| p.nth_any_contextual(n, ALTER_ACTION_LEAD_CONTEXTUAL_WORDS)
|| (p.nth_contextual(n, ContextualKeyword::Cluster) && p.nth_at(n + 1, BY_KW))
}
fn alter_actions(p: &mut Parser) {
if at_alter_action_start(p, 0) {
alter_action(p);
while p.at(COMMA) && at_alter_action_start(p, 1) {
p.bump(COMMA);
alter_action(p);
}
}
while !at_stmt_terminator(p) {
p.bump_any();
}
}
fn alter_action(p: &mut Parser) {
let m = p.start();
if p.at(SET_KW) {
p.bump(SET_KW);
alter_set_tail(p);
} else {
if p.at_keyword() {
p.bump_any(); } else {
p.bump_as(CONTEXTUAL_KEYWORD); }
alter_action_token_run(p);
}
m.complete(p, ALTER_ACTION);
}
fn alter_set_tail(p: &mut Parser) {
while at_alter_set_property(p, 0) {
object_property(p);
if p.at(COMMA) && at_alter_set_property(p, 1) && !at_alter_action_start(p, 1) {
p.bump(COMMA);
}
}
alter_action_token_run(p);
}
fn at_alter_set_property(p: &Parser, n: usize) -> bool {
(p.nth_at(n, IDENT) || p.nth_at(n, QUOTED_IDENT)) && p.nth_at(n + 1, EQ)
}
fn alter_action_token_run(p: &mut Parser) {
balanced_token_run_until(
p,
|p| at_stmt_terminator(p) || (p.at(COMMA) && at_alter_action_start(p, 1)),
bump_alter_word,
);
}
fn bump_alter_word(p: &mut Parser) {
if p.at_keyword() {
p.bump_any();
} else if is_ddl_contextual_word(p) || p.nth_any_contextual(0, ALTER_RUN_CONTEXTUAL_WORDS) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
}
pub(super) fn at_comment_stmt(p: &Parser) -> bool {
p.nth_contextual(0, ContextualKeyword::Comment) && p.nth_at(1, ON_KW)
}
pub(super) fn comment_stmt(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); while !at_stmt_terminator(p) {
p.bump_any();
}
m.complete(p, COMMENT_STMT);
}