@@ -22,7 +22,7 @@ use super::tokenizer::*;
2222use std:: error:: Error ;
2323use std:: fmt;
2424
25- use crate :: ast:: ParsedDate ;
25+ use crate :: ast:: { ParsedDate , ParsedTimestamp } ;
2626
2727// Use `Parser::expected` instead, if possible
2828macro_rules! parser_err {
@@ -212,7 +212,7 @@ impl Parser {
212212 expr : Box :: new ( self . parse_subexpr ( Self :: UNARY_NOT_PREC ) ?) ,
213213 } ) ,
214214 "TIME" => Ok ( Expr :: Value ( Value :: Time ( self . parse_literal_string ( ) ?) ) ) ,
215- "TIMESTAMP" => Ok ( Expr :: Value ( Value :: Timestamp ( self . parse_literal_string ( ) ?) ) ) ,
215+ "TIMESTAMP" => Ok ( Expr :: Value ( self . parse_timestamp ( ) ?) ) ,
216216 // Here `w` is a word, check if it's a part of a multi-part
217217 // identifier, a function call, or a simple identifier:
218218 _ => match self . peek_token ( ) {
@@ -504,6 +504,73 @@ impl Parser {
504504 }
505505 }
506506
507+ fn parse_timestamp ( & mut self ) -> Result < Value , ParserError > {
508+ use std:: convert:: TryInto ;
509+
510+ let value = self . parse_literal_string ( ) ?;
511+ let pdt = Self :: parse_interval_string ( & value, & DateTimeField :: Year ) ?;
512+
513+ match (
514+ pdt. year , pdt. month , pdt. day , pdt. hour , pdt. minute , pdt. second , pdt. nano ,
515+ ) {
516+ ( Some ( year) , Some ( month) , Some ( day) , Some ( hour) , Some ( minute) , Some ( second) , nano) => {
517+ let p_err = |e : std:: num:: TryFromIntError , field : & str | {
518+ ParserError :: ParserError ( format ! (
519+ "{} in date '{}' is invalid: {}" ,
520+ field, value, e
521+ ) )
522+ } ;
523+
524+ // type inference with try_into() fails so we need to mutate it negative
525+ let mut year: i64 = year. try_into ( ) . map_err ( |e| p_err ( e, "Year" ) ) ?;
526+ year *= pdt. positivity ( ) ;
527+ if month > 12 || month == 0 {
528+ return parser_err ! (
529+ "Month in date '{}' must be a number between 1 and 12, got: {}" ,
530+ value,
531+ month
532+ ) ;
533+ }
534+ let month: u8 = month. try_into ( ) . expect ( "invalid month" ) ;
535+ if month == 0 {
536+ parser_err ! ( "Month in timestamp '{}' cannot be zero: {}" , value, day) ?;
537+ }
538+ let day: u8 = day. try_into ( ) . map_err ( |e| p_err ( e, "Day" ) ) ?;
539+ if day == 0 {
540+ parser_err ! ( "Day in timestamp '{}' cannot be zero: {}" , value, day) ?;
541+ }
542+ let hour: u8 = hour. try_into ( ) . map_err ( |e| p_err ( e, "Hour" ) ) ?;
543+ if hour > 23 {
544+ parser_err ! ( "Hour in timestamp '{}' cannot be > 23: {}" , value, hour) ?;
545+ }
546+ let minute: u8 = minute. try_into ( ) . map_err ( |e| p_err ( e, "Minute" ) ) ?;
547+ if minute > 59 {
548+ parser_err ! ( "Minute in timestamp '{}' cannot be > 59: {}" , value, minute) ?;
549+ }
550+ let second: u8 = second. try_into ( ) . map_err ( |e| p_err ( e, "Minute" ) ) ?;
551+ if second > 60 {
552+ parser_err ! ( "Second in timestamp '{}' cannot be > 60: {}" , value, second) ?;
553+ }
554+ Ok ( Value :: Timestamp (
555+ value,
556+ ParsedTimestamp {
557+ year,
558+ month,
559+ day,
560+ hour,
561+ minute,
562+ second,
563+ nano : nano. unwrap_or ( 0 ) ,
564+ } ,
565+ ) )
566+ }
567+ _ => Err ( ParserError :: ParserError ( format ! (
568+ "timestamp is missing fields, year through second are all required, got: '{}'" ,
569+ value
570+ ) ) ) ,
571+ }
572+ }
573+
507574 /// Parse an INTERVAL literal.
508575 ///
509576 /// Some syntactically valid intervals:
0 commit comments