| 1 | /* |
| 2 | Copyright (c) 2016, 2017 MariaDB |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License as published by |
| 6 | the Free Software Foundation; version 2 of the License. |
| 7 | |
| 8 | This program is distributed in the hope that it will be useful, |
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | GNU General Public License for more details. |
| 12 | |
| 13 | You should have received a copy of the GNU General Public License |
| 14 | along with this program; if not, write to the Free Software |
| 15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 16 | |
| 17 | #ifndef SQL_WINDOW_INCLUDED |
| 18 | #define SQL_WINDOW_INCLUDED |
| 19 | |
| 20 | #include "filesort.h" |
| 21 | #include "records.h" |
| 22 | |
| 23 | class Item_window_func; |
| 24 | |
| 25 | /* |
| 26 | Window functions module. |
| 27 | |
| 28 | Each instance of window function has its own element in SELECT_LEX::window_specs. |
| 29 | */ |
| 30 | |
| 31 | |
| 32 | class Window_frame_bound : public Sql_alloc |
| 33 | { |
| 34 | |
| 35 | public: |
| 36 | |
| 37 | enum Bound_precedence_type |
| 38 | { |
| 39 | PRECEDING, |
| 40 | CURRENT, // Used for CURRENT ROW window frame bounds |
| 41 | FOLLOWING |
| 42 | }; |
| 43 | |
| 44 | Bound_precedence_type precedence_type; |
| 45 | |
| 46 | |
| 47 | /* |
| 48 | For UNBOUNDED PRECEDING / UNBOUNDED FOLLOWING window frame bounds |
| 49 | precedence type is seto to PRECEDING / FOLLOWING and |
| 50 | offset is set to NULL. |
| 51 | The offset is not meaningful with precedence type CURRENT |
| 52 | */ |
| 53 | Item *offset; |
| 54 | |
| 55 | Window_frame_bound(Bound_precedence_type prec_type, |
| 56 | Item *offset_val) |
| 57 | : precedence_type(prec_type), offset(offset_val) {} |
| 58 | |
| 59 | bool is_unbounded() { return offset == NULL; } |
| 60 | |
| 61 | void print(String *str, enum_query_type query_type); |
| 62 | |
| 63 | }; |
| 64 | |
| 65 | |
| 66 | class Window_frame : public Sql_alloc |
| 67 | { |
| 68 | |
| 69 | public: |
| 70 | |
| 71 | enum Frame_units |
| 72 | { |
| 73 | UNITS_ROWS, |
| 74 | UNITS_RANGE |
| 75 | }; |
| 76 | |
| 77 | enum Frame_exclusion |
| 78 | { |
| 79 | EXCL_NONE, |
| 80 | EXCL_CURRENT_ROW, |
| 81 | EXCL_GROUP, |
| 82 | EXCL_TIES |
| 83 | }; |
| 84 | |
| 85 | Frame_units units; |
| 86 | |
| 87 | Window_frame_bound *top_bound; |
| 88 | |
| 89 | Window_frame_bound *bottom_bound; |
| 90 | |
| 91 | Frame_exclusion exclusion; |
| 92 | |
| 93 | Window_frame(Frame_units win_frame_units, |
| 94 | Window_frame_bound *win_frame_top_bound, |
| 95 | Window_frame_bound *win_frame_bottom_bound, |
| 96 | Frame_exclusion win_frame_exclusion) |
| 97 | : units(win_frame_units), top_bound(win_frame_top_bound), |
| 98 | bottom_bound(win_frame_bottom_bound), exclusion(win_frame_exclusion) {} |
| 99 | |
| 100 | bool check_frame_bounds(); |
| 101 | |
| 102 | void print(String *str, enum_query_type query_type); |
| 103 | |
| 104 | }; |
| 105 | |
| 106 | class Window_spec : public Sql_alloc |
| 107 | { |
| 108 | bool window_names_are_checked; |
| 109 | public: |
| 110 | virtual ~Window_spec() {} |
| 111 | |
| 112 | LEX_CSTRING *window_ref; |
| 113 | |
| 114 | SQL_I_List<ORDER> *partition_list; |
| 115 | |
| 116 | SQL_I_List<ORDER> *order_list; |
| 117 | |
| 118 | Window_frame *window_frame; |
| 119 | |
| 120 | Window_spec *referenced_win_spec; |
| 121 | |
| 122 | Window_spec(LEX_CSTRING *win_ref, |
| 123 | SQL_I_List<ORDER> *part_list, |
| 124 | SQL_I_List<ORDER> *ord_list, |
| 125 | Window_frame *win_frame) |
| 126 | : window_names_are_checked(false), window_ref(win_ref), |
| 127 | partition_list(part_list), order_list(ord_list), |
| 128 | window_frame(win_frame), referenced_win_spec(NULL) {} |
| 129 | |
| 130 | virtual const char *name() { return NULL; } |
| 131 | |
| 132 | bool check_window_names(List_iterator_fast<Window_spec> &it); |
| 133 | |
| 134 | const char *window_reference() |
| 135 | { |
| 136 | return window_ref ? window_ref->str : NULL; |
| 137 | } |
| 138 | |
| 139 | void join_partition_and_order_lists() |
| 140 | { |
| 141 | *(partition_list->next)= order_list->first; |
| 142 | } |
| 143 | |
| 144 | void disjoin_partition_and_order_lists() |
| 145 | { |
| 146 | *(partition_list->next)= NULL; |
| 147 | } |
| 148 | |
| 149 | void print(String *str, enum_query_type query_type); |
| 150 | |
| 151 | }; |
| 152 | |
| 153 | class Window_def : public Window_spec |
| 154 | { |
| 155 | public: |
| 156 | |
| 157 | LEX_CSTRING *window_name; |
| 158 | |
| 159 | Window_def(LEX_CSTRING *win_name, |
| 160 | LEX_CSTRING *win_ref, |
| 161 | SQL_I_List<ORDER> *part_list, |
| 162 | SQL_I_List<ORDER> *ord_list, |
| 163 | Window_frame *win_frame) |
| 164 | : Window_spec(win_ref, part_list, ord_list, win_frame), |
| 165 | window_name(win_name) {} |
| 166 | |
| 167 | const char *name() { return window_name->str; } |
| 168 | |
| 169 | }; |
| 170 | |
| 171 | int setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, |
| 172 | List<Item> &fields, List<Item> &all_fields, |
| 173 | List<Window_spec> &win_specs, List<Item_window_func> &win_funcs); |
| 174 | |
| 175 | |
| 176 | ////////////////////////////////////////////////////////////////////////////// |
| 177 | // Classes that make window functions computation a part of SELECT's query plan |
| 178 | ////////////////////////////////////////////////////////////////////////////// |
| 179 | |
| 180 | class Frame_cursor; |
| 181 | /* |
| 182 | This handles computation of one window function. |
| 183 | |
| 184 | Currently, we make a spearate filesort() call for each window function. |
| 185 | */ |
| 186 | |
| 187 | class Window_func_runner : public Sql_alloc |
| 188 | { |
| 189 | public: |
| 190 | /* Add the function to be computed during the execution pass */ |
| 191 | bool add_function_to_run(Item_window_func *win_func); |
| 192 | |
| 193 | /* Compute and fill the fields in the table. */ |
| 194 | bool exec(THD *thd, TABLE *tbl, SORT_INFO *filesort_result); |
| 195 | |
| 196 | private: |
| 197 | /* A list of window functions for which this Window_func_runner will compute |
| 198 | values during the execution phase. */ |
| 199 | List<Item_window_func> window_functions; |
| 200 | }; |
| 201 | |
| 202 | |
| 203 | /* |
| 204 | Represents a group of window functions that require the same sorting of |
| 205 | rows and so share the filesort() call. |
| 206 | |
| 207 | */ |
| 208 | |
| 209 | class Window_funcs_sort : public Sql_alloc |
| 210 | { |
| 211 | public: |
| 212 | bool setup(THD *thd, SQL_SELECT *sel, List_iterator<Item_window_func> &it, |
| 213 | st_join_table *join_tab); |
| 214 | bool exec(JOIN *join); |
| 215 | void cleanup() { delete filesort; } |
| 216 | |
| 217 | friend class Window_funcs_computation; |
| 218 | |
| 219 | private: |
| 220 | Window_func_runner runner; |
| 221 | |
| 222 | /* Window functions can be computed over this sorting */ |
| 223 | Filesort *filesort; |
| 224 | }; |
| 225 | |
| 226 | |
| 227 | struct st_join_table; |
| 228 | class Explain_aggr_window_funcs; |
| 229 | |
| 230 | /* |
| 231 | This is a "window function computation phase": a single object of this class |
| 232 | takes care of computing all window functions in a SELECT. |
| 233 | |
| 234 | - JOIN optimizer is exected to call setup() during query optimization. |
| 235 | - JOIN::exec() should call exec() once it has collected join output in a |
| 236 | temporary table. |
| 237 | */ |
| 238 | |
| 239 | class Window_funcs_computation : public Sql_alloc |
| 240 | { |
| 241 | List<Window_funcs_sort> win_func_sorts; |
| 242 | public: |
| 243 | bool setup(THD *thd, List<Item_window_func> *window_funcs, st_join_table *tab); |
| 244 | bool exec(JOIN *join); |
| 245 | |
| 246 | Explain_aggr_window_funcs *save_explain_plan(MEM_ROOT *mem_root, bool is_analyze); |
| 247 | void cleanup(); |
| 248 | }; |
| 249 | |
| 250 | |
| 251 | #endif /* SQL_WINDOW_INCLUDED */ |
| 252 | |