Skip to content

Commit 7f7ac31

Browse files
committed
feat(parser): parse CREATE AGGREGATE
Wire AGGREGATE into the CREATE dispatch (before the or_replace error branch so CREATE OR REPLACE AGGREGATE is accepted). parse_create_aggregate parses the name, argument-type list, and the options block. Each recognised option keyword dispatches to parse_create_aggregate_option which produces the typed CreateAggregateOption variant.
1 parent 6774b8a commit 7f7ac31

1 file changed

Lines changed: 190 additions & 0 deletions

File tree

src/parser/mod.rs

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5173,6 +5173,8 @@ impl<'a> Parser<'a> {
51735173
self.parse_create_secret(or_replace, temporary, persistent)
51745174
} else if self.parse_keyword(Keyword::USER) {
51755175
self.parse_create_user(or_replace).map(Into::into)
5176+
} else if self.parse_keyword(Keyword::AGGREGATE) {
5177+
self.parse_create_aggregate(or_replace).map(Into::into)
51765178
} else if or_replace {
51775179
self.expected_ref(
51785180
"[EXTERNAL] TABLE or [MATERIALIZED] VIEW or FUNCTION after CREATE OR REPLACE",
@@ -7210,6 +7212,194 @@ impl<'a> Parser<'a> {
72107212
})
72117213
}
72127214

7215+
/// Parse a [Statement::CreateAggregate]
7216+
///
7217+
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-createaggregate.html)
7218+
pub fn parse_create_aggregate(
7219+
&mut self,
7220+
or_replace: bool,
7221+
) -> Result<CreateAggregate, ParserError> {
7222+
let name = self.parse_object_name(false)?;
7223+
7224+
// Argument type list: `(input_data_type [, ...])` or `(*)` for zero-arg.
7225+
self.expect_token(&Token::LParen)?;
7226+
let args = if self.consume_token(&Token::Mul) {
7227+
// zero-argument aggregate written as `(*)` — treat as empty arg list.
7228+
vec![]
7229+
} else if self.consume_token(&Token::RParen) {
7230+
self.prev_token();
7231+
vec![]
7232+
} else {
7233+
let parsed = self.parse_comma_separated(|p| p.parse_data_type())?;
7234+
parsed
7235+
};
7236+
self.expect_token(&Token::RParen)?;
7237+
7238+
// Options block: `( SFUNC = ..., STYPE = ..., ... )`
7239+
self.expect_token(&Token::LParen)?;
7240+
let mut options: Vec<CreateAggregateOption> = Vec::new();
7241+
loop {
7242+
let token = self.next_token();
7243+
match &token.token {
7244+
Token::RParen => break,
7245+
Token::Comma => continue,
7246+
Token::Word(word) => {
7247+
let option = self.parse_create_aggregate_option(&word.value.to_uppercase())?;
7248+
options.push(option);
7249+
}
7250+
other => {
7251+
return Err(ParserError::ParserError(format!(
7252+
"Unexpected token in CREATE AGGREGATE options: {other:?}"
7253+
)));
7254+
}
7255+
}
7256+
}
7257+
7258+
Ok(CreateAggregate {
7259+
or_replace,
7260+
name,
7261+
args,
7262+
options,
7263+
})
7264+
}
7265+
7266+
fn parse_create_aggregate_option(
7267+
&mut self,
7268+
key: &str,
7269+
) -> Result<CreateAggregateOption, ParserError> {
7270+
match key {
7271+
"SFUNC" => {
7272+
self.expect_token(&Token::Eq)?;
7273+
Ok(CreateAggregateOption::Sfunc(
7274+
self.parse_object_name(false)?,
7275+
))
7276+
}
7277+
"STYPE" => {
7278+
self.expect_token(&Token::Eq)?;
7279+
Ok(CreateAggregateOption::Stype(self.parse_data_type()?))
7280+
}
7281+
"SSPACE" => {
7282+
self.expect_token(&Token::Eq)?;
7283+
let size = self.parse_literal_uint()?;
7284+
Ok(CreateAggregateOption::Sspace(size))
7285+
}
7286+
"FINALFUNC" => {
7287+
self.expect_token(&Token::Eq)?;
7288+
Ok(CreateAggregateOption::Finalfunc(
7289+
self.parse_object_name(false)?,
7290+
))
7291+
}
7292+
"FINALFUNC_EXTRA" => Ok(CreateAggregateOption::FinalfuncExtra),
7293+
"FINALFUNC_MODIFY" => {
7294+
self.expect_token(&Token::Eq)?;
7295+
Ok(CreateAggregateOption::FinalfuncModify(
7296+
self.parse_aggregate_modify_kind()?,
7297+
))
7298+
}
7299+
"COMBINEFUNC" => {
7300+
self.expect_token(&Token::Eq)?;
7301+
Ok(CreateAggregateOption::Combinefunc(
7302+
self.parse_object_name(false)?,
7303+
))
7304+
}
7305+
"SERIALFUNC" => {
7306+
self.expect_token(&Token::Eq)?;
7307+
Ok(CreateAggregateOption::Serialfunc(
7308+
self.parse_object_name(false)?,
7309+
))
7310+
}
7311+
"DESERIALFUNC" => {
7312+
self.expect_token(&Token::Eq)?;
7313+
Ok(CreateAggregateOption::Deserialfunc(
7314+
self.parse_object_name(false)?,
7315+
))
7316+
}
7317+
"INITCOND" => {
7318+
self.expect_token(&Token::Eq)?;
7319+
Ok(CreateAggregateOption::Initcond(self.parse_value()?.value))
7320+
}
7321+
"MSFUNC" => {
7322+
self.expect_token(&Token::Eq)?;
7323+
Ok(CreateAggregateOption::Msfunc(
7324+
self.parse_object_name(false)?,
7325+
))
7326+
}
7327+
"MINVFUNC" => {
7328+
self.expect_token(&Token::Eq)?;
7329+
Ok(CreateAggregateOption::Minvfunc(
7330+
self.parse_object_name(false)?,
7331+
))
7332+
}
7333+
"MSTYPE" => {
7334+
self.expect_token(&Token::Eq)?;
7335+
Ok(CreateAggregateOption::Mstype(self.parse_data_type()?))
7336+
}
7337+
"MSSPACE" => {
7338+
self.expect_token(&Token::Eq)?;
7339+
let size = self.parse_literal_uint()?;
7340+
Ok(CreateAggregateOption::Msspace(size))
7341+
}
7342+
"MFINALFUNC" => {
7343+
self.expect_token(&Token::Eq)?;
7344+
Ok(CreateAggregateOption::Mfinalfunc(
7345+
self.parse_object_name(false)?,
7346+
))
7347+
}
7348+
"MFINALFUNC_EXTRA" => Ok(CreateAggregateOption::MfinalfuncExtra),
7349+
"MFINALFUNC_MODIFY" => {
7350+
self.expect_token(&Token::Eq)?;
7351+
Ok(CreateAggregateOption::MfinalfuncModify(
7352+
self.parse_aggregate_modify_kind()?,
7353+
))
7354+
}
7355+
"MINITCOND" => {
7356+
self.expect_token(&Token::Eq)?;
7357+
Ok(CreateAggregateOption::Minitcond(self.parse_value()?.value))
7358+
}
7359+
"SORTOP" => {
7360+
self.expect_token(&Token::Eq)?;
7361+
Ok(CreateAggregateOption::Sortop(
7362+
self.parse_object_name(false)?,
7363+
))
7364+
}
7365+
"PARALLEL" => {
7366+
self.expect_token(&Token::Eq)?;
7367+
let parallel = match self.expect_one_of_keywords(&[
7368+
Keyword::SAFE,
7369+
Keyword::RESTRICTED,
7370+
Keyword::UNSAFE,
7371+
])? {
7372+
Keyword::SAFE => FunctionParallel::Safe,
7373+
Keyword::RESTRICTED => FunctionParallel::Restricted,
7374+
Keyword::UNSAFE => FunctionParallel::Unsafe,
7375+
_ => unreachable!(),
7376+
};
7377+
Ok(CreateAggregateOption::Parallel(parallel))
7378+
}
7379+
"HYPOTHETICAL" => Ok(CreateAggregateOption::Hypothetical),
7380+
other => Err(ParserError::ParserError(format!(
7381+
"Unknown CREATE AGGREGATE option: {other}"
7382+
))),
7383+
}
7384+
}
7385+
7386+
fn parse_aggregate_modify_kind(&mut self) -> Result<AggregateModifyKind, ParserError> {
7387+
let token = self.next_token();
7388+
match &token.token {
7389+
Token::Word(word) => match word.value.to_uppercase().as_str() {
7390+
"READ_ONLY" => Ok(AggregateModifyKind::ReadOnly),
7391+
"SHAREABLE" => Ok(AggregateModifyKind::Shareable),
7392+
"READ_WRITE" => Ok(AggregateModifyKind::ReadWrite),
7393+
other => Err(ParserError::ParserError(format!(
7394+
"Expected READ_ONLY, SHAREABLE, or READ_WRITE, got: {other}"
7395+
))),
7396+
},
7397+
other => Err(ParserError::ParserError(format!(
7398+
"Expected READ_ONLY, SHAREABLE, or READ_WRITE, got: {other:?}"
7399+
))),
7400+
}
7401+
}
7402+
72137403
/// Parse a [Statement::CreateOperatorFamily]
72147404
///
72157405
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-createopfamily.html)

0 commit comments

Comments
 (0)