// Port of sqlglot/parser.py: transactions, ALTER, ANALYZE, MERGE, SHOW/SET, dictionaries,
// comprehensions and heredocs.
///|
pub fn Parser::parse_transaction(self : Parser) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_transaction {
Some(f) => f(self)
None => self.parse_transaction_base()
}
}
///|
pub fn Parser::parse_transaction_base(
self : Parser,
) -> Expr? raise SqlglotError {
let mut this : String? = None
if self.match_text_set(self.cfg.transaction_kind) {
this = Some(self.prev.text)
}
self.match_texts(["TRANSACTION", "WORK"]) |> ignore
let modes = []
while true {
let mode = []
while self.match_(VAR) || self.match_(NOT) {
mode.push(self.prev.text)
}
if !mode.is_empty() {
modes.push(mode.join(" "))
}
if !self.match_(COMMA) {
break
}
}
Some(self.expression(mk(Transaction, [("this", this), ("modes", modes)])))
}
///|
pub fn Parser::parse_commit_or_rollback(
self : Parser,
) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_commit_or_rollback {
Some(f) => f(self)
None => self.parse_commit_or_rollback_base()
}
}
///|
pub fn Parser::parse_commit_or_rollback_base(
self : Parser,
) -> Expr? raise SqlglotError {
let mut chain : Bool? = None
let mut savepoint : Expr? = None
let is_rollback = self.prev.token_type == ROLLBACK
self.match_texts(["TRANSACTION", "WORK"]) |> ignore
if self.match_text("TO") {
self.match_text("SAVEPOINT") |> ignore
savepoint = self.parse_id_var()
}
if self.match_(AND) {
chain = Some(!self.match_text("NO"))
self.match_text("CHAIN") |> ignore
}
if is_rollback {
return Some(self.expression(mk(Rollback, [("savepoint", savepoint)])))
}
Some(self.expression(mk(Commit, [("chain", chain)])))
}
///|
pub fn Parser::parse_refresh(self : Parser) -> Expr? raise SqlglotError {
let kind = if self.match_text_seq(["EXTERNAL", "TABLE"]) {
"EXTERNAL TABLE"
} else if self.match_(TABLE) {
"TABLE"
} else if self.match_text_seq(["MATERIALIZED", "VIEW"]) {
"MATERIALIZED VIEW"
} else {
""
}
let this = expr_or(self.parse_string(), () => self.parse_table())
let is_literal = match this {
Some(t) => t.kind == Literal
None => false
}
if kind.is_empty() && !is_literal {
return Some(self.parse_as_command(self.prev))
}
Some(self.expression(mk(Refresh, [("this", this), ("kind", kind)])))
}
///|
pub fn Parser::parse_column_def_with_exists(
self : Parser,
) -> Expr? raise SqlglotError {
let start = self.index
self.match_(COLUMN) |> ignore
let exists_column = self.parse_exists(not_=true)
let expression = self.parse_field_def()
match expression {
Some(e) if e.kind == ColumnDef => {
e.set("exists", exists_column)
Some(e)
}
_ => {
self.retreat(start)
None
}
}
}
///|
pub fn Parser::parse_add_column(self : Parser) -> Expr? raise SqlglotError {
if self.prev_upper() != "ADD" {
return None
}
self.parse_column_def_with_exists()
}
///|
pub fn Parser::parse_drop_column(self : Parser) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_drop_column {
Some(f) => f(self)
None => self.parse_drop_column_base()
}
}
///|
pub fn Parser::parse_drop_column_base(
self : Parser,
) -> Expr? raise SqlglotError {
let drop = if self.match_(DROP) { self.parse_drop() } else { None }
match drop {
Some(d) if d.kind != Command =>
// drop.set("kind", drop.args.get("kind", "COLUMN")): an explicit None kind is
// popped, a missing one becomes COLUMN
if d.has_key("kind") {
d.set("kind", d.get("kind"))
} else {
d.set("kind", "COLUMN")
}
_ => ()
}
drop
}
///|
pub fn Parser::parse_alter_drop_action(
self : Parser,
) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_alter_drop_action {
Some(f) => f(self)
None => self.parse_drop_column()
}
}
///|
pub fn Parser::parse_drop_partition(
self : Parser,
exists? : Bool?,
) -> Expr? raise SqlglotError {
let exists : Bool? = match exists {
Some(e) => e
None => None
}
Some(
self.expression(
mk(DropPartition, [
("expressions", self.parse_csv(() => self.parse_partition())),
("exists", exists),
]),
),
)
}
///|
pub fn Parser::parse_alter_table_add(
self : Parser,
) -> Array[Expr] raise SqlglotError {
fn parse_add_alteration() -> Expr? raise SqlglotError {
self.match_text("ADD") |> ignore
if self.match_set(self.cfg.add_constraint_tokens, advance=false) {
return Some(
self.expression(
mk(AddConstraint, [
("expressions", self.parse_csv(() => self.parse_constraint())),
]),
),
)
}
match self.parse_add_column() {
Some(c) if c.kind == ColumnDef => return Some(c)
_ => ()
}
let exists = self.parse_exists(not_=true)
if self.match_pair(PARTITION, L_PAREN, advance=false) {
let this = self.parse_field(any_token=true)
let location : Value? = if self.match_text("LOCATION", advance=false) {
self.parse_property()
} else {
Some(Bool(false))
}
return Some(
self.expression(
mk(AddPartition, [
("exists", exists),
("this", this),
("location", location),
]),
),
)
}
None
}
if !self.match_set(self.cfg.add_constraint_tokens, advance=false) &&
(
!self.dialect.cfg.alter_table_add_required_for_each_column ||
self.match_text("COLUMNS")
) {
let schema = self.parse_schema()
return match schema {
Some(s) => [s]
None => self.parse_csv(() => self.parse_column_def_with_exists())
}
}
self.parse_csv(parse_add_alteration)
}
///|
pub fn Parser::parse_alter_table_alter(
self : Parser,
) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_alter_table_alter {
Some(f) => f(self)
None => self.parse_alter_table_alter_base()
}
}
///|
pub fn Parser::parse_alter_table_alter_base(
self : Parser,
) -> Expr? raise SqlglotError {
if self.match_text_keys(self.fns.alter_alter_parsers) {
return self.fns.alter_alter_parsers[self.prev_upper()](self)
}
self.match_(COLUMN) |> ignore
let exists = match self.parse_exists() {
Some(true) => Some(true)
_ => None
}
let column = self.parse_field(any_token=true)
if self.match_pair(DROP, DEFAULT) {
return Some(
self.expression(
mk(AlterColumn, [("this", column), ("drop", true), ("exists", exists)]),
),
)
}
if self.match_pair(SET, DEFAULT) {
return Some(
self.expression(
mk(AlterColumn, [
("this", column),
("default", self.parse_disjunction()),
("exists", exists),
]),
),
)
}
if self.match_(COMMENT) {
return Some(
self.expression(
mk(AlterColumn, [
("this", column),
("comment", self.parse_string()),
("exists", exists),
]),
),
)
}
if self.match_text_seq(["DROP", "NOT", "NULL"]) {
return Some(
self.expression(
mk(AlterColumn, [
("this", column),
("drop", true),
("allow_null", true),
("exists", exists),
]),
),
)
}
if self.match_text_seq(["SET", "NOT", "NULL"]) {
return Some(
self.expression(
mk(AlterColumn, [
("this", column),
("allow_null", false),
("exists", exists),
]),
),
)
}
if self.match_text_seq(["SET", "VISIBLE"]) {
return Some(
self.expression(
mk(AlterColumn, [
("this", column),
("visible", "VISIBLE"),
("exists", exists),
]),
),
)
}
if self.match_text_seq(["SET", "INVISIBLE"]) {
return Some(
self.expression(
mk(AlterColumn, [
("this", column),
("visible", "INVISIBLE"),
("exists", exists),
]),
),
)
}
self.match_text_seq(["SET", "DATA"]) |> ignore
self.match_text("TYPE") |> ignore
let dtype = self.parse_types()
let collate = self.andv(self.match_(COLLATE), () => self.parse_term())
let using_ = self.andv(self.match_(USING), () => self.parse_disjunction())
Some(
self.expression(
mk(AlterColumn, [
("this", column),
("dtype", dtype),
("collate", collate),
("using", using_),
("exists", exists),
]),
),
)
}
///|
pub fn Parser::parse_alter_diststyle(self : Parser) -> Expr? raise SqlglotError {
if self.match_texts(["ALL", "EVEN", "AUTO"]) {
return Some(self.expression(mk1(AlterDistStyle, var_(self.prev_upper()))))
}
self.match_text_seq(["KEY", "DISTKEY"]) |> ignore
Some(self.expression(mk1(AlterDistStyle, self.parse_column())))
}
///|
pub fn Parser::parse_alter_sortkey(
self : Parser,
compound? : Bool,
) -> Expr? raise SqlglotError {
if compound == Some(true) {
self.match_text("SORTKEY") |> ignore
}
if self.match_(L_PAREN, advance=false) {
return Some(
self.expression(
mk(AlterSortKey, [
("expressions", self.parse_wrapped_id_vars()),
("compound", compound),
]),
),
)
}
self.match_texts(["AUTO", "NONE"]) |> ignore
Some(
self.expression(
mk(AlterSortKey, [
("this", var_(self.prev_upper())),
("compound", compound),
]),
),
)
}
///|
pub fn Parser::parse_alter_table_drop(
self : Parser,
) -> Array[Expr] raise SqlglotError {
let index = self.index - 1
let partition_exists = self.parse_exists()
if self.match_(PARTITION, advance=false) {
return self.parse_csv(() => {
self.parse_drop_partition(exists=partition_exists)
})
}
self.retreat(index)
self.parse_csv(() => self.parse_alter_drop_action())
}
///|
pub fn Parser::parse_alter_table_rename(
self : Parser,
) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_alter_table_rename {
Some(f) => f(self)
None => self.parse_alter_table_rename_base()
}
}
///|
pub fn Parser::parse_alter_table_rename_base(
self : Parser,
) -> Expr? raise SqlglotError {
if self.match_(COLUMN) ||
(
!self.cfg.alter_rename_requires_column &&
!self.match_text("TO", advance=false)
) {
let exists = self.parse_exists()
let old_column = self.parse_column()
let to = self.match_text("TO")
let new_column = self.parse_column()
if old_column is None || !to || new_column is None {
return None
}
return Some(
self.expression(
mk(RenameColumn, [
("this", old_column),
("to", new_column),
("exists", exists),
]),
),
)
}
self.match_text("TO") |> ignore
Some(self.expression(mk1(AlterRename, self.parse_table(schema=true))))
}
///|
pub fn Parser::parse_alter_table_set(self : Parser) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_alter_table_set {
Some(f) => f(self)
None => self.parse_alter_table_set_base()
}
}
///|
pub fn Parser::parse_alter_table_set_base(
self : Parser,
) -> Expr? raise SqlglotError {
let alter_set = self.expression(mk0(AlterSet))
if self.match_(L_PAREN, advance=false) ||
self.match_text_seq(["TABLE", "PROPERTIES"]) {
alter_set.set(
"expressions",
self.parse_wrapped_csv(() => self.parse_assignment()),
)
} else if self.match_text("FILESTREAM_ON", advance=false) {
alter_set.set("expressions", [self.parse_assignment()].filter_map(x => x))
} else if self.match_texts(["LOGGED", "UNLOGGED"]) {
alter_set.set("option", var_(self.prev_upper()))
} else if self.match_text("WITHOUT") && self.match_texts(["CLUSTER", "OIDS"]) {
alter_set.set("option", var_("WITHOUT \{self.prev_upper()}"))
} else if self.match_text("LOCATION") {
alter_set.set("location", self.parse_field())
} else if self.match_text_seq(["ACCESS", "METHOD"]) {
alter_set.set("access_method", self.parse_field())
} else if self.match_text("TABLESPACE") {
alter_set.set("tablespace", self.parse_field())
} else if self.match_text_seq(["FILE", "FORMAT"]) ||
self.match_text("FILEFORMAT") {
alter_set.set("file_format", [self.parse_field()].filter_map(x => x))
} else if self.match_text("STAGE_FILE_FORMAT") {
alter_set.set("file_format", self.parse_wrapped_options())
} else if self.match_text("STAGE_COPY_OPTIONS") {
alter_set.set("copy_options", self.parse_wrapped_options())
} else if self.match_text("TAG") || self.match_text("TAGS") {
alter_set.set("tag", self.parse_csv(() => self.parse_assignment()))
} else {
if self.match_text("SERDE") {
alter_set.set("serde", self.parse_field())
}
let properties = self.parse_wrapped(
() => self.parse_properties(),
optional=true,
)
alter_set.set("expressions", [properties].filter_map(x => x))
}
Some(alter_set)
}
///|
pub fn Parser::parse_alter_session(self : Parser) -> Expr? raise SqlglotError {
if self.match_(SET) {
let expressions = self.parse_csv(() => self.parse_set_item_assignment())
return Some(
self.expression(
mk(AlterSession, [("expressions", expressions), ("unset", false)]),
),
)
}
self.match_text("UNSET") |> ignore
let expressions = self.parse_csv(() => {
Some(self.expression(mk1(SetItem, self.parse_id_var(any_token=true))))
})
Some(
self.expression(
mk(AlterSession, [("expressions", expressions), ("unset", true)]),
),
)
}
///|
pub fn Parser::parse_alter(self : Parser) -> Expr? raise SqlglotError {
let start = self.prev
let iceberg = self.match_text("ICEBERG")
let alter_token = if self.match_set(self.cfg.alterables) {
self.prev
} else {
return Some(self.parse_as_command(start))
}
if iceberg && alter_token.token_type != TABLE {
return Some(self.parse_as_command(start))
}
let exists = self.parse_exists()
let only = self.match_text("ONLY")
let mut this : Expr? = None
let mut check : Bool? = None
let mut cluster : Expr? = None
if alter_token.token_type != SESSION {
this = self.parse_table(
schema=true,
parse_partition=self.cfg.alter_table_partitions,
)
check = Some(self.match_text_seq(["WITH", "CHECK"]))
cluster = if self.match_(ON) { self.parse_on_property() } else { None }
if self.next.ok() {
self.advance()
}
}
let parser = if self.prev.ok() {
self.fns.alter_parsers.get(self.prev_upper())
} else {
None
}
match parser {
Some(parser) => {
let actions = match parser(self) {
Some(Node(e)) => [e]
Some(List(l)) => l.filter_map(x => x.as_node())
_ => []
}
let not_valid = self.match_text_seq(["NOT", "VALID"])
let options = self
.parse_csv_any(() => self.parse_property())
.filter_map(x => x.as_node())
let cascade = self.dialect.cfg.alter_table_supports_cascade &&
self.match_text("CASCADE")
if !self.curr.ok() && !actions.is_empty() {
return Some(
self.expression(
mk(Alter, [
("this", this),
("kind", py_upper(alter_token.text)),
("exists", exists),
("actions", actions),
("only", only),
("options", options),
("cluster", cluster),
("not_valid", not_valid),
("check", check),
("cascade", cascade),
("iceberg", iceberg),
]),
),
)
}
}
None => ()
}
Some(self.parse_as_command(start))
}
///|
pub fn Parser::parse_analyze(self : Parser) -> Expr? raise SqlglotError {
let start = self.prev
if !self.curr.ok() {
return Some(self.expression(mk0(Analyze)))
}
let options = []
while self.match_text_set(self.cfg.analyze_styles) {
if self.prev_upper() == "BUFFER_USAGE_LIMIT" {
let n = match self.parse_number() {
Some(n) => expr_to_sql(n)
None => "None"
}
options.push("BUFFER_USAGE_LIMIT \{n}")
} else {
options.push(self.prev_upper())
}
}
let mut tables : Array[Expr] = []
let mut inner_expression : Expr? = None
let mut kind : String? = if self.curr.ok() {
Some(py_upper(self.curr.text))
} else {
None
}
if self.match_(TABLE) {
tables = self.parse_csv(() => self.parse_table_parts())
} else if self.match_(INDEX) {
tables = self.parse_table_parts() |> opt_list
} else if self.match_text("TABLES") {
if self.match_any([FROM, IN]) {
kind = Some("\{kind.unwrap_or("None")} \{self.prev_upper()}")
tables = self.parse_table(schema=true, is_db_reference=true) |> opt_list
}
} else if self.match_text("DATABASE") {
tables = self.parse_table(schema=true, is_db_reference=true) |> opt_list
} else if self.match_text("CLUSTER") {
tables = self.parse_table() |> opt_list
} else if self.match_text_keys(self.fns.analyze_expression_parsers) {
kind = None
inner_expression = self.fns.analyze_expression_parsers[self.prev_upper()](
self,
)
} else {
kind = None
tables = self.parse_csv(() => self.parse_table_parts())
}
let partition = self.try_parse(() => self.parse_partition())
if partition is None && self.match_text_set(self.cfg.partition_keywords) {
return Some(self.parse_as_command(start))
}
let mode = if self.match_text_seq(["WITH", "SYNC", "MODE"]) ||
self.match_text_seq(["WITH", "ASYNC", "MODE"]) {
Some("WITH \{py_upper(self.tokens[self.index - 2].text)} MODE")
} else {
None
}
if self.match_text_keys(self.fns.analyze_expression_parsers) {
inner_expression = self.fns.analyze_expression_parsers[self.prev_upper()](
self,
)
}
let properties = self.parse_properties()
Some(
self.expression(
mk(Analyze, [
("kind", kind),
("tables", tables),
("mode", mode),
("partition", partition),
("properties", properties),
("expression", inner_expression),
("options", options),
]),
),
)
}
///|
pub fn Parser::parse_analyze_statistics(
self : Parser,
) -> Expr? raise SqlglotError {
let mut this : String? = None
let kind = self.prev_upper()
let option = if self.match_text("DELTA") {
Some(self.prev_upper())
} else {
None
}
let mut expressions = []
if !self.match_text("STATISTICS") {
self.raise_error("Expecting token STATISTICS")
}
if self.match_text("NOSCAN") {
this = Some("NOSCAN")
} else if self.match_(FOR) {
if self.match_text_seq(["ALL", "COLUMNS"]) {
this = Some("FOR ALL COLUMNS")
}
if self.match_text("COLUMNS") {
this = Some("FOR COLUMNS")
expressions = self.parse_csv(() => self.parse_column_reference())
}
} else if self.match_text("SAMPLE") {
let sample = self.parse_number()
let k = if self.match_(PERCENT) { Some(self.prev_upper()) } else { None }
expressions = [
self.expression(mk(AnalyzeSample, [("sample", sample), ("kind", k)])),
]
}
Some(
self.expression(
mk(AnalyzeStatistics, [
("kind", kind),
("option", option),
("this", this),
("expressions", expressions),
]),
),
)
}
///|
pub fn Parser::parse_analyze_validate(
self : Parser,
) -> Expr? raise SqlglotError {
let mut kind : String? = None
let mut this : String? = None
let mut expression : Expr? = None
if self.match_text_seq(["REF", "UPDATE"]) {
kind = Some("REF")
this = Some("UPDATE")
if self.match_text_seq(["SET", "DANGLING", "TO", "NULL"]) {
this = Some("UPDATE SET DANGLING TO NULL")
}
} else if self.match_text("STRUCTURE") {
kind = Some("STRUCTURE")
if self.match_text_seq(["CASCADE", "FAST"]) {
this = Some("CASCADE FAST")
} else if self.match_text_seq(["CASCADE", "COMPLETE"]) &&
self.match_texts(["ONLINE", "OFFLINE"]) {
this = Some("CASCADE COMPLETE \{self.prev_upper()}")
expression = self.parse_into_clause()
}
}
Some(
self.expression(
mk(AnalyzeValidate, [
("kind", kind),
("this", this),
("expression", expression),
]),
),
)
}
///|
pub fn Parser::parse_analyze_columns(self : Parser) -> Expr? raise SqlglotError {
let this = self.prev_upper()
if self.match_text("COLUMNS") {
return Some(
self.expression(mk1(AnalyzeColumns, "\{this} \{self.prev_upper()}")),
)
}
None
}
///|
pub fn Parser::parse_analyze_delete(self : Parser) -> Expr? raise SqlglotError {
let kind = if self.match_text("SYSTEM") {
Some(self.prev_upper())
} else {
None
}
if self.match_text("STATISTICS") {
return Some(self.expression(mk(AnalyzeDelete, [("kind", kind)])))
}
None
}
///|
pub fn Parser::parse_analyze_list(self : Parser) -> Expr? raise SqlglotError {
if self.match_text_seq(["CHAINED", "ROWS"]) {
return Some(
self.expression(
mk(AnalyzeListChainedRows, [("expression", self.parse_into_clause())]),
),
)
}
None
}
///|
pub fn Parser::parse_analyze_histogram(
self : Parser,
) -> Expr? raise SqlglotError {
let this = self.prev_upper()
let mut expression : Expr? = None
let mut expressions = []
let mut update_options : String? = None
if self.match_text_seq(["HISTOGRAM", "ON"]) {
expressions = self.parse_csv(() => self.parse_column_reference())
let with_expressions = []
while self.match_(WITH) {
if self.match_texts(["SYNC", "ASYNC"]) {
if self.match_text("MODE", advance=false) {
with_expressions.push("\{self.prev_upper()} MODE")
self.advance()
}
} else {
let buckets = self.parse_number()
if self.match_text("BUCKETS") {
let b = match buckets {
Some(b) => expr_to_sql(b)
None => "None"
}
with_expressions.push("\{b} BUCKETS")
}
}
}
if !with_expressions.is_empty() {
expression = Some(
self.expression(mk(AnalyzeWith, [("expressions", with_expressions)])),
)
}
if self.match_texts(["MANUAL", "AUTO"]) &&
self.match_(UPDATE, advance=false) {
update_options = Some(self.prev_upper())
self.advance()
} else if self.match_text_seq(["USING", "DATA"]) {
expression = Some(self.expression(mk1(UsingData, self.parse_string())))
}
}
Some(
self.expression(
mk(AnalyzeHistogram, [
("this", this),
("expressions", expressions),
("expression", expression),
("update_options", update_options),
]),
),
)
}
///|
pub fn Parser::parse_merge(self : Parser) -> Expr? raise SqlglotError {
self.match_(INTO) |> ignore
let target = self.parse_table()
match target {
Some(t) if self.match_(ALIAS, advance=false) =>
t.set("alias", self.parse_table_alias())
_ => ()
}
self.match_(USING) |> ignore
let using_ = self.parse_table()
let on = self.andv(self.match_(ON), () => self.parse_disjunction())
let using_cond = self.andl(self.match_(USING), () => {
self.parse_using_identifiers()
})
let whens = self.parse_when_matched()
let returning = self.parse_returning()
Some(
self.expression(
mk(Merge, [
("this", target),
("using", using_),
("on", on),
("using_cond", using_cond),
("whens", whens),
("returning", returning),
]),
),
)
}
///|
pub fn Parser::parse_when_matched(self : Parser) -> Expr? raise SqlglotError {
let whens = []
while self.match_(WHEN) {
let matched = !self.match_(NOT)
self.match_text("MATCHED") |> ignore
let source = if self.match_text_seq(["BY", "TARGET"]) {
false
} else {
self.match_text_seq(["BY", "SOURCE"])
}
let condition = if self.match_(AND) {
self.parse_disjunction()
} else {
None
}
self.match_(THEN) |> ignore
let then = if self.match_(INSERT) {
match self.parse_star() {
Some(this) => Some(self.expression(mk1(Insert, this)))
None => {
let this = if self.match_text("ROW") {
Some(var_("ROW"))
} else {
self.parse_value(values=false)
}
let expression = self.andv(self.match_text("VALUES"), () => {
self.parse_value()
})
let where_ = self.parse_where()
Some(
self.expression(
mk(Insert, [
("this", this),
("expression", expression),
("where", where_),
]),
),
)
}
}
} else if self.match_(UPDATE) {
match self.parse_star() {
Some(expressions) =>
Some(self.expression(mk(Update, [("expressions", expressions)])))
None => {
let expressions = self.andl(self.match_(SET), () => {
self.parse_csv(() => self.parse_update_assignment())
})
let where_ = self.parse_where()
Some(
self.expression(
mk(Update, [("expressions", expressions), ("where", where_)]),
),
)
}
}
} else if self.match_(DELETE) {
Some(self.expression(mk1(Var, self.prev.text)))
} else {
self.parse_var_from_options(self.cfg.conflict_actions)
}
whens.push(
self.expression(
mk(When, [
("matched", matched),
("source", source),
("condition", condition),
("then", then),
]),
),
)
}
Some(self.expression(mk(Whens, [("expressions", whens)])))
}
///|
pub fn Parser::parse_show(self : Parser) -> Expr? raise SqlglotError {
match self.find_parser(self.fns.show_parsers, self.fns.show_trie) {
Some(parser) => parser(self)
None => Some(self.parse_as_command(self.prev))
}
}
///|
pub fn Parser::parse_set_item_assignment(
self : Parser,
kind? : String,
) -> Expr? raise SqlglotError {
let index = self.index
if (kind == Some("GLOBAL") || kind == Some("SESSION")) &&
self.match_text("TRANSACTION") {
return Some(self.parse_set_transaction(global_=kind == Some("GLOBAL")))
}
let left = expr_or(self.parse_primary(), () => self.parse_column())
let assignment_delimiter = self.match_text_set(
self.cfg.set_assignment_delimiters,
)
if left is None ||
(self.cfg.set_requires_assignment_delimiter && !assignment_delimiter) {
self.retreat(index)
return None
}
let mut right = expr_or(self.parse_statement(), () => self.parse_id_var())
match right {
Some(r) if r.kind.is_any([Column, Identifier]) =>
right = Some(var_(r.name()))
_ => ()
}
let this = self.expression(mk(EQ, [("this", left), ("expression", right)]))
Some(self.expression(mk(SetItem, [("this", this), ("kind", kind)])))
}
///|
pub fn Parser::parse_set_transaction(
self : Parser,
global_? : Bool = false,
) -> Expr raise SqlglotError {
self.match_text("TRANSACTION") |> ignore
let characteristics = self.parse_csv(() => {
self.parse_var_from_options(self.cfg.transaction_characteristics)
})
self.expression(
mk(SetItem, [
("expressions", characteristics),
("kind", "TRANSACTION"),
("global_", global_),
]),
)
}
///|
pub fn Parser::parse_set_item(self : Parser) -> Expr? raise SqlglotError {
match self.find_parser(self.fns.set_parsers, self.fns.set_trie) {
Some(parser) => parser(self)
None => self.parse_set_item_assignment()
}
}
///|
pub fn Parser::parse_set(
self : Parser,
unset? : Bool = false,
tag? : Bool = false,
) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_set {
Some(f) => f(self, unset, tag)
None => self.parse_set_base(unset~, tag~)
}
}
///|
pub fn Parser::parse_set_base(
self : Parser,
unset? : Bool = false,
tag? : Bool = false,
) -> Expr? raise SqlglotError {
let index = self.index
let set_ = self.expression(
mk(Set, [
("expressions", self.parse_csv(() => self.parse_set_item())),
("unset", unset),
("tag", tag),
]),
)
if self.curr.ok() {
self.retreat(index)
return Some(self.parse_as_command(self.prev))
}
Some(set_)
}
///|
pub fn Parser::parse_dict_property(
self : Parser,
this : String,
) -> Expr? raise SqlglotError {
let settings = []
self.match_l_paren()
let kind = self.parse_id_var()
if self.match_(L_PAREN) {
while true {
let key = self.parse_id_var()
let value = expr_or(self.parse_function(), () => {
self.parse_primary_or_var()
})
if key is None && value is None {
break
}
settings.push(
self.expression(mk(DictSubProperty, [("this", key), ("value", value)])),
)
}
self.match_(R_PAREN) |> ignore
}
self.match_r_paren()
let kind_v : Value? = match kind {
Some(k) => k.args.get("this")
None => None
}
Some(
self.expression(
mk(DictProperty, [
("this", this),
("kind", kind_v),
("settings", settings),
]),
),
)
}
///|
pub fn Parser::parse_dict_range(
self : Parser,
this : String,
) -> Expr? raise SqlglotError {
self.match_l_paren()
let has_min = self.match_text("MIN")
let (min, max) = if has_min {
let min = expr_or(self.parse_var(), () => self.parse_primary())
self.match_text("MAX") |> ignore
let max = expr_or(self.parse_var(), () => self.parse_primary())
(min, max)
} else {
let max = expr_or(self.parse_var(), () => self.parse_primary())
(Some(literal_int(0)), max)
}
self.match_r_paren()
Some(
self.expression(mk(DictRange, [("this", this), ("min", min), ("max", max)])),
)
}
///|
pub fn Parser::parse_comprehension(
self : Parser,
this : Expr?,
) -> Expr? raise SqlglotError {
let index = self.index
let expression = self.parse_column()
let position = self.andv(self.match_(COMMA), () => self.parse_column())
if !self.match_(IN) {
self.retreat(index - 1)
return None
}
let iterator = self.parse_column()
let condition = if self.match_text("IF") {
self.parse_disjunction()
} else {
None
}
Some(
self.expression(
mk(Comprehension, [
("this", this),
("expression", expression),
("position", position),
("iterator", iterator),
("condition", condition),
]),
),
)
}
///|
pub fn Parser::parse_heredoc(self : Parser) -> Expr? raise SqlglotError {
if self.match_(HEREDOC_STRING) {
return Some(self.expression(mk1(Heredoc, self.prev.text)))
}
if !self.match_text("$") {
return None
}
let tags = ["$"]
let mut tag_text : String? = None
if self.is_connected() {
self.advance()
tags.push(self.prev_upper())
} else {
self.raise_error("No closing $ found")
}
if tags[tags.length() - 1] != "$" {
if self.is_connected() && self.match_text("$") {
tag_text = Some(tags[tags.length() - 1])
tags.push("$")
} else {
self.raise_error("No closing $ found")
}
}
let heredoc_start = self.curr
while self.curr.ok() {
if self.match_text_seq(tags, advance=false) {
let this = self.find_sql(heredoc_start, self.prev)
self.advance(times=tags.length())
return Some(
self.expression(mk(Heredoc, [("this", this), ("tag", tag_text)])),
)
}
self.advance()
}
self.raise_error("No closing \{tags.join("")} found")
None
}