Skip to content

Commit 436240d

Browse files
author
Sean Loiselle
authored
Merge pull request #1407 from sploiselle/parse-numbers-begin-decimal
parse decimals without leading integer, e.g. .1
2 parents 01fbf4f + 8dca4df commit 436240d

File tree

3 files changed

+70
-33
lines changed

3 files changed

+70
-33
lines changed

src/sql-parser/src/tokenizer.rs

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -394,38 +394,7 @@ impl<'a> Tokenizer<'a> {
394394
}
395395
}
396396
// numbers
397-
'0'..='9' => {
398-
let mut seen_decimal = false;
399-
let mut s = peeking_take_while(chars, |ch| match ch {
400-
'0'..='9' => true,
401-
'.' if !seen_decimal => {
402-
seen_decimal = true;
403-
true
404-
}
405-
_ => false,
406-
});
407-
// If in e-notation, parse the e-notation with special care given to negative exponents.
408-
match chars.peek() {
409-
Some('e') | Some('E') => {
410-
s.push('E');
411-
// Consume the e-notation signifier.
412-
chars.next();
413-
if let Some('-') = chars.peek() {
414-
s.push('-');
415-
// Consume the negative sign.
416-
chars.next();
417-
}
418-
let e = peeking_take_while(chars, |ch| match ch {
419-
'0'..='9' => true,
420-
_ => false,
421-
});
422-
s.push_str(&e);
423-
}
424-
_ => {}
425-
}
426-
427-
Ok(Some(Token::Number(s)))
428-
}
397+
'0'..='9' => self.tokenize_number(chars, false),
429398
// punctuation
430399
'(' => self.consume_and_return(chars, Token::LParen),
431400
')' => self.consume_and_return(chars, Token::RParen),
@@ -518,7 +487,13 @@ impl<'a> Tokenizer<'a> {
518487
}
519488
}
520489
'=' => self.consume_and_return(chars, Token::Eq),
521-
'.' => self.consume_and_return(chars, Token::Period),
490+
'.' => {
491+
chars.next(); // consume '.'
492+
match chars.peek() {
493+
Some('0'..='9') => self.tokenize_number(chars, true),
494+
_ => Ok(Some(Token::Period)),
495+
}
496+
}
522497
'!' => {
523498
chars.next(); // consume
524499
match chars.peek() {
@@ -660,6 +635,49 @@ impl<'a> Tokenizer<'a> {
660635
Ok(Some(Token::Parameter(n)))
661636
}
662637

638+
fn tokenize_number(
639+
&self,
640+
chars: &mut Peekable<Chars<'_>>,
641+
seen_decimal: bool,
642+
) -> Result<Option<Token>, TokenizerError> {
643+
let mut seen_decimal = seen_decimal;
644+
let mut s = if seen_decimal {
645+
".".to_string()
646+
} else {
647+
String::default()
648+
};
649+
650+
s.push_str(&peeking_take_while(chars, |ch| match ch {
651+
'0'..='9' => true,
652+
'.' if !seen_decimal => {
653+
seen_decimal = true;
654+
true
655+
}
656+
_ => false,
657+
}));
658+
// If in e-notation, parse the e-notation with special care given to negative exponents.
659+
match chars.peek() {
660+
Some('e') | Some('E') => {
661+
s.push('E');
662+
// Consume the e-notation signifier.
663+
chars.next();
664+
if let Some('-') = chars.peek() {
665+
s.push('-');
666+
// Consume the negative sign.
667+
chars.next();
668+
}
669+
let e = peeking_take_while(chars, |ch| match ch {
670+
'0'..='9' => true,
671+
_ => false,
672+
});
673+
s.push_str(&e);
674+
}
675+
_ => {}
676+
}
677+
678+
Ok(Some(Token::Number(s)))
679+
}
680+
663681
fn consume_and_return(
664682
&self,
665683
chars: &mut Peekable<Chars<'_>>,

src/sql-parser/tests/sqlparser_common.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,12 @@ fn parse_number() {
485485
assert_eq!(expr, Expr::Value(Value::Number("1.0".into())));
486486
}
487487

488+
#[test]
489+
fn parse_numeric_begin_with_decimal() {
490+
let expr = verified_expr(".1");
491+
assert_eq!(expr, Expr::Value(Value::Number(".1".into())));
492+
}
493+
488494
#[test]
489495
fn parse_approximate_numeric_literal() {
490496
let expr = verified_expr("1.0E2");

test/decimal.slt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,16 @@ query R
294294
SELECT CAST (null::float AS decimal(38, 7))
295295
----
296296
NULL
297+
298+
### No leading integer ###
299+
300+
query R
301+
SELECT .123
302+
----
303+
0.123
304+
305+
statement error
306+
SELECT ..123
307+
308+
statement error
309+
SELECT .1.23

0 commit comments

Comments
 (0)