@@ -181,6 +181,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
181181%token VIEW WHEN WITH ADD ALL AND ASC END FOR INT KEY
182182%token NOT OFF SET TOP AS BY IF IN IS OF ON OR TO
183183%token ARRAY CONCAT ILIKE SECOND MINUTE HOUR DAY MONTH YEAR
184+ %token SECONDS MINUTES HOURS DAYS MONTHS YEARS INTERVAL
184185%token TRUE FALSE
185186%token TRANSACTION BEGIN COMMIT ROLLBACK
186187
@@ -209,13 +210,13 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
209210%type <table> join_clause table_ref_name_no_alias
210211%type <expr> expr operand scalar_expr unary_expr binary_expr logic_expr exists_expr extract_expr cast_expr
211212%type <expr> function_expr between_expr expr_alias param_expr
212- %type <expr> column_name literal int_literal num_literal string_literal bool_literal date_literal
213+ %type <expr> column_name literal int_literal num_literal string_literal bool_literal date_literal interval_literal
213214%type <expr> comp_expr opt_where join_condition opt_having case_expr case_list in_expr hint
214215%type <expr> array_expr array_index null_literal
215216%type <limit> opt_limit opt_top
216217%type <order> order_desc
217218%type <order_type> opt_order_type
218- %type <datetime_field> datetime_field
219+ %type <datetime_field> datetime_field datetime_field_plural duration_field
219220%type <column_t> column_def
220221%type <column_type_t> column_type
221222%type <update_t> update_clause
@@ -1007,6 +1008,20 @@ datetime_field:
10071008 | YEAR { $$ = kDatetimeYear ; }
10081009 ;
10091010
1011+ datetime_field_plural :
1012+ SECONDS { $$ = kDatetimeSecond ; }
1013+ | MINUTES { $$ = kDatetimeMinute ; }
1014+ | HOURS { $$ = kDatetimeHour ; }
1015+ | DAYS { $$ = kDatetimeDay ; }
1016+ | MONTHS { $$ = kDatetimeMonth ; }
1017+ | YEARS { $$ = kDatetimeYear ; }
1018+ ;
1019+
1020+ duration_field :
1021+ datetime_field
1022+ | datetime_field_plural
1023+ ;
1024+
10101025array_expr :
10111026 ARRAY ' [' expr_list ' ]' { $$ = Expr::makeArray($3 ); }
10121027 ;
@@ -1032,6 +1047,7 @@ literal:
10321047 | num_literal
10331048 | null_literal
10341049 | date_literal
1050+ | interval_literal
10351051 | param_expr
10361052 ;
10371053
@@ -1054,7 +1070,7 @@ int_literal:
10541070 ;
10551071
10561072null_literal :
1057- NULL { $$ = Expr::makeNullLiteral(); }
1073+ NULL { $$ = Expr::makeNullLiteral(); }
10581074 ;
10591075
10601076date_literal :
@@ -1070,6 +1086,52 @@ date_literal:
10701086 }
10711087 ;
10721088
1089+ interval_literal :
1090+ int_literal duration_field { $$ = Expr::makeIntervalLiteral($1 ->ival, $2 ); delete $1 ; }
1091+ | INTERVAL STRING datetime_field {
1092+ int duration{0 }, chars_parsed{0 };
1093+ // If the whole string is parsed, chars_parsed points to the terminating null byte after the last character
1094+ if (sscanf($2 , " %d%n" , &duration, &chars_parsed) != 1 || $2 [chars_parsed] != 0 ) {
1095+ free ($2 );
1096+ yyerror (&yyloc, result, scanner, " Found incorrect interval format. Expected format: INTEGER" );
1097+ YYERROR ;
1098+ }
1099+ free ($2 );
1100+ $$ = Expr::makeIntervalLiteral(duration, $3 );
1101+ }
1102+ | INTERVAL STRING {
1103+ int duration{0 }, chars_parsed{0 };
1104+ // 'seconds' and 'minutes' are the longest accepted interval qualifiers (7 chars) + null byte
1105+ char unit_string[8 ];
1106+ // If the whole string is parsed, chars_parsed points to the terminating null byte after the last character
1107+ if (sscanf($2 , " %d %7s%n" , &duration, unit_string, &chars_parsed) != 2 || $2 [chars_parsed] != 0 ) {
1108+ free ($2 );
1109+ yyerror (&yyloc, result, scanner, " Found incorrect interval format. Expected format: INTEGER INTERVAL_QUALIIFIER" );
1110+ YYERROR ;
1111+ }
1112+ free ($2 );
1113+
1114+ DatetimeField unit;
1115+ if (strcasecmp(unit_string, " second" ) == 0 || strcasecmp(unit_string, " seconds" ) == 0 ) {
1116+ unit = kDatetimeSecond ;
1117+ } else if (strcasecmp(unit_string, " minute" ) == 0 || strcasecmp(unit_string, " minutes" ) == 0 ) {
1118+ unit = kDatetimeMinute ;
1119+ } else if (strcasecmp(unit_string, " hour" ) == 0 || strcasecmp(unit_string, " hours" ) == 0 ) {
1120+ unit = kDatetimeHour ;
1121+ } else if (strcasecmp(unit_string, " day" ) == 0 || strcasecmp(unit_string, " days" ) == 0 ) {
1122+ unit = kDatetimeDay ;
1123+ } else if (strcasecmp(unit_string, " month" ) == 0 || strcasecmp(unit_string, " months" ) == 0 ) {
1124+ unit = kDatetimeMonth ;
1125+ } else if (strcasecmp(unit_string, " year" ) == 0 || strcasecmp(unit_string, " years" ) == 0 ) {
1126+ unit = kDatetimeYear ;
1127+ } else {
1128+ yyerror (&yyloc, result, scanner, " Interval qualifier is unknown." );
1129+ YYERROR ;
1130+ }
1131+ $$ = Expr::makeIntervalLiteral(duration, unit);
1132+ }
1133+ ;
1134+
10731135param_expr :
10741136 ' ?' {
10751137 $$ = Expr::makeParameter(yylloc.total_column);
0 commit comments