Skip to content

Commit 3b13e15

Browse files
committed
Fix parse_time() handling of fractional seconds
There's no Token::Period in such situation, so fractional part (from sec) was silently truncated. Can't uncomment the test yet, because parse_timestamp() is effectively unused: the code added to parse_value() in 5abd9e7 was wrong as it attempted to handle unquoted date/time literals. One part of it was commented out earlier, the other can't work as far as I can see, as it tries to parse a Number token - `([0-9]|\.)+` - as a timestamp, so I removed it as well.
1 parent 52277c3 commit 3b13e15

File tree

2 files changed

+18
-35
lines changed

2 files changed

+18
-35
lines changed

src/sqlparser.rs

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -682,30 +682,13 @@ impl Parser {
682682
"NULL" => Ok(Value::Null),
683683
_ => return parser_err!(format!("No value parser for keyword {}", k)),
684684
},
685-
//TODO: parse the timestamp here
685+
//TODO: parse the timestamp here (see parse_timestamp_value())
686686
Token::Number(ref n) if n.contains(".") => match n.parse::<f64>() {
687687
Ok(n) => Ok(Value::Double(n)),
688-
Err(e) => {
689-
let index = self.index;
690-
self.prev_token();
691-
if let Ok(timestamp) = self.parse_timestamp_value() {
692-
println!("timstamp: {:?}", timestamp);
693-
Ok(timestamp)
694-
} else {
695-
self.index = index;
696-
parser_err!(format!("Could not parse '{}' as i64: {}", n, e))
697-
}
698-
}
688+
Err(e) => parser_err!(format!("Could not parse '{}' as i64: {}", n, e)),
699689
},
700690
Token::Number(ref n) => match n.parse::<i64>() {
701-
Ok(n) => {
702-
// if let Some(Token::Minus) = self.peek_token() {
703-
// self.prev_token();
704-
// self.parse_timestamp_value()
705-
// } else {
706-
Ok(Value::Long(n))
707-
// }
708-
}
691+
Ok(n) => Ok(Value::Long(n)),
709692
Err(e) => parser_err!(format!("Could not parse '{}' as i64: {}", n, e)),
710693
},
711694
Token::Identifier(id) => Ok(Value::String(id.to_string())),
@@ -733,13 +716,13 @@ impl Parser {
733716
}
734717
}
735718

736-
/// Parse a literal integer/long
719+
/// Parse a literal double
737720
pub fn parse_literal_double(&mut self) -> Result<f64, ParserError> {
738721
match self.next_token() {
739722
Some(Token::Number(s)) => s.parse::<f64>().map_err(|e| {
740-
ParserError::ParserError(format!("Could not parse '{}' as i64: {}", s, e))
723+
ParserError::ParserError(format!("Could not parse '{}' as f64: {}", s, e))
741724
}),
742-
other => parser_err!(format!("Expected literal int, found {:?}", other)),
725+
other => parser_err!(format!("Expected literal number, found {:?}", other)),
743726
}
744727
}
745728

@@ -820,19 +803,17 @@ impl Parser {
820803
self.consume_token(&Token::Colon)?;
821804
let min = self.parse_literal_int()?;
822805
self.consume_token(&Token::Colon)?;
806+
// On one hand, the SQL specs defines <seconds fraction> ::= <unsigned integer>,
807+
// so it would be more correct to parse it as such
823808
let sec = self.parse_literal_double()?;
824-
let _ = (sec.fract() * 1000.0).round();
825-
if let Ok(true) = self.consume_token(&Token::Period) {
826-
let ms = self.parse_literal_int()?;
827-
Ok(NaiveTime::from_hms_milli(
828-
hour as u32,
829-
min as u32,
830-
sec as u32,
831-
ms as u32,
832-
))
833-
} else {
834-
Ok(NaiveTime::from_hms(hour as u32, min as u32, sec as u32))
835-
}
809+
// On the other, chrono only supports nanoseconds, which should(?) fit in seconds-as-f64...
810+
let nanos = (sec.fract() * 1_000_000_000.0).round();
811+
Ok(NaiveTime::from_hms_nano(
812+
hour as u32,
813+
min as u32,
814+
sec as u32,
815+
nanos as u32,
816+
))
836817
}
837818

838819
/// Parse a SQL datatype (in the context of a CREATE TABLE statement for example)

tests/sqlparser_postgres.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,13 +657,15 @@ fn parse_timestamps_example() {
657657
let sql = "2016-02-15 09:43:33";
658658
let _ = parse_sql(sql);
659659
//TODO add assertion
660+
//assert_eq!(sql, ast.to_string());
660661
}
661662

662663
#[test]
663664
fn parse_timestamps_with_millis_example() {
664665
let sql = "2017-11-02 19:15:42.308637";
665666
let _ = parse_sql(sql);
666667
//TODO add assertion
668+
//assert_eq!(sql, ast.to_string());
667669
}
668670

669671
#[test]

0 commit comments

Comments
 (0)