Skip to content

Commit

Permalink
Return errors, not panic, when integers fail to parse in `AUTO_INCREM…
Browse files Browse the repository at this point in the history
…ENT` and `TOP` (#1305)
  • Loading branch information
eejbyfeldt committed Jun 18, 2024
1 parent 345e209 commit 79af31b
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 15 deletions.
40 changes: 25 additions & 15 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ use alloc::{
vec,
vec::Vec,
};
use core::fmt;
use core::{
fmt::{self, Display},
str::FromStr,
};

use log::debug;

Expand Down Expand Up @@ -3260,6 +3263,18 @@ impl<'a> Parser<'a> {
}
}

fn parse<T: FromStr>(s: String, loc: Location) -> Result<T, ParserError>
where
<T as FromStr>::Err: Display,
{
s.parse::<T>().map_err(|e| {
ParserError::ParserError(format!(
"Could not parse '{s}' as {}: {e}{loc}",
core::any::type_name::<T>()
))
})
}

/// Parse a comma-separated list of 1+ SelectItem
pub fn parse_projection(&mut self) -> Result<Vec<SelectItem>, ParserError> {
// BigQuery and Snowflake allow trailing commas, but only in project lists
Expand Down Expand Up @@ -5281,7 +5296,7 @@ impl<'a> Parser<'a> {
let _ = self.consume_token(&Token::Eq);
let next_token = self.next_token();
match next_token.token {
Token::Number(s, _) => Some(s.parse::<u32>().expect("literal int")),
Token::Number(s, _) => Some(Self::parse::<u32>(s, next_token.location)?),
_ => self.expected("literal int", next_token)?,
}
} else {
Expand Down Expand Up @@ -6725,10 +6740,7 @@ impl<'a> Parser<'a> {
// The call to n.parse() returns a bigdecimal when the
// bigdecimal feature is enabled, and is otherwise a no-op
// (i.e., it returns the input string).
Token::Number(ref n, l) => match n.parse() {
Ok(n) => Ok(Value::Number(n, l)),
Err(e) => parser_err!(format!("Could not parse '{n}' as number: {e}"), location),
},
Token::Number(n, l) => Ok(Value::Number(Self::parse(n, location)?, l)),
Token::SingleQuotedString(ref s) => Ok(Value::SingleQuotedString(s.to_string())),
Token::DoubleQuotedString(ref s) => Ok(Value::DoubleQuotedString(s.to_string())),
Token::TripleSingleQuotedString(ref s) => {
Expand Down Expand Up @@ -6820,9 +6832,7 @@ impl<'a> Parser<'a> {
pub fn parse_literal_uint(&mut self) -> Result<u64, ParserError> {
let next_token = self.next_token();
match next_token.token {
Token::Number(s, _) => s.parse::<u64>().map_err(|e| {
ParserError::ParserError(format!("Could not parse '{s}' as u64: {e}"))
}),
Token::Number(s, _) => Self::parse::<u64>(s, next_token.location),
_ => self.expected("literal int", next_token),
}
}
Expand Down Expand Up @@ -9273,20 +9283,20 @@ impl<'a> Parser<'a> {
return self.expected("literal number", next_token);
};
self.expect_token(&Token::RBrace)?;
RepetitionQuantifier::AtMost(n.parse().expect("literal int"))
RepetitionQuantifier::AtMost(Self::parse(n, token.location)?)
}
Token::Number(n, _) if self.consume_token(&Token::Comma) => {
let next_token = self.next_token();
match next_token.token {
Token::Number(m, _) => {
self.expect_token(&Token::RBrace)?;
RepetitionQuantifier::Range(
n.parse().expect("literal int"),
m.parse().expect("literal int"),
Self::parse(n, token.location)?,
Self::parse(m, token.location)?,
)
}
Token::RBrace => {
RepetitionQuantifier::AtLeast(n.parse().expect("literal int"))
RepetitionQuantifier::AtLeast(Self::parse(n, token.location)?)
}
_ => {
return self.expected("} or upper bound", next_token);
Expand All @@ -9295,7 +9305,7 @@ impl<'a> Parser<'a> {
}
Token::Number(n, _) => {
self.expect_token(&Token::RBrace)?;
RepetitionQuantifier::Exactly(n.parse().expect("literal int"))
RepetitionQuantifier::Exactly(Self::parse(n, token.location)?)
}
_ => return self.expected("quantifier range", token),
}
Expand Down Expand Up @@ -10329,7 +10339,7 @@ impl<'a> Parser<'a> {
} else {
let next_token = self.next_token();
let quantity = match next_token.token {
Token::Number(s, _) => s.parse::<u64>().expect("literal int"),
Token::Number(s, _) => Self::parse::<u64>(s, next_token.location)?,
_ => self.expected("literal int", next_token)?,
};
Some(TopQuantity::Constant(quantity))
Expand Down
15 changes: 15 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10006,3 +10006,18 @@ fn parse_select_wildcard_with_except() {
"sql parser error: Expected identifier, found: )"
);
}

#[test]
fn parse_auto_increment_too_large() {
let dialect = GenericDialect {};
let u64_max = u64::MAX;
let sql =
format!("CREATE TABLE foo (bar INT NOT NULL AUTO_INCREMENT) AUTO_INCREMENT=1{u64_max}");

let res = Parser::new(&dialect)
.try_with_sql(&sql)
.expect("tokenize to work")
.parse_statements();

assert!(res.is_err(), "{res:?}");
}

0 comments on commit 79af31b

Please sign in to comment.