Skip to content

Commit c247124

Browse files
authored
Add window functions (#233)
This PR adds SQL:2003 window functions compatible to Postgres. The window is added as an aditional description for function expressions.
1 parent 5af29dd commit c247124

File tree

13 files changed

+5006
-4277
lines changed

13 files changed

+5006
-4277
lines changed

src/parser/bison_parser.cpp

Lines changed: 1776 additions & 1619 deletions
Large diffs are not rendered by default.

src/parser/bison_parser.h

Lines changed: 217 additions & 196 deletions
Large diffs are not rendered by default.

src/parser/bison_parser.y

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,14 @@
125125
hsql::DatetimeField datetime_field;
126126
hsql::DropColumnAction* drop_action_t;
127127
hsql::Expr* expr;
128+
hsql::FrameBound* frame_bound;
129+
hsql::FrameDescription* frame_description;
130+
hsql::FrameType frame_type;
128131
hsql::GroupByDescription* group_t;
129132
hsql::ImportType import_type_t;
130133
hsql::JoinType join_type;
131134
hsql::LimitDescription* limit;
135+
hsql::LockingClause* locking_t;
132136
hsql::OrderDescription* order;
133137
hsql::OrderType order_type;
134138
hsql::SetOperation* set_operator_t;
@@ -137,8 +141,8 @@
137141
hsql::TableName table_name;
138142
hsql::TableRef* table;
139143
hsql::UpdateClause* update_t;
144+
hsql::WindowDescription* window_description;
140145
hsql::WithDescription* with_description_t;
141-
hsql::LockingClause* locking_t;
142146

143147
std::vector<char*>* str_vec;
144148
std::unordered_set<hsql::ConstraintType>* column_constraint_set;
@@ -161,7 +165,7 @@
161165
** Destructor symbols
162166
*********************************/
163167
// clang-format off
164-
%destructor { } <fval> <ival> <bval> <join_type> <order_type> <datetime_field> <column_type_t> <column_constraint_t> <import_type_t> <column_constraint_set> <lock_mode_t> <lock_wait_policy_t>
168+
%destructor { } <fval> <ival> <bval> <join_type> <order_type> <datetime_field> <column_type_t> <column_constraint_t> <import_type_t> <column_constraint_set> <lock_mode_t> <lock_wait_policy_t> <frame_type>
165169
%destructor {
166170
free( ($$.name) );
167171
free( ($$.schema) );
@@ -202,17 +206,18 @@
202206
%token DOUBLE ESCAPE EXCEPT EXISTS EXTRACT CAST FORMAT GLOBAL HAVING IMPORT
203207
%token INSERT ISNULL OFFSET RENAME SCHEMA SELECT SORTED
204208
%token TABLES UNIQUE UNLOAD UPDATE VALUES AFTER ALTER CROSS
205-
%token DELTA FLOAT GROUP INDEX INNER LIMIT LOCAL MERGE MINUS ORDER
209+
%token DELTA FLOAT GROUP INDEX INNER LIMIT LOCAL MERGE MINUS ORDER OVER
206210
%token OUTER RIGHT TABLE UNION USING WHERE CALL CASE CHAR COPY DATE DATETIME
207211
%token DESC DROP ELSE FILE FROM FULL HASH HINT INTO JOIN
208-
%token LEFT LIKE LOAD LONG NULL PLAN SHOW TEXT THEN TIME
212+
%token LEFT LIKE LOAD LONG NULL PARTITION PLAN SHOW TEXT THEN TIME
209213
%token VIEW WHEN WITH ADD ALL AND ASC END FOR INT KEY
210214
%token NOT OFF SET TOP AS BY IF IN IS OF ON OR TO NO
211215
%token ARRAY CONCAT ILIKE SECOND MINUTE HOUR DAY MONTH YEAR
212216
%token SECONDS MINUTES HOURS DAYS MONTHS YEARS INTERVAL
213217
%token TRUE FALSE BOOLEAN
214218
%token TRANSACTION BEGIN COMMIT ROLLBACK
215219
%token NOWAIT SKIP LOCKED SHARE
220+
%token RANGE ROWS GROUPS UNBOUNDED FOLLOWING PRECEDING CURRENT_ROW
216221

217222
/*********************************
218223
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
@@ -235,6 +240,10 @@
235240
%type <table_name> table_name
236241
%type <sval> opt_index_name
237242
%type <sval> file_path prepare_target_query
243+
%type <frame_description> opt_frame_clause
244+
%type <frame_bound> frame_bound
245+
%type <frame_type> frame_type
246+
%type <window_description> opt_window
238247
%type <bval> opt_not_exists opt_exists opt_distinct opt_all
239248
%type <ival_pair> opt_decimal_specification
240249
%type <ival> opt_time_precision
@@ -272,7 +281,7 @@
272281
%type <import_type_t> opt_file_type file_type
273282

274283
%type <str_vec> ident_commalist opt_column_list
275-
%type <expr_vec> expr_list select_list opt_literal_list literal_list hint_list opt_hints
284+
%type <expr_vec> expr_list select_list opt_literal_list literal_list hint_list opt_hints opt_partition
276285
%type <table_vec> table_ref_commalist
277286
%type <order_vec> opt_order order_list
278287
%type <with_description_vec> opt_with_clause with_clause with_description_list
@@ -978,8 +987,37 @@ comp_expr : operand '=' operand { $$ = Expr::makeOpBinary($1, kOpEquals, $3); }
978987
| operand LESSEQ operand { $$ = Expr::makeOpBinary($1, kOpLessEq, $3); }
979988
| operand GREATEREQ operand { $$ = Expr::makeOpBinary($1, kOpGreaterEq, $3); };
980989

981-
function_expr : IDENTIFIER '(' ')' { $$ = Expr::makeFunctionRef($1, new std::vector<Expr*>(), false); }
982-
| IDENTIFIER '(' opt_distinct expr_list ')' { $$ = Expr::makeFunctionRef($1, $4, $3); };
990+
// `function_expr is used for window functions, aggregate expressions, and functions calls because we run into shift/
991+
// reduce conflicts when splitting them.
992+
function_expr : IDENTIFIER '(' ')' opt_window { $$ = Expr::makeFunctionRef($1, new std::vector<Expr*>(), false, $4); }
993+
| IDENTIFIER '(' opt_distinct expr_list ')' opt_window { $$ = Expr::makeFunctionRef($1, $4, $3, $6); };
994+
995+
// Window function expressions, based on https://www.postgresql.org/docs/15/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS
996+
// We do not support named windows, collations and exclusions (for simplicity) and filters (not part of the SQL standard).
997+
opt_window : OVER '(' opt_partition opt_order opt_frame_clause ')' { $$ = new WindowDescription($3, $4, $5); }
998+
| /* empty */ { $$ = nullptr; };
999+
1000+
opt_partition : PARTITION BY expr_list { $$ = $3; }
1001+
| /* empty */ { $$ = nullptr; };
1002+
1003+
// We use the Postgres default if the frame end or the whole frame clause is omitted. "If `frame_end` is omitted, the
1004+
// end defaults to `CURRENT ROW`. [...] The default framing option is `RANGE UNBOUNDED PRECEDING`, which is the same as
1005+
// `RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`."
1006+
opt_frame_clause : frame_type frame_bound { $$ = new FrameDescription{$1, $2, new FrameBound{0, kCurrentRow, false}}; }
1007+
| frame_type BETWEEN frame_bound AND frame_bound { $$ = new FrameDescription{$1, $3, $5}; }
1008+
| /* empty */ {
1009+
$$ = new FrameDescription{kRange, new FrameBound{0, kPreceding, true}, new FrameBound{0, kCurrentRow, false}};
1010+
};
1011+
1012+
frame_type : RANGE { $$ = kRange; }
1013+
| ROWS { $$ = kRows; }
1014+
| GROUPS { $$ = kGroups; };
1015+
1016+
frame_bound : UNBOUNDED PRECEDING { $$ = new FrameBound{0, kPreceding, true}; }
1017+
| INTVAL PRECEDING { $$ = new FrameBound{$1, kPreceding, false}; }
1018+
| UNBOUNDED FOLLOWING { $$ = new FrameBound{0, kFollowing, true}; }
1019+
| INTVAL FOLLOWING { $$ = new FrameBound{$1, kFollowing, false}; }
1020+
| CURRENT_ROW { $$ = new FrameBound{0, kCurrentRow, false}; };
9831021

9841022
extract_expr : EXTRACT '(' datetime_field FROM expr ')' { $$ = Expr::makeExtract($3, $5); };
9851023

0 commit comments

Comments
 (0)