Skip to content

Commit

Permalink
Optionally parse numbers into BigDecimals
Browse files Browse the repository at this point in the history
With `--features bigdecimal`, parse numbers into BigDecimals instead of
leaving them as strings.
  • Loading branch information
benesch committed Sep 1, 2019
1 parent b5621c0 commit a0aca82
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 57 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -49,6 +49,7 @@ script:
- travis-cargo clippy -- --all-targets --all-features -- -D warnings
- travis-cargo build
- travis-cargo test
- travis-cargo test -- all-features
- cargo +nightly fmt -- --check --config-path <(echo 'license_template_path = "HEADER"')

after_success:
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -19,6 +19,7 @@ name = "sqlparser"
path = "src/lib.rs"

[dependencies]
bigdecimal = { version = "0.1.0", optional = true }
log = "0.4.5"

[dev-dependencies]
Expand Down
5 changes: 5 additions & 0 deletions src/ast/value.rs
Expand Up @@ -10,13 +10,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#[cfg(feature = "bigdecimal")]
use bigdecimal::BigDecimal;
use std::fmt;

/// Primitive SQL values such as number and string
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Value {
/// Numeric literal
#[cfg(not(feature = "bigdecimal"))]
Number(String),
#[cfg(feature = "bigdecimal")]
Number(BigDecimal),
/// 'string value'
SingleQuotedString(String),
/// N'string value'
Expand Down
25 changes: 19 additions & 6 deletions src/parser.rs
Expand Up @@ -1183,7 +1183,13 @@ impl Parser {
return parser_err!(format!("No value parser for keyword {}", k.keyword));
}
},
Token::Number(ref n) => Ok(Value::Number(n.to_string())),
// 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) => match n.parse() {
Ok(n) => Ok(Value::Number(n)),
Err(e) => parser_err!(format!("Could not parse '{}' as number: {}", n, e)),
},
Token::SingleQuotedString(ref s) => Ok(Value::SingleQuotedString(s.to_string())),
Token::NationalStringLiteral(ref s) => {
Ok(Value::NationalStringLiteral(s.to_string()))
Expand All @@ -1195,6 +1201,16 @@ impl Parser {
}
}

pub fn parse_number_value(&mut self) -> Result<Value, ParserError> {
match self.parse_value()? {
v @ Value::Number(_) => Ok(v),
_ => {
self.prev_token();
self.expected("literal number", self.peek_token())
}
}
}

/// Parse an unsigned literal integer/long
pub fn parse_literal_uint(&mut self) -> Result<u64, ParserError> {
match self.next_token() {
Expand Down Expand Up @@ -1856,16 +1872,13 @@ impl Parser {
if self.parse_keyword("ALL") {
Ok(None)
} else {
self.parse_literal_uint()
.map(|n| Some(Expr::Value(Value::Number(n.to_string()))))
Ok(Some(Expr::Value(self.parse_number_value()?)))
}
}

/// Parse an OFFSET clause
pub fn parse_offset(&mut self) -> Result<Expr, ParserError> {
let value = self
.parse_literal_uint()
.map(|n| Expr::Value(Value::Number(n.to_string())))?;
let value = Expr::Value(self.parse_number_value()?);
self.expect_one_of_keywords(&["ROW", "ROWS"])?;
Ok(value)
}
Expand Down
4 changes: 4 additions & 0 deletions src/test_utils.rs
Expand Up @@ -136,3 +136,7 @@ pub fn expr_from_projection(item: &SelectItem) -> &Expr {
_ => panic!("Expected UnnamedExpr"),
}
}

pub fn number(n: &'static str) -> Value {
Value::Number(n.parse().unwrap())
}

0 comments on commit a0aca82

Please sign in to comment.