Skip to content

Commit 63532aa

Browse files
committed
Don't lose precision when parsing decimal fractions
The SQL standard requires that numeric literals with a decimal point, like 1.23, are represented exactly, up to some precision. That means that parsing these literals into f64s is invalid, as it is impossible to represent many decimal numbers exactly in binary floating point (for example, 0.3). This commit parses all numeric literals into a new `Value` variant `Number(String)`, removing the old `Long(u64)` and `Double(f64)` variants. This is slightly less convenient for downstream consumers, but far more flexible, as numbers that do not fit into a u64 and f64 are now representable.
1 parent 391a54b commit 63532aa

File tree

6 files changed

+86
-84
lines changed

6 files changed

+86
-84
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ path = "src/lib.rs"
2020

2121
[dependencies]
2222
log = "0.4.5"
23-
ordered-float = "1.0.2"
2423

2524
[dev-dependencies]
2625
simple_logger = "1.0.1"

src/ast/query.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ pub struct Query {
2323
/// ORDER BY
2424
pub order_by: Vec<OrderByExpr>,
2525
/// `LIMIT { <N> | ALL }`
26-
pub limit: Option<Expr>,
26+
pub limit: Option<u64>,
2727
/// `OFFSET <N> { ROW | ROWS }`
28-
pub offset: Option<Expr>,
28+
pub offset: Option<u64>,
2929
/// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
3030
pub fetch: Option<Fetch>,
3131
}

src/ast/value.rs

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

13-
use ordered_float::OrderedFloat;
1413
use std::fmt;
1514

1615
/// Primitive SQL values such as number and string
1716
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1817
pub enum Value {
19-
/// Unsigned integer value
20-
Long(u64),
21-
/// Unsigned floating point value
22-
Double(OrderedFloat<f64>),
18+
/// Numeric literal
19+
Number(String),
2320
/// 'string value'
2421
SingleQuotedString(String),
2522
/// N'string value'
@@ -60,8 +57,7 @@ pub enum Value {
6057
impl fmt::Display for Value {
6158
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6259
match self {
63-
Value::Long(v) => write!(f, "{}", v),
64-
Value::Double(v) => write!(f, "{}", v),
60+
Value::Number(v) => write!(f, "{}", v),
6561
Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
6662
Value::NationalStringLiteral(v) => write!(f, "N'{}'", v),
6763
Value::HexStringLiteral(v) => write!(f, "X'{}'", v),

src/parser.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,14 +1176,7 @@ impl Parser {
11761176
return parser_err!(format!("No value parser for keyword {}", k.keyword));
11771177
}
11781178
},
1179-
Token::Number(ref n) if n.contains('.') => match n.parse::<f64>() {
1180-
Ok(n) => Ok(Value::Double(n.into())),
1181-
Err(e) => parser_err!(format!("Could not parse '{}' as f64: {}", n, e)),
1182-
},
1183-
Token::Number(ref n) => match n.parse::<u64>() {
1184-
Ok(n) => Ok(Value::Long(n)),
1185-
Err(e) => parser_err!(format!("Could not parse '{}' as u64: {}", n, e)),
1186-
},
1179+
Token::Number(ref n) => Ok(Value::Number(n.to_string())),
11871180
Token::SingleQuotedString(ref s) => Ok(Value::SingleQuotedString(s.to_string())),
11881181
Token::NationalStringLiteral(ref s) => {
11891182
Ok(Value::NationalStringLiteral(s.to_string()))
@@ -1854,20 +1847,17 @@ impl Parser {
18541847
}
18551848

18561849
/// Parse a LIMIT clause
1857-
pub fn parse_limit(&mut self) -> Result<Option<Expr>, ParserError> {
1850+
pub fn parse_limit(&mut self) -> Result<Option<u64>, ParserError> {
18581851
if self.parse_keyword("ALL") {
18591852
Ok(None)
18601853
} else {
1861-
self.parse_literal_uint()
1862-
.map(|n| Some(Expr::Value(Value::Long(n))))
1854+
Ok(Some(self.parse_literal_uint()?))
18631855
}
18641856
}
18651857

18661858
/// Parse an OFFSET clause
1867-
pub fn parse_offset(&mut self) -> Result<Expr, ParserError> {
1868-
let value = self
1869-
.parse_literal_uint()
1870-
.map(|n| Expr::Value(Value::Long(n)))?;
1859+
pub fn parse_offset(&mut self) -> Result<u64, ParserError> {
1860+
let value = self.parse_literal_uint()?;
18711861
self.expect_one_of_keywords(&["ROW", "ROWS"])?;
18721862
Ok(value)
18731863
}

0 commit comments

Comments
 (0)