Skip to content

Commit f1afb9a

Browse files
authored
Add Interval Literal (#190)
This PR adds SQL date intervals, i.e., supports statements such the following: ```SQL SELECT * FROM t WHERE t.date BETWEEN '2021-01-01' AND DATE '2021-01-01' + 30 DAYS ``` This is achieved by a new type of literal/`Expr`, with type `kExpressionLiteralInterval`. It is returned as second operand of the binary plus (or minus, respectivley) expression, where the start date ist the first one. Only checks if duration is a positive integer and the time unit is any of second(s), minute(s), hour(s), day(s), month(s), year(s). Any further sanity checks are in response of the consuming system. closes #184 closes #178
1 parent 78f0d6f commit f1afb9a

File tree

13 files changed

+2634
-2274
lines changed

13 files changed

+2634
-2274
lines changed

src/parser/bison_parser.cpp

Lines changed: 1276 additions & 1136 deletions
Large diffs are not rendered by default.

src/parser/bison_parser.h

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* A Bison parser, made by GNU Bison 3.7.6. */
1+
/* A Bison parser, made by GNU Bison 3.7.5. */
22

33
/* Bison interface for Yacc-like parsers in C
44
@@ -16,7 +16,7 @@
1616
GNU General Public License for more details.
1717
1818
You should have received a copy of the GNU General Public License
19-
along with this program. If not, see <https://www.gnu.org/licenses/>. */
19+
along with this program. If not, see <http://www.gnu.org/licenses/>. */
2020

2121
/* As a special exception, you may create a larger work that contains
2222
part or all of the Bison parser skeleton and distribute that work
@@ -223,20 +223,27 @@ extern int hsql_debug;
223223
SQL_DAY = 390, /* DAY */
224224
SQL_MONTH = 391, /* MONTH */
225225
SQL_YEAR = 392, /* YEAR */
226-
SQL_TRUE = 393, /* TRUE */
227-
SQL_FALSE = 394, /* FALSE */
228-
SQL_TRANSACTION = 395, /* TRANSACTION */
229-
SQL_BEGIN = 396, /* BEGIN */
230-
SQL_COMMIT = 397, /* COMMIT */
231-
SQL_ROLLBACK = 398, /* ROLLBACK */
232-
SQL_EQUALS = 399, /* EQUALS */
233-
SQL_NOTEQUALS = 400, /* NOTEQUALS */
234-
SQL_LESS = 401, /* LESS */
235-
SQL_GREATER = 402, /* GREATER */
236-
SQL_LESSEQ = 403, /* LESSEQ */
237-
SQL_GREATEREQ = 404, /* GREATEREQ */
238-
SQL_NOTNULL = 405, /* NOTNULL */
239-
SQL_UMINUS = 406 /* UMINUS */
226+
SQL_SECONDS = 393, /* SECONDS */
227+
SQL_MINUTES = 394, /* MINUTES */
228+
SQL_HOURS = 395, /* HOURS */
229+
SQL_DAYS = 396, /* DAYS */
230+
SQL_MONTHS = 397, /* MONTHS */
231+
SQL_YEARS = 398, /* YEARS */
232+
SQL_INTERVAL = 399, /* INTERVAL */
233+
SQL_TRUE = 400, /* TRUE */
234+
SQL_FALSE = 401, /* FALSE */
235+
SQL_TRANSACTION = 402, /* TRANSACTION */
236+
SQL_BEGIN = 403, /* BEGIN */
237+
SQL_COMMIT = 404, /* COMMIT */
238+
SQL_ROLLBACK = 405, /* ROLLBACK */
239+
SQL_EQUALS = 406, /* EQUALS */
240+
SQL_NOTEQUALS = 407, /* NOTEQUALS */
241+
SQL_LESS = 408, /* LESS */
242+
SQL_GREATER = 409, /* GREATER */
243+
SQL_LESSEQ = 410, /* LESSEQ */
244+
SQL_GREATEREQ = 411, /* GREATEREQ */
245+
SQL_NOTNULL = 412, /* NOTNULL */
246+
SQL_UMINUS = 413 /* UMINUS */
240247
};
241248
typedef enum hsql_tokentype hsql_token_kind_t;
242249
#endif
@@ -293,7 +300,7 @@ union HSQL_STYPE
293300
std::vector<hsql::OrderDescription*>* order_vec;
294301
std::vector<hsql::WithDescription*>* with_description_vec;
295302

296-
#line 297 "bison_parser.h"
303+
#line 304 "bison_parser.h"
297304

298305
};
299306
typedef union HSQL_STYPE HSQL_STYPE;

src/parser/bison_parser.y

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
10101025
array_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

10561072
null_literal:
1057-
NULL { $$ = Expr::makeNullLiteral(); }
1073+
NULL { $$ = Expr::makeNullLiteral(); }
10581074
;
10591075

10601076
date_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+
10731135
param_expr:
10741136
'?' {
10751137
$$ = Expr::makeParameter(yylloc.total_column);

0 commit comments

Comments
 (0)