Skip to content

Commit cfe7ee5

Browse files
committed
make precision on FLOAT optional for now
1 parent 4dbd769 commit cfe7ee5

File tree

3 files changed

+52
-40
lines changed

3 files changed

+52
-40
lines changed

docs/custom_sql_parser.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Writing a Custom SQL Parser
2+
3+
I have explored many different ways of building this library to make it easy to extend it for custom SQL dialects. Most of my attempts ended in failure but I have now found a workable solution. It is not without downsides but this seems to be the most pragmatic solution.
4+
5+
The concept is simply to write a new parser that delegates to the ANSI parser so that as much as possible of the core functionality can be re-used.
6+

src/sqlast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ pub enum SQLType {
9595
Int,
9696
/// Big integer
9797
BigInt,
98-
/// Floating point with precision e.g. FLOAT(8)
99-
Float(usize),
98+
/// Floating point with optional precision e.g. FLOAT(8)
99+
Float(Option<usize>),
100100
/// Floating point e.g. REAL
101101
Real,
102102
/// Double e.g. DOUBLE PRECISION

src/sqlparser.rs

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -64,32 +64,23 @@ impl Parser {
6464
}
6565

6666
/// Parse tokens until the precedence changes
67-
fn parse_expr(&mut self, precedence: u8) -> Result<ASTNode, ParserError> {
68-
// println!("parse_expr() precendence = {}", precedence);
69-
67+
pub fn parse_expr(&mut self, precedence: u8) -> Result<ASTNode, ParserError> {
7068
let mut expr = self.parse_prefix()?;
71-
// println!("parsed prefix: {:?}", expr);
72-
7369
loop {
7470
let next_precedence = self.get_next_precedence()?;
7571
if precedence >= next_precedence {
76-
// println!("break on precedence change ({} >= {})", precedence, next_precedence);
7772
break;
7873
}
7974

8075
if let Some(infix_expr) = self.parse_infix(expr.clone(), next_precedence)? {
81-
// println!("parsed infix: {:?}", infix_expr);
8276
expr = infix_expr;
8377
}
8478
}
85-
86-
// println!("parse_expr() returning {:?}", expr);
87-
8879
Ok(expr)
8980
}
9081

9182
/// Parse an expression prefix
92-
fn parse_prefix(&mut self) -> Result<ASTNode, ParserError> {
83+
pub fn parse_prefix(&mut self) -> Result<ASTNode, ParserError> {
9384
match self.next_token() {
9485
Some(t) => {
9586
match t {
@@ -150,7 +141,7 @@ impl Parser {
150141
}
151142

152143
/// Parse a SQL CAST function e.g. `CAST(expr AS FLOAT)`
153-
fn parse_cast_expression(&mut self) -> Result<ASTNode, ParserError> {
144+
pub fn parse_cast_expression(&mut self) -> Result<ASTNode, ParserError> {
154145
let expr = self.parse_expr(0)?;
155146
self.consume_token(&Token::Keyword("AS".to_string()))?;
156147
let data_type = self.parse_data_type()?;
@@ -162,7 +153,7 @@ impl Parser {
162153
}
163154

164155
/// Parse an expression infix (typically an operator)
165-
fn parse_infix(
156+
pub fn parse_infix(
166157
&mut self,
167158
expr: ASTNode,
168159
precedence: u8,
@@ -206,7 +197,7 @@ impl Parser {
206197
}
207198

208199
/// Convert a token operator to an AST operator
209-
fn to_sql_operator(&self, tok: &Token) -> Result<SQLOperator, ParserError> {
200+
pub fn to_sql_operator(&self, tok: &Token) -> Result<SQLOperator, ParserError> {
210201
match tok {
211202
&Token::Eq => Ok(SQLOperator::Eq),
212203
&Token::Neq => Ok(SQLOperator::NotEq),
@@ -226,7 +217,7 @@ impl Parser {
226217
}
227218

228219
/// Get the precedence of the next token
229-
fn get_next_precedence(&self) -> Result<u8, ParserError> {
220+
pub fn get_next_precedence(&self) -> Result<u8, ParserError> {
230221
if self.index < self.tokens.len() {
231222
self.get_precedence(&self.tokens[self.index])
232223
} else {
@@ -235,7 +226,7 @@ impl Parser {
235226
}
236227

237228
/// Get the precedence of a token
238-
fn get_precedence(&self, tok: &Token) -> Result<u8, ParserError> {
229+
pub fn get_precedence(&self, tok: &Token) -> Result<u8, ParserError> {
239230
//println!("get_precedence() {:?}", tok);
240231

241232
match tok {
@@ -252,7 +243,7 @@ impl Parser {
252243
}
253244

254245
/// Peek at the next token
255-
fn peek_token(&mut self) -> Option<Token> {
246+
pub fn peek_token(&mut self) -> Option<Token> {
256247
if self.index < self.tokens.len() {
257248
Some(self.tokens[self.index].clone())
258249
} else {
@@ -261,7 +252,7 @@ impl Parser {
261252
}
262253

263254
/// Get the next token and increment the token index
264-
fn next_token(&mut self) -> Option<Token> {
255+
pub fn next_token(&mut self) -> Option<Token> {
265256
if self.index < self.tokens.len() {
266257
self.index = self.index + 1;
267258
Some(self.tokens[self.index - 1].clone())
@@ -271,7 +262,7 @@ impl Parser {
271262
}
272263

273264
/// Get the previous token and decrement the token index
274-
fn prev_token(&mut self) -> Option<Token> {
265+
pub fn prev_token(&mut self) -> Option<Token> {
275266
if self.index > 0 {
276267
Some(self.tokens[self.index - 1].clone())
277268
} else {
@@ -280,7 +271,7 @@ impl Parser {
280271
}
281272

282273
/// Look for an expected keyword and consume it if it exists
283-
fn parse_keyword(&mut self, expected: &'static str) -> bool {
274+
pub fn parse_keyword(&mut self, expected: &'static str) -> bool {
284275
match self.peek_token() {
285276
Some(Token::Keyword(k)) => {
286277
if expected.eq_ignore_ascii_case(k.as_str()) {
@@ -295,7 +286,7 @@ impl Parser {
295286
}
296287

297288
/// Look for an expected sequence of keywords and consume them if they exist
298-
fn parse_keywords(&mut self, keywords: Vec<&'static str>) -> bool {
289+
pub fn parse_keywords(&mut self, keywords: Vec<&'static str>) -> bool {
299290
let index = self.index;
300291
for keyword in keywords {
301292
//println!("parse_keywords aborting .. expecting {}", keyword);
@@ -312,7 +303,7 @@ impl Parser {
312303
//TODO: this function is inconsistent and sometimes returns bool and sometimes fails
313304

314305
/// Consume the next token if it matches the expected token, otherwise return an error
315-
fn consume_token(&mut self, expected: &Token) -> Result<bool, ParserError> {
306+
pub fn consume_token(&mut self, expected: &Token) -> Result<bool, ParserError> {
316307
match self.peek_token() {
317308
Some(ref t) => if *t == *expected {
318309
self.next_token();
@@ -329,7 +320,7 @@ impl Parser {
329320
}
330321

331322
/// Parse a SQL CREATE statement
332-
fn parse_create(&mut self) -> Result<ASTNode, ParserError> {
323+
pub fn parse_create(&mut self) -> Result<ASTNode, ParserError> {
333324
if self.parse_keywords(vec!["TABLE"]) {
334325
match self.next_token() {
335326
Some(Token::Identifier(id)) => {
@@ -398,7 +389,7 @@ impl Parser {
398389
}
399390

400391
/// Parse a literal integer/long
401-
fn parse_literal_int(&mut self) -> Result<i64, ParserError> {
392+
pub fn parse_literal_int(&mut self) -> Result<i64, ParserError> {
402393
match self.next_token() {
403394
Some(Token::Number(s)) => s.parse::<i64>().map_err(|e| {
404395
ParserError::ParserError(format!("Could not parse '{}' as i64: {}", s, e))
@@ -408,19 +399,19 @@ impl Parser {
408399
}
409400

410401
/// Parse a literal string
411-
// fn parse_literal_string(&mut self) -> Result<String, ParserError> {
412-
// match self.next_token() {
413-
// Some(Token::String(ref s)) => Ok(s.clone()),
414-
// other => parser_err!(format!("Expected literal string, found {:?}", other)),
415-
// }
416-
// }
402+
pub fn parse_literal_string(&mut self) -> Result<String, ParserError> {
403+
match self.next_token() {
404+
Some(Token::String(ref s)) => Ok(s.clone()),
405+
other => parser_err!(format!("Expected literal string, found {:?}", other)),
406+
}
407+
}
417408

418409
/// Parse a SQL datatype (in the context of a CREATE TABLE statement for example)
419-
fn parse_data_type(&mut self) -> Result<SQLType, ParserError> {
410+
pub fn parse_data_type(&mut self) -> Result<SQLType, ParserError> {
420411
match self.next_token() {
421412
Some(Token::Keyword(k)) => match k.to_uppercase().as_ref() {
422413
"BOOLEAN" => Ok(SQLType::Boolean),
423-
"FLOAT" => Ok(SQLType::Float(self.parse_precision()?)),
414+
"FLOAT" => Ok(SQLType::Float(self.parse_optional_precision()?)),
424415
"REAL" => Ok(SQLType::Real),
425416
"DOUBLE" => Ok(SQLType::Double),
426417
"SMALLINT" => Ok(SQLType::SmallInt),
@@ -433,12 +424,12 @@ impl Parser {
433424
}
434425
}
435426

436-
fn parse_precision(&mut self) -> Result<usize, ParserError> {
427+
pub fn parse_precision(&mut self) -> Result<usize, ParserError> {
437428
//TODO: error handling
438429
Ok(self.parse_optional_precision()?.unwrap())
439430
}
440431

441-
fn parse_optional_precision(&mut self) -> Result<Option<usize>, ParserError> {
432+
pub fn parse_optional_precision(&mut self) -> Result<Option<usize>, ParserError> {
442433
if self.consume_token(&Token::LParen)? {
443434
let n = self.parse_literal_int()?;
444435
//TODO: check return value of reading rparen
@@ -450,7 +441,7 @@ impl Parser {
450441
}
451442

452443
/// Parse a SELECT statement
453-
fn parse_select(&mut self) -> Result<ASTNode, ParserError> {
444+
pub fn parse_select(&mut self) -> Result<ASTNode, ParserError> {
454445
let projection = self.parse_expr_list()?;
455446

456447
let relation: Option<Box<ASTNode>> = if self.parse_keyword("FROM") {
@@ -509,7 +500,7 @@ impl Parser {
509500
}
510501

511502
/// Parse a comma-delimited list of SQL expressions
512-
fn parse_expr_list(&mut self) -> Result<Vec<ASTNode>, ParserError> {
503+
pub fn parse_expr_list(&mut self) -> Result<Vec<ASTNode>, ParserError> {
513504
let mut expr_list: Vec<ASTNode> = vec![];
514505
loop {
515506
expr_list.push(self.parse_expr(0)?);
@@ -528,7 +519,7 @@ impl Parser {
528519
}
529520

530521
/// Parse a comma-delimited list of SQL ORDER BY expressions
531-
fn parse_order_by_expr_list(&mut self) -> Result<Vec<ASTNode>, ParserError> {
522+
pub fn parse_order_by_expr_list(&mut self) -> Result<Vec<ASTNode>, ParserError> {
532523
let mut expr_list: Vec<ASTNode> = vec![];
533524
loop {
534525
let expr = self.parse_expr(0)?;
@@ -575,7 +566,7 @@ impl Parser {
575566
}
576567

577568
/// Parse a LIMIT clause
578-
fn parse_limit(&mut self) -> Result<Option<Box<ASTNode>>, ParserError> {
569+
pub fn parse_limit(&mut self) -> Result<Option<Box<ASTNode>>, ParserError> {
579570
if self.parse_keyword("ALL") {
580571
Ok(None)
581572
} else {
@@ -845,6 +836,21 @@ mod tests {
845836
//TODO: assertions
846837
}
847838

839+
#[test]
840+
fn parse_literal_string() {
841+
let sql = "SELECT 'one'";
842+
match parse_sql(&sql) {
843+
ASTNode::SQLSelect { ref projection, .. } => {
844+
assert_eq!(
845+
projection[0],
846+
ASTNode::SQLLiteralString("one".to_string())
847+
);
848+
}
849+
_ => panic!(),
850+
}
851+
852+
}
853+
848854
#[test]
849855
fn parse_select_version() {
850856
let sql = "SELECT @@version";

0 commit comments

Comments
 (0)