Skip to content

Commit 09b1a28

Browse files
committed
Optionally parse numbers into BigDecimals
With `--features bigdecimal`, parse numbers into BigDecimals instead of leaving them as strings.
1 parent 63532aa commit 09b1a28

File tree

6 files changed

+65
-38
lines changed

6 files changed

+65
-38
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ name = "sqlparser"
1919
path = "src/lib.rs"
2020

2121
[dependencies]
22+
bigdecimal = { version = "0.1.0", optional = true }
2223
log = "0.4.5"
2324

2425
[dev-dependencies]

src/ast/value.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@
1010
// See the License for the specific language governing permissions and
1111
// limitations under the License.
1212

13+
#[cfg(feature = "bigdecimal")]
14+
use bigdecimal::BigDecimal;
1315
use std::fmt;
1416

1517
/// Primitive SQL values such as number and string
1618
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1719
pub enum Value {
1820
/// Numeric literal
21+
#[cfg(not(feature = "bigdecimal"))]
1922
Number(String),
23+
#[cfg(feature = "bigdecimal")]
24+
Number(BigDecimal),
2025
/// 'string value'
2126
SingleQuotedString(String),
2227
/// N'string value'

src/parser.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,10 @@ impl Parser {
11761176
return parser_err!(format!("No value parser for keyword {}", k.keyword));
11771177
}
11781178
},
1179-
Token::Number(ref n) => Ok(Value::Number(n.to_string())),
1179+
Token::Number(ref n) => match n.parse() {
1180+
Ok(n) => Ok(Value::Number(n)),
1181+
Err(e) => parser_err!(format!("Could not parse '{}' as number: {}", n, e)),
1182+
},
11801183
Token::SingleQuotedString(ref s) => Ok(Value::SingleQuotedString(s.to_string())),
11811184
Token::NationalStringLiteral(ref s) => {
11821185
Ok(Value::NationalStringLiteral(s.to_string()))

src/test_utils.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,7 @@ pub fn expr_from_projection(item: &SelectItem) -> &Expr {
136136
_ => panic!("Expected UnnamedExpr"),
137137
}
138138
}
139+
140+
pub fn number(n: &'static str) -> Value {
141+
Value::Number(n.parse().unwrap())
142+
}

tests/sqlparser_common.rs

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ use matches::assert_matches;
2222

2323
use sqlparser::ast::*;
2424
use sqlparser::parser::*;
25-
use sqlparser::test_utils::{all_dialects, expr_from_projection, only};
25+
use sqlparser::test_utils::{all_dialects, expr_from_projection, number, only};
2626

2727
#[test]
2828
fn parse_insert_values() {
2929
let row = vec![
30-
Expr::Value(Value::Number("1".into())),
31-
Expr::Value(Value::Number("2".into())),
32-
Expr::Value(Value::Number("3".into())),
30+
Expr::Value(number("1")),
31+
Expr::Value(number("2")),
32+
Expr::Value(number("3")),
3333
];
3434
let rows1 = vec![row.clone()];
3535
let rows2 = vec![row.clone(), row];
@@ -107,15 +107,15 @@ fn parse_update() {
107107
vec![
108108
Assignment {
109109
id: "a".into(),
110-
value: Expr::Value(Value::Number("1".into())),
110+
value: Expr::Value(number("1")),
111111
},
112112
Assignment {
113113
id: "b".into(),
114-
value: Expr::Value(Value::Number("2".into())),
114+
value: Expr::Value(number("2")),
115115
},
116116
Assignment {
117117
id: "c".into(),
118-
value: Expr::Value(Value::Number("3".into())),
118+
value: Expr::Value(number("3")),
119119
},
120120
]
121121
);
@@ -181,7 +181,7 @@ fn parse_where_delete_statement() {
181181
Expr::BinaryOp {
182182
left: Box::new(Expr::Identifier("name".to_string())),
183183
op: Eq,
184-
right: Box::new(Expr::Value(Value::Number("5".into()))),
184+
right: Box::new(Expr::Value(number("5"))),
185185
},
186186
selection.unwrap(),
187187
);
@@ -286,7 +286,7 @@ fn parse_column_aliases() {
286286
} = only(&select.projection)
287287
{
288288
assert_eq!(&BinaryOperator::Plus, op);
289-
assert_eq!(&Expr::Value(Value::Number("1".into())), right.as_ref());
289+
assert_eq!(&Expr::Value(number("1")), right.as_ref());
290290
assert_eq!("newname", alias);
291291
} else {
292292
panic!("Expected ExprWithAlias")
@@ -426,6 +426,20 @@ fn parse_escaped_single_quote_string_predicate() {
426426
);
427427
}
428428

429+
#[test]
430+
fn parse_number() {
431+
let expr = verified_expr("1.0");
432+
433+
#[cfg(feature = "bigdecimal")]
434+
assert_eq!(
435+
expr,
436+
Expr::Value(Value::Number(bigdecimal::BigDecimal::from(1)))
437+
);
438+
439+
#[cfg(not(feature = "bigdecimal"))]
440+
assert_eq!(expr, Expr::Value(Value::Number("1.0".into())));
441+
}
442+
429443
#[test]
430444
fn parse_compound_expr_1() {
431445
use self::BinaryOperator::*;
@@ -527,9 +541,9 @@ fn parse_not_precedence() {
527541
Expr::UnaryOp {
528542
op: UnaryOperator::Not,
529543
expr: Box::new(Expr::Between {
530-
expr: Box::new(Expr::Value(Value::Number("1".into()))),
531-
low: Box::new(Expr::Value(Value::Number("1".into()))),
532-
high: Box::new(Expr::Value(Value::Number("2".into()))),
544+
expr: Box::new(Expr::Value(number("1"))),
545+
low: Box::new(Expr::Value(number("1"))),
546+
high: Box::new(Expr::Value(number("2"))),
533547
negated: true,
534548
}),
535549
},
@@ -658,8 +672,8 @@ fn parse_between() {
658672
assert_eq!(
659673
Expr::Between {
660674
expr: Box::new(Expr::Identifier("age".to_string())),
661-
low: Box::new(Expr::Value(Value::Number("25".into()))),
662-
high: Box::new(Expr::Value(Value::Number("32".into()))),
675+
low: Box::new(Expr::Value(number("25"))),
676+
high: Box::new(Expr::Value(number("32"))),
663677
negated,
664678
},
665679
select.selection.unwrap()
@@ -676,16 +690,16 @@ fn parse_between_with_expr() {
676690
let select = verified_only_select(sql);
677691
assert_eq!(
678692
Expr::IsNull(Box::new(Expr::Between {
679-
expr: Box::new(Expr::Value(Value::Number("1".into()))),
693+
expr: Box::new(Expr::Value(number("1"))),
680694
low: Box::new(Expr::BinaryOp {
681-
left: Box::new(Expr::Value(Value::Number("1".into()))),
695+
left: Box::new(Expr::Value(number("1"))),
682696
op: Plus,
683-
right: Box::new(Expr::Value(Value::Number("2".into()))),
697+
right: Box::new(Expr::Value(number("2"))),
684698
}),
685699
high: Box::new(Expr::BinaryOp {
686-
left: Box::new(Expr::Value(Value::Number("3".into()))),
700+
left: Box::new(Expr::Value(number("3"))),
687701
op: Plus,
688-
right: Box::new(Expr::Value(Value::Number("4".into()))),
702+
right: Box::new(Expr::Value(number("4"))),
689703
}),
690704
negated: false,
691705
})),
@@ -697,19 +711,19 @@ fn parse_between_with_expr() {
697711
assert_eq!(
698712
Expr::BinaryOp {
699713
left: Box::new(Expr::BinaryOp {
700-
left: Box::new(Expr::Value(Value::Number("1".into()))),
714+
left: Box::new(Expr::Value(number("1"))),
701715
op: BinaryOperator::Eq,
702-
right: Box::new(Expr::Value(Value::Number("1".into()))),
716+
right: Box::new(Expr::Value(number("1"))),
703717
}),
704718
op: BinaryOperator::And,
705719
right: Box::new(Expr::Between {
706720
expr: Box::new(Expr::BinaryOp {
707-
left: Box::new(Expr::Value(Value::Number("1".into()))),
721+
left: Box::new(Expr::Value(number("1"))),
708722
op: BinaryOperator::Plus,
709723
right: Box::new(Expr::Identifier("x".to_string())),
710724
}),
711-
low: Box::new(Expr::Value(Value::Number("1".into()))),
712-
high: Box::new(Expr::Value(Value::Number("2".into()))),
725+
low: Box::new(Expr::Value(number("1"))),
726+
high: Box::new(Expr::Value(number("2"))),
713727
negated: false,
714728
}),
715729
},
@@ -792,7 +806,7 @@ fn parse_select_having() {
792806
distinct: false
793807
})),
794808
op: BinaryOperator::Gt,
795-
right: Box::new(Expr::Value(Value::Number("1".into())))
809+
right: Box::new(Expr::Value(number("1")))
796810
}),
797811
select.having
798812
);
@@ -988,7 +1002,7 @@ fn parse_create_table_with_options() {
9881002
},
9891003
SqlOption {
9901004
name: "a".into(),
991-
value: Value::Number("123".into())
1005+
value: number("123")
9921006
},
9931007
],
9941008
with_options
@@ -1186,11 +1200,11 @@ fn parse_literal_decimal() {
11861200
let select = verified_only_select(sql);
11871201
assert_eq!(2, select.projection.len());
11881202
assert_eq!(
1189-
&Expr::Value(Value::Number("0.300000000000000004".into())),
1203+
&Expr::Value(number("0.300000000000000004")),
11901204
expr_from_projection(&select.projection[0]),
11911205
);
11921206
assert_eq!(
1193-
&Expr::Value(Value::Number("9007199254740993.0".into())),
1207+
&Expr::Value(number("9007199254740993.0")),
11941208
expr_from_projection(&select.projection[1]),
11951209
)
11961210
}
@@ -1438,12 +1452,12 @@ fn parse_searched_case_expr() {
14381452
BinaryOp {
14391453
left: Box::new(Identifier("bar".to_string())),
14401454
op: Eq,
1441-
right: Box::new(Expr::Value(Value::Number("0".into())))
1455+
right: Box::new(Expr::Value(number("0")))
14421456
},
14431457
BinaryOp {
14441458
left: Box::new(Identifier("bar".to_string())),
14451459
op: GtEq,
1446-
right: Box::new(Expr::Value(Value::Number("0".into())))
1460+
right: Box::new(Expr::Value(number("0")))
14471461
}
14481462
],
14491463
results: vec![
@@ -1468,7 +1482,7 @@ fn parse_simple_case_expr() {
14681482
assert_eq!(
14691483
&Case {
14701484
operand: Some(Box::new(Identifier("foo".to_string()))),
1471-
conditions: vec![Expr::Value(Value::Number("1".into()))],
1485+
conditions: vec![Expr::Value(number("1"))],
14721486
results: vec![Expr::Value(Value::SingleQuotedString("Y".to_string())),],
14731487
else_result: Some(Box::new(Expr::Value(Value::SingleQuotedString(
14741488
"N".to_string()
@@ -2080,7 +2094,7 @@ fn parse_create_view_with_options() {
20802094
},
20812095
SqlOption {
20822096
name: "a".into(),
2083-
value: Value::Number("123".into())
2097+
value: number("123")
20842098
},
20852099
],
20862100
with_options
@@ -2249,7 +2263,7 @@ fn parse_fetch() {
22492263
let fetch_first_two_rows_only = Some(Fetch {
22502264
with_ties: false,
22512265
percent: false,
2252-
quantity: Some(Expr::Value(Value::Number("2".into()))),
2266+
quantity: Some(Expr::Value(number("2"))),
22532267
});
22542268
let ast = verified_query("SELECT foo FROM bar FETCH FIRST 2 ROWS ONLY");
22552269
assert_eq!(ast.fetch, fetch_first_two_rows_only);
@@ -2276,7 +2290,7 @@ fn parse_fetch() {
22762290
Some(Fetch {
22772291
with_ties: true,
22782292
percent: false,
2279-
quantity: Some(Expr::Value(Value::Number("2".into()))),
2293+
quantity: Some(Expr::Value(number("2"))),
22802294
})
22812295
);
22822296
let ast = verified_query("SELECT foo FROM bar FETCH FIRST 50 PERCENT ROWS ONLY");
@@ -2285,7 +2299,7 @@ fn parse_fetch() {
22852299
Some(Fetch {
22862300
with_ties: false,
22872301
percent: true,
2288-
quantity: Some(Expr::Value(Value::Number("50".into()))),
2302+
quantity: Some(Expr::Value(number("50"))),
22892303
})
22902304
);
22912305
let ast = verified_query(

tests/sqlparser_postgres.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,15 @@ fn parse_create_table_with_defaults() {
163163
vec![
164164
SqlOption {
165165
name: "fillfactor".into(),
166-
value: Value::Number("20".into())
166+
value: number("20")
167167
},
168168
SqlOption {
169169
name: "user_catalog_table".into(),
170170
value: Value::Boolean(true)
171171
},
172172
SqlOption {
173173
name: "autovacuum_vacuum_threshold".into(),
174-
value: Value::Number("100".into())
174+
value: number("100")
175175
},
176176
]
177177
);

0 commit comments

Comments
 (0)