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_CTE_INCLUDED
18#define SQL_CTE_INCLUDED
19#include "sql_list.h"
20#include "sql_lex.h"
21#include "sql_select.h"
22
23class select_unit;
24struct st_unit_ctxt_elem;
25
26
27/**
28 @class With_element
29 @brief Definition of a CTE table
30
31 It contains a reference to the name of the table introduced by this with element,
32 and a reference to the unit that specificies this table. Also it contains
33 a reference to the with clause to which this element belongs to.
34*/
35
36class With_element : public Sql_alloc
37{
38private:
39 With_clause *owner; // with clause this object belongs to
40 With_element *next; // next element in the with clause
41 uint number; // number of the element in the with clause (starting from 0)
42 table_map elem_map; // The map where with only one 1 set in this->number
43 /*
44 The map base_dep_map has 1 in the i-th position if the query that
45 specifies this with element contains a reference to the with element number i
46 in the query FROM list.
47 (In this case this with element depends directly on the i-th with element.)
48 */
49 table_map base_dep_map;
50 /*
51 The map derived_dep_map has 1 in i-th position if this with element depends
52 directly or indirectly from the i-th with element.
53 */
54 table_map derived_dep_map;
55 /*
56 The map sq_dep_map has 1 in i-th position if there is a reference to this
57 with element somewhere in subqueries of the specifications of the tables
58 defined in the with clause containing this element;
59 */
60 table_map sq_dep_map;
61 table_map work_dep_map; // dependency map used for work
62 /* Dependency map of with elements mutually recursive with this with element */
63 table_map mutually_recursive;
64 /*
65 Dependency map built only for the top level references i.e. for those that
66 are encountered in from lists of the selects of the specification unit
67 */
68 table_map top_level_dep_map;
69 /*
70 Points to a recursive reference in subqueries.
71 Used only for specifications without recursive references on the top level.
72 */
73 TABLE_LIST *sq_rec_ref;
74 /*
75 The next with element from the circular chain of the with elements
76 mutually recursive with this with element.
77 (If This element is simply recursive than next_mutually_recursive contains
78 the pointer to itself. If it's not recursive than next_mutually_recursive
79 is set to NULL.)
80 */
81 With_element *next_mutually_recursive;
82 /*
83 Total number of references to this element in the FROM lists of
84 the queries that are in the scope of the element (including
85 subqueries and specifications of other with elements).
86 */
87 uint references;
88 /*
89 Unparsed specification of the query that specifies this element.
90 It used to build clones of the specification if they are needed.
91 */
92 LEX_CSTRING unparsed_spec;
93
94 /* Return the map where 1 is set only in the position for this element */
95 table_map get_elem_map() { return (table_map) 1 << number; }
96
97public:
98 /*
99 The name of the table introduced by this with elememt. The name
100 can be used in FROM lists of the queries in the scope of the element.
101 */
102 LEX_CSTRING *query_name;
103 /*
104 Optional list of column names to name the columns of the table introduced
105 by this with element. It is used in the case when the names are not
106 inherited from the query that specified the table. Otherwise the list is
107 always empty.
108 */
109 List <LEX_CSTRING> column_list;
110 /* The query that specifies the table introduced by this with element */
111 st_select_lex_unit *spec;
112 /*
113 Set to true is recursion is used (directly or indirectly)
114 for the definition of this element
115 */
116 bool is_recursive;
117
118 /*
119 Any non-recursive select in the specification of a recursive
120 with element is a called anchor. In the case mutually recursive
121 elements the specification of some them may be without any anchor.
122 Yet at least one of them must contain an anchor.
123 All anchors of any recursivespecification are moved ahead before
124 the prepare stage.
125 */
126 /* Set to true if this is a recursive element with an anchor */
127 bool with_anchor;
128 /*
129 Set to the first recursive select of the unit specifying the element
130 after all anchor have been moved to the head of the unit.
131 */
132 st_select_lex *first_recursive;
133
134 /*
135 The number of the last performed iteration for recursive table
136 (the number of the initial non-recursive step is 0, the number
137 of the first iteration is 1).
138 */
139 uint level;
140
141 /*
142 The pointer to the object used to materialize this with element
143 if it's recursive. This object is built at the end of prepare
144 stage and is used at the execution stage.
145 */
146 select_union_recursive *rec_result;
147
148 /* List of Item_subselects containing recursive references to this CTE */
149 SQL_I_List<Item_subselect> sq_with_rec_ref;
150 /* List of derived tables containing recursive references to this CTE */
151 SQL_I_List<TABLE_LIST> derived_with_rec_ref;
152
153 With_element(LEX_CSTRING *name,
154 List <LEX_CSTRING> list,
155 st_select_lex_unit *unit)
156 : next(NULL), base_dep_map(0), derived_dep_map(0),
157 sq_dep_map(0), work_dep_map(0), mutually_recursive(0),
158 top_level_dep_map(0), sq_rec_ref(NULL),
159 next_mutually_recursive(NULL), references(0),
160 query_name(name), column_list(list), spec(unit),
161 is_recursive(false), with_anchor(false),
162 level(0), rec_result(NULL)
163 { unit->with_element= this; }
164
165 bool check_dependencies_in_spec();
166
167 void check_dependencies_in_select(st_select_lex *sl, st_unit_ctxt_elem *ctxt,
168 bool in_subq, table_map *dep_map);
169
170 void check_dependencies_in_unit(st_select_lex_unit *unit,
171 st_unit_ctxt_elem *ctxt,
172 bool in_subq,
173 table_map *dep_map);
174
175 void check_dependencies_in_with_clause(With_clause *with_clause,
176 st_unit_ctxt_elem *ctxt,
177 bool in_subq,
178 table_map *dep_map);
179
180 void set_dependency_on(With_element *with_elem)
181 { base_dep_map|= with_elem->get_elem_map(); }
182
183 bool check_dependency_on(With_element *with_elem)
184 { return base_dep_map & with_elem->get_elem_map(); }
185
186 TABLE_LIST *find_first_sq_rec_ref_in_select(st_select_lex *sel);
187
188 bool set_unparsed_spec(THD *thd, char *spec_start, char *spec_end);
189
190 st_select_lex_unit *clone_parsed_spec(THD *thd, TABLE_LIST *with_table);
191
192 bool is_referenced() { return references != 0; }
193
194 void inc_references() { references++; }
195
196 bool rename_columns_of_derived_unit(THD *thd, st_select_lex_unit *unit);
197
198 bool prepare_unreferenced(THD *thd);
199
200 bool check_unrestricted_recursive(st_select_lex *sel,
201 table_map &unrestricted,
202 table_map &encountered);
203
204 void print(String *str, enum_query_type query_type);
205
206 With_clause *get_owner() { return owner; }
207
208 bool contains_sq_with_recursive_reference()
209 { return sq_dep_map & mutually_recursive; }
210
211 bool no_rec_ref_on_top_level()
212 { return !(top_level_dep_map & mutually_recursive); }
213
214 table_map get_mutually_recursive() { return mutually_recursive; }
215
216 With_element *get_next_mutually_recursive()
217 { return next_mutually_recursive; }
218
219 TABLE_LIST *get_sq_rec_ref() { return sq_rec_ref; }
220
221 bool is_anchor(st_select_lex *sel);
222
223 void move_anchors_ahead();
224
225 bool is_unrestricted();
226
227 bool is_with_prepared_anchor();
228
229 void mark_as_with_prepared_anchor();
230
231 bool is_cleaned();
232
233 void mark_as_cleaned();
234
235 void reset_recursive_for_exec();
236
237 void cleanup_stabilized();
238
239 void set_as_stabilized();
240
241 bool is_stabilized();
242
243 bool all_are_stabilized();
244
245 bool instantiate_tmp_tables();
246
247 void prepare_for_next_iteration();
248
249 friend class With_clause;
250};
251
252const uint max_number_of_elements_in_with_clause= sizeof(table_map)*8;
253
254/**
255 @class With_clause
256 @brief Set of with_elements
257
258 It has a reference to the first with element from this with clause.
259 This reference allows to navigate through all the elements of the with clause.
260 It contains a reference to the unit to which this with clause is attached.
261 It also contains a flag saying whether this with clause was specified as recursive.
262*/
263
264class With_clause : public Sql_alloc
265{
266private:
267 st_select_lex_unit *owner; // the unit this with clause attached to
268
269 /* The list of all with elements from this with clause */
270 SQL_I_List<With_element> with_list;
271 /*
272 The with clause immediately containing this with clause if there is any,
273 otherwise NULL. Now used only at parsing.
274 */
275 With_clause *embedding_with_clause;
276 /*
277 The next with the clause of the chain of with clauses encountered
278 in the current statement
279 */
280 With_clause *next_with_clause;
281 /* Set to true if dependencies between with elements have been checked */
282 bool dependencies_are_checked;
283
284 /*
285 The bitmap of all recursive with elements whose specifications
286 are not complied with restrictions imposed by the SQL standards
287 on recursive specifications.
288 */
289 table_map unrestricted;
290 /*
291 The bitmap of all recursive with elements whose anchors
292 has been already prepared.
293 */
294 table_map with_prepared_anchor;
295 table_map cleaned;
296 /*
297 The bitmap of all recursive with elements that
298 has been already materialized
299 */
300 table_map stabilized;
301
302public:
303 /* If true the specifier RECURSIVE is present in the with clause */
304 bool with_recursive;
305
306 With_clause(bool recursive_fl, With_clause *emb_with_clause)
307 : owner(NULL),
308 embedding_with_clause(emb_with_clause), next_with_clause(NULL),
309 dependencies_are_checked(false), unrestricted(0),
310 with_prepared_anchor(0), cleaned(0), stabilized(0),
311 with_recursive(recursive_fl)
312 { }
313
314 bool add_with_element(With_element *elem);
315
316 /* Add this with clause to the list of with clauses used in the statement */
317 void add_to_list(With_clause ** &last_next)
318 {
319 *last_next= this;
320 last_next= &this->next_with_clause;
321 }
322
323 void set_owner(st_select_lex_unit *unit) { owner= unit; }
324
325 With_clause *pop() { return embedding_with_clause; }
326
327 bool check_dependencies();
328
329 bool check_anchors();
330
331 void move_anchors_ahead();
332
333 With_element *find_table_def(TABLE_LIST *table, With_element *barrier);
334
335 With_element *find_table_def_in_with_clauses(TABLE_LIST *table);
336
337 bool prepare_unreferenced_elements(THD *thd);
338
339 void add_unrestricted(table_map map) { unrestricted|= map; }
340
341 void print(String *str, enum_query_type query_type);
342
343 friend class With_element;
344
345 friend
346 bool
347 check_dependencies_in_with_clauses(With_clause *with_clauses_list);
348};
349
350inline
351bool With_element::is_unrestricted()
352{
353 return owner->unrestricted & get_elem_map();
354}
355
356inline
357
358bool With_element::is_with_prepared_anchor()
359{
360 return owner->with_prepared_anchor & get_elem_map();
361}
362
363inline
364void With_element::mark_as_with_prepared_anchor()
365{
366 owner->with_prepared_anchor|= mutually_recursive;
367}
368
369
370inline
371bool With_element::is_cleaned()
372{
373 return owner->cleaned & get_elem_map();
374}
375
376
377inline
378void With_element::mark_as_cleaned()
379{
380 owner->cleaned|= get_elem_map();
381}
382
383
384inline
385void With_element::reset_recursive_for_exec()
386{
387 DBUG_ASSERT(is_recursive);
388 level= 0;
389 owner->with_prepared_anchor&= ~mutually_recursive;
390 owner->cleaned&= ~get_elem_map();
391 cleanup_stabilized();
392 spec->columns_are_renamed= false;
393}
394
395
396
397inline
398void With_element::cleanup_stabilized()
399{
400 owner->stabilized&= ~mutually_recursive;
401}
402
403
404inline
405void With_element::set_as_stabilized()
406{
407 owner->stabilized|= get_elem_map();
408}
409
410
411inline
412bool With_element::is_stabilized()
413{
414 return owner->stabilized & get_elem_map();
415}
416
417
418inline
419bool With_element::all_are_stabilized()
420{
421 return (owner->stabilized & mutually_recursive) == mutually_recursive;
422}
423
424
425inline
426void With_element::prepare_for_next_iteration()
427{
428 With_element *with_elem= this;
429 while ((with_elem= with_elem->get_next_mutually_recursive()) != this)
430 {
431 TABLE *rec_table= with_elem->rec_result->first_rec_table_to_update;
432 if (rec_table)
433 rec_table->reginfo.join_tab->preread_init_done= false;
434 }
435}
436
437
438inline
439void st_select_lex_unit::set_with_clause(With_clause *with_cl)
440{
441 with_clause= with_cl;
442 if (with_clause)
443 with_clause->set_owner(this);
444}
445
446
447inline
448void st_select_lex::set_with_clause(With_clause *with_clause)
449{
450 master_unit()->with_clause= with_clause;
451 if (with_clause)
452 with_clause->set_owner(master_unit());
453}
454
455#endif /* SQL_CTE_INCLUDED */
456