Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorganize the Parser module #1581

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
648 changes: 492 additions & 156 deletions src/parser/alter.rs

Large diffs are not rendered by default.

59 changes: 59 additions & 0 deletions src/parser/analyze.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::parser::*;

impl Parser<'_> {
pub fn parse_analyze(&mut self) -> Result<Statement, ParserError> {
self.expect_keyword(Keyword::TABLE)?;
let table_name = self.parse_object_name(false)?;
let mut for_columns = false;
let mut cache_metadata = false;
let mut noscan = false;
let mut partitions = None;
let mut compute_statistics = false;
let mut columns = vec![];
loop {
match self.parse_one_of_keywords(&[
Keyword::PARTITION,
Keyword::FOR,
Keyword::CACHE,
Keyword::NOSCAN,
Keyword::COMPUTE,
]) {
Some(Keyword::PARTITION) => {
self.expect_token(&Token::LParen)?;
partitions = Some(self.parse_comma_separated(Parser::parse_expr)?);
self.expect_token(&Token::RParen)?;
}
Some(Keyword::NOSCAN) => noscan = true,
Some(Keyword::FOR) => {
self.expect_keyword(Keyword::COLUMNS)?;

columns = self
.maybe_parse(|parser| {
parser.parse_comma_separated(|p| p.parse_identifier(false))
})?
.unwrap_or_default();
for_columns = true
}
Some(Keyword::CACHE) => {
self.expect_keyword(Keyword::METADATA)?;
cache_metadata = true
}
Some(Keyword::COMPUTE) => {
self.expect_keyword(Keyword::STATISTICS)?;
compute_statistics = true
}
_ => break,
}
}

Ok(Statement::Analyze {
table_name,
for_columns,
columns,
partitions,
cache_metadata,
noscan,
compute_statistics,
})
}
}
14 changes: 14 additions & 0 deletions src/parser/assert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use crate::parser::*;

impl Parser<'_> {
pub fn parse_assert(&mut self) -> Result<Statement, ParserError> {
let condition = self.parse_expr()?;
let message = if self.parse_keyword(Keyword::AS) {
Some(self.parse_expr()?)
} else {
None
};

Ok(Statement::Assert { condition, message })
}
}
23 changes: 23 additions & 0 deletions src/parser/assignment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::parser::*;

impl Parser<'_> {
/// Parse a `var = expr` assignment, used in an UPDATE statement
pub fn parse_assignment(&mut self) -> Result<Assignment, ParserError> {
let target = self.parse_assignment_target()?;
self.expect_token(&Token::Eq)?;
let value = self.parse_expr()?;
Ok(Assignment { target, value })
}

/// Parse the left-hand side of an assignment, used in an UPDATE statement
pub fn parse_assignment_target(&mut self) -> Result<AssignmentTarget, ParserError> {
if self.consume_token(&Token::LParen) {
let columns = self.parse_comma_separated(|p| p.parse_object_name(false))?;
self.expect_token(&Token::RParen)?;
Ok(AssignmentTarget::Tuple(columns))
} else {
let column = self.parse_object_name(false)?;
Ok(AssignmentTarget::ColumnName(column))
}
}
}
15 changes: 15 additions & 0 deletions src/parser/attach.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::parser::*;

impl Parser<'_> {
pub fn parse_attach_database(&mut self) -> Result<Statement, ParserError> {
let database = self.parse_keyword(Keyword::DATABASE);
let database_file_name = self.parse_expr()?;
self.expect_keyword(Keyword::AS)?;
let schema_name = self.parse_identifier(false)?;
Ok(Statement::AttachDatabase {
database,
schema_name,
database_file_name,
})
}
}
93 changes: 93 additions & 0 deletions src/parser/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use crate::parser::*;

impl Parser<'_> {
/// Parse a CACHE TABLE statement
pub fn parse_cache_table(&mut self) -> Result<Statement, ParserError> {
let (mut table_flag, mut options, mut has_as, mut query) = (None, vec![], false, None);
if self.parse_keyword(Keyword::TABLE) {
let table_name = self.parse_object_name(false)?;
if self.peek_token().token != Token::EOF {
if let Token::Word(word) = self.peek_token().token {
if word.keyword == Keyword::OPTIONS {
options = self.parse_options(Keyword::OPTIONS)?
}
};

if self.peek_token().token != Token::EOF {
let (a, q) = self.parse_as_query()?;
has_as = a;
query = Some(q);
}

Ok(Statement::Cache {
table_flag,
table_name,
has_as,
options,
query,
})
} else {
Ok(Statement::Cache {
table_flag,
table_name,
has_as,
options,
query,
})
}
} else {
table_flag = Some(self.parse_object_name(false)?);
if self.parse_keyword(Keyword::TABLE) {
let table_name = self.parse_object_name(false)?;
if self.peek_token() != Token::EOF {
if let Token::Word(word) = self.peek_token().token {
if word.keyword == Keyword::OPTIONS {
options = self.parse_options(Keyword::OPTIONS)?
}
};

if self.peek_token() != Token::EOF {
let (a, q) = self.parse_as_query()?;
has_as = a;
query = Some(q);
}

Ok(Statement::Cache {
table_flag,
table_name,
has_as,
options,
query,
})
} else {
Ok(Statement::Cache {
table_flag,
table_name,
has_as,
options,
query,
})
}
} else {
if self.peek_token() == Token::EOF {
self.prev_token();
}
self.expected("a `TABLE` keyword", self.peek_token())
}
}
}

/// Parse 'AS' before as query,such as `WITH XXX AS SELECT XXX` oer `CACHE TABLE AS SELECT XXX`
pub fn parse_as_query(&mut self) -> Result<(bool, Box<Query>), ParserError> {
match self.peek_token().token {
Token::Word(word) => match word.keyword {
Keyword::AS => {
self.next_token();
Ok((true, self.parse_query()?))
}
_ => Ok((false, self.parse_query()?)),
},
_ => self.expected("a QUERY statement", self.peek_token()),
}
}
}
82 changes: 82 additions & 0 deletions src/parser/call.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::parser::*;

use crate::parser_err;

impl Parser<'_> {
/// Parse a `CALL procedure_name(arg1, arg2, ...)`
/// or `CALL procedure_name` statement
pub fn parse_call(&mut self) -> Result<Statement, ParserError> {
let object_name = self.parse_object_name(false)?;
if self.peek_token().token == Token::LParen {
match self.parse_function(object_name)? {
Expr::Function(f) => Ok(Statement::Call(f)),
other => parser_err!(
format!("Expected a simple procedure call but found: {other}"),
self.peek_token().span.start
),
}
} else {
Ok(Statement::Call(Function {
name: object_name,
parameters: FunctionArguments::None,
args: FunctionArguments::None,
over: None,
filter: None,
null_treatment: None,
within_group: vec![],
}))
}
}

pub fn parse_function_desc(&mut self) -> Result<FunctionDesc, ParserError> {
let name = self.parse_object_name(false)?;

let args = if self.consume_token(&Token::LParen) {
if self.consume_token(&Token::RParen) {
None
} else {
let args = self.parse_comma_separated(Parser::parse_function_arg)?;
self.expect_token(&Token::RParen)?;
Some(args)
}
} else {
None
};

Ok(FunctionDesc { name, args })
}

pub(crate) fn parse_function_arg(&mut self) -> Result<OperateFunctionArg, ParserError> {
let mode = if self.parse_keyword(Keyword::IN) {
Some(ArgMode::In)
} else if self.parse_keyword(Keyword::OUT) {
Some(ArgMode::Out)
} else if self.parse_keyword(Keyword::INOUT) {
Some(ArgMode::InOut)
} else {
None
};

// parse: [ argname ] argtype
let mut name = None;
let mut data_type = self.parse_data_type()?;
if let DataType::Custom(n, _) = &data_type {
// the first token is actually a name
name = Some(n.0[0].clone());
data_type = self.parse_data_type()?;
}

let default_expr = if self.parse_keyword(Keyword::DEFAULT) || self.consume_token(&Token::Eq)
{
Some(self.parse_expr()?)
} else {
None
};
Ok(OperateFunctionArg {
mode,
name,
data_type,
default_expr,
})
}
}
15 changes: 15 additions & 0 deletions src/parser/close.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::parser::*;

impl Parser<'_> {
pub fn parse_close(&mut self) -> Result<Statement, ParserError> {
let cursor = if self.parse_keyword(Keyword::ALL) {
CloseCursor::All
} else {
let name = self.parse_identifier(false)?;

CloseCursor::Specific { name }
};

Ok(Statement::Close { cursor })
}
}
Loading
Loading