Skip to content

Commit 8c97e3d

Browse files
committed
feat(parser): parse CREATE STATISTICS, ACCESS METHOD, EVENT TRIGGER, TRANSFORM
Add parse_create_statistics, parse_create_access_method, parse_create_event_trigger, and parse_create_transform to the parser. - STATISTICS: name, optional IF NOT EXISTS, optional (kind, ...) list, ON expr-list, FROM table - ACCESS METHOD: name TYPE INDEX|TABLE HANDLER function - EVENT TRIGGER: name ON event [WHEN TAG IN (...)] EXECUTE FUNCTION|PROCEDURE name() - TRANSFORM: [OR REPLACE] FOR type LANGUAGE lang (element, ...) TRANSFORM is dispatched before the or_replace error guard.
1 parent ceb1cf3 commit 8c97e3d

1 file changed

Lines changed: 164 additions & 0 deletions

File tree

src/parser/mod.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,6 +5175,8 @@ impl<'a> Parser<'a> {
51755175
self.parse_create_user(or_replace).map(Into::into)
51765176
} else if self.parse_keyword(Keyword::AGGREGATE) {
51775177
self.parse_create_aggregate(or_replace).map(Into::into)
5178+
} else if self.parse_keyword(Keyword::TRANSFORM) {
5179+
self.parse_create_transform(or_replace).map(Into::into)
51785180
} else if or_replace {
51795181
self.expected_ref(
51805182
"[EXTERNAL] TABLE or [MATERIALIZED] VIEW or FUNCTION after CREATE OR REPLACE",
@@ -5232,6 +5234,12 @@ impl<'a> Parser<'a> {
52325234
self.parse_create_publication().map(Into::into)
52335235
} else if self.parse_keyword(Keyword::SUBSCRIPTION) {
52345236
self.parse_create_subscription().map(Into::into)
5237+
} else if self.parse_keyword(Keyword::STATISTICS) {
5238+
self.parse_create_statistics().map(Into::into)
5239+
} else if self.parse_keywords(&[Keyword::ACCESS, Keyword::METHOD]) {
5240+
self.parse_create_access_method().map(Into::into)
5241+
} else if self.parse_keywords(&[Keyword::EVENT, Keyword::TRIGGER]) {
5242+
self.parse_create_event_trigger().map(Into::into)
52355243
} else {
52365244
self.expected_ref("an object type after CREATE", self.peek_token_ref())
52375245
}
@@ -20268,6 +20276,162 @@ impl<'a> Parser<'a> {
2026820276
})
2026920277
}
2027020278

20279+
/// Parse a `CREATE STATISTICS` statement.
20280+
///
20281+
/// See <https://www.postgresql.org/docs/current/sql-createstatistics.html>
20282+
pub fn parse_create_statistics(&mut self) -> Result<CreateStatistics, ParserError> {
20283+
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
20284+
let name = self.parse_object_name(false)?;
20285+
20286+
let kinds = if self.consume_token(&Token::LParen) {
20287+
let kinds = self.parse_comma_separated(|p| {
20288+
let ident = p.parse_identifier()?;
20289+
match ident.value.to_lowercase().as_str() {
20290+
"ndistinct" => Ok(StatisticsKind::NDistinct),
20291+
"dependencies" => Ok(StatisticsKind::Dependencies),
20292+
"mcv" => Ok(StatisticsKind::Mcv),
20293+
other => Err(ParserError::ParserError(format!(
20294+
"Unknown statistics kind: {other}"
20295+
))),
20296+
}
20297+
})?;
20298+
self.expect_token(&Token::RParen)?;
20299+
kinds
20300+
} else {
20301+
vec![]
20302+
};
20303+
20304+
self.expect_keyword_is(Keyword::ON)?;
20305+
let on = self.parse_comma_separated(Parser::parse_expr)?;
20306+
self.expect_keyword_is(Keyword::FROM)?;
20307+
let from = self.parse_object_name(false)?;
20308+
20309+
Ok(CreateStatistics {
20310+
if_not_exists,
20311+
name,
20312+
kinds,
20313+
on,
20314+
from,
20315+
})
20316+
}
20317+
20318+
/// Parse a `CREATE ACCESS METHOD` statement.
20319+
///
20320+
/// See <https://www.postgresql.org/docs/current/sql-create-access-method.html>
20321+
pub fn parse_create_access_method(&mut self) -> Result<CreateAccessMethod, ParserError> {
20322+
let name = self.parse_identifier()?;
20323+
self.expect_keyword_is(Keyword::TYPE)?;
20324+
let method_type = if self.parse_keyword(Keyword::INDEX) {
20325+
AccessMethodType::Index
20326+
} else if self.parse_keyword(Keyword::TABLE) {
20327+
AccessMethodType::Table
20328+
} else {
20329+
return self.expected_ref("INDEX or TABLE after TYPE", self.peek_token_ref());
20330+
};
20331+
self.expect_keyword_is(Keyword::HANDLER)?;
20332+
let handler = self.parse_object_name(false)?;
20333+
20334+
Ok(CreateAccessMethod {
20335+
name,
20336+
method_type,
20337+
handler,
20338+
})
20339+
}
20340+
20341+
/// Parse a `CREATE EVENT TRIGGER` statement.
20342+
///
20343+
/// See <https://www.postgresql.org/docs/current/sql-createeventtrigger.html>
20344+
pub fn parse_create_event_trigger(&mut self) -> Result<CreateEventTrigger, ParserError> {
20345+
let name = self.parse_identifier()?;
20346+
self.expect_keyword_is(Keyword::ON)?;
20347+
let event_ident = self.parse_identifier()?;
20348+
let event = match event_ident.value.to_lowercase().as_str() {
20349+
"ddl_command_start" => EventTriggerEvent::DdlCommandStart,
20350+
"ddl_command_end" => EventTriggerEvent::DdlCommandEnd,
20351+
"table_rewrite" => EventTriggerEvent::TableRewrite,
20352+
"sql_drop" => EventTriggerEvent::SqlDrop,
20353+
other => {
20354+
return Err(ParserError::ParserError(format!(
20355+
"Unknown event trigger event: {other}"
20356+
)))
20357+
}
20358+
};
20359+
20360+
let when_tags = if self.parse_keyword(Keyword::WHEN) {
20361+
self.expect_keyword_is(Keyword::TAG)?;
20362+
self.expect_keyword_is(Keyword::IN)?;
20363+
self.expect_token(&Token::LParen)?;
20364+
let tags = self.parse_comma_separated(|p| p.parse_value().map(|v| v.value))?;
20365+
self.expect_token(&Token::RParen)?;
20366+
Some(tags)
20367+
} else {
20368+
None
20369+
};
20370+
20371+
self.expect_keyword_is(Keyword::EXECUTE)?;
20372+
let is_procedure = if self.parse_keyword(Keyword::FUNCTION) {
20373+
false
20374+
} else if self.parse_keyword(Keyword::PROCEDURE) {
20375+
true
20376+
} else {
20377+
return self.expected_ref("FUNCTION or PROCEDURE after EXECUTE", self.peek_token_ref());
20378+
};
20379+
let execute = self.parse_object_name(false)?;
20380+
self.expect_token(&Token::LParen)?;
20381+
self.expect_token(&Token::RParen)?;
20382+
20383+
Ok(CreateEventTrigger {
20384+
name,
20385+
event,
20386+
when_tags,
20387+
execute,
20388+
is_procedure,
20389+
})
20390+
}
20391+
20392+
/// Parse a `CREATE [OR REPLACE] TRANSFORM` statement.
20393+
///
20394+
/// See <https://www.postgresql.org/docs/current/sql-createtransform.html>
20395+
pub fn parse_create_transform(&mut self, or_replace: bool) -> Result<CreateTransform, ParserError> {
20396+
self.expect_keyword_is(Keyword::FOR)?;
20397+
let type_name = self.parse_data_type()?;
20398+
self.expect_keyword_is(Keyword::LANGUAGE)?;
20399+
let language = self.parse_identifier()?;
20400+
self.expect_token(&Token::LParen)?;
20401+
let elements = self.parse_comma_separated(|p| {
20402+
let is_from = if p.parse_keyword(Keyword::FROM) {
20403+
true
20404+
} else {
20405+
p.expect_keyword_is(Keyword::TO)?;
20406+
false
20407+
};
20408+
p.expect_keyword_is(Keyword::SQL)?;
20409+
p.expect_keyword_is(Keyword::WITH)?;
20410+
p.expect_keyword_is(Keyword::FUNCTION)?;
20411+
let function = p.parse_object_name(false)?;
20412+
p.expect_token(&Token::LParen)?;
20413+
let arg_types = if p.peek_token().token == Token::RParen {
20414+
vec![]
20415+
} else {
20416+
p.parse_comma_separated(|p| p.parse_data_type())?
20417+
};
20418+
p.expect_token(&Token::RParen)?;
20419+
Ok(TransformElement {
20420+
is_from,
20421+
function,
20422+
arg_types,
20423+
})
20424+
})?;
20425+
self.expect_token(&Token::RParen)?;
20426+
20427+
Ok(CreateTransform {
20428+
or_replace,
20429+
type_name,
20430+
language,
20431+
elements,
20432+
})
20433+
}
20434+
2027120435
/// The index of the first unprocessed token.
2027220436
pub fn index(&self) -> usize {
2027320437
self.index

0 commit comments

Comments
 (0)