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 #include "mariadb.h"
18 #include "sql_class.h"
19 #include "sql_lex.h"
20 #include "sql_cte.h"
21 #include "sql_view.h" // for make_valid_column_names
22 #include "sql_parse.h"
23 #include "sql_select.h"
24
25
26 /**
27 @brief
28 Add a new element to this with clause
29
30 @param elem The with element to add to this with clause
31
32 @details
33 The method adds the with element 'elem' to the elements
34 in this with clause. The method reports an error if
35 the number of the added element exceeds the value
36 of the constant max_number_of_elements_in_with_clause.
37
38 @retval
39 true if an error is reported
40 false otherwise
41 */
42
add_with_element(With_element * elem)43 bool With_clause::add_with_element(With_element *elem)
44 {
45 if (with_list.elements == max_number_of_elements_in_with_clause)
46 {
47 my_error(ER_TOO_MANY_DEFINITIONS_IN_WITH_CLAUSE, MYF(0));
48 return true;
49 }
50 elem->owner= this;
51 elem->number= with_list.elements;
52 elem->spec->with_element= elem;
53 with_list.link_in_list(elem, &elem->next);
54 return false;
55 }
56
57
set_with_clause(With_clause * with_cl)58 void st_select_lex_unit::set_with_clause(With_clause *with_cl)
59 {
60 with_clause= with_cl;
61 if (with_clause)
62 with_clause->set_owner(this);
63 }
64
65
66 /**
67 @brief
68 Check dependencies between tables defined in a list of with clauses
69
70 @param
71 with_clauses_list Pointer to the first clause in the list
72
73 @details
74 For each with clause from the given list the procedure finds all
75 dependencies between tables defined in the clause by calling the
76 method With_clause::checked_dependencies.
77 Additionally, based on the info collected by this method the procedure
78 finds anchors for each recursive definition and moves them at the head
79 of the definition.
80
81 @retval
82 false on success
83 true on failure
84 */
85
check_dependencies_in_with_clauses()86 bool LEX::check_dependencies_in_with_clauses()
87 {
88 for (With_clause *with_clause= with_clauses_list;
89 with_clause;
90 with_clause= with_clause->next_with_clause)
91 {
92 if (with_clause->check_dependencies())
93 return true;
94 if (with_clause->check_anchors())
95 return true;
96 with_clause->move_anchors_ahead();
97 }
98 return false;
99 }
100
101
102 /**
103 @brief
104 Resolve references to CTE in specification of hanging CTE
105
106 @details
107 A CTE to which there are no references in the query is called hanging CTE.
108 Although such CTE is not used for execution its specification must be
109 subject to context analysis. All errors concerning references to
110 non-existing tables or fields occurred in the specification must be
111 reported as well as all other errors caught at the prepare stage.
112 The specification of a hanging CTE might contain references to other
113 CTE outside of the specification and within it if the specification
114 contains a with clause. This function resolves all such references for
115 all hanging CTEs encountered in the processed query.
116
117 @retval
118 false on success
119 true on failure
120 */
121
122 bool
resolve_references_to_cte_in_hanging_cte()123 LEX::resolve_references_to_cte_in_hanging_cte()
124 {
125 for (With_clause *with_clause= with_clauses_list;
126 with_clause; with_clause= with_clause->next_with_clause)
127 {
128 for (With_element *with_elem= with_clause->with_list.first;
129 with_elem; with_elem= with_elem->next)
130 {
131 if (!with_elem->is_referenced())
132 {
133 TABLE_LIST *first_tbl=
134 with_elem->spec->first_select()->table_list.first;
135 TABLE_LIST **with_elem_end_pos= with_elem->head->tables_pos.end_pos;
136 if (first_tbl && resolve_references_to_cte(first_tbl, with_elem_end_pos))
137 return true;
138 }
139 }
140 }
141 return false;
142 }
143
144
145 /**
146 @brief
147 Resolve table references to CTE from a sub-chain of table references
148
149 @param tables Points to the beginning of the sub-chain
150 @param tables_last Points to the address with the sub-chain barrier
151
152 @details
153 The method resolves tables references to CTE from the chain of
154 table references specified by the parameters 'tables' and 'tables_last'.
155 It resolves the references against the CTE definition occurred in a query
156 or the specification of a CTE whose parsing tree is represented by
157 this LEX structure. The method is always called right after the process
158 of parsing the query or of the specification of a CTE has been finished,
159 thus the chain of table references used in the parsed fragment has been
160 already built. It is assumed that parameters of the method specify a
161 a sub-chain of this chain.
162 If a table reference can be potentially a table reference to a CTE and it
163 has not been resolved yet then the method tries to find the definition
164 of the CTE against which the reference can be resolved. If it succeeds
165 it sets the field TABLE_LIST::with to point to the found definition.
166 It also sets the field TABLE_LIST::derived to point to the specification
167 of the found CTE and sets TABLE::db.str to empty_c_string. This will
168 allow to handle this table reference like a reference to a derived handle.
169 If another table reference has been already resolved against this CTE
170 and this CTE is not recursive then a clone of the CTE specification is
171 constructed using the function With_element::clone_parsed_spec() and
172 TABLE_LIST::derived is set to point to this clone rather than to the
173 original specification.
174 If the method does not find a matched CTE definition in the parsed fragment
175 then in the case when the flag this->only_cte_resolution is set to true
176 it just moves to the resolution of the next table reference from the
177 specified sub-chain while in the case when this->only_cte_resolution is set
178 to false the method additionally sets an mdl request for this table
179 reference.
180
181 @notes
182 The flag this->only_cte_resolution is set to true in the cases when
183 the failure to resolve a table reference as a CTE reference within
184 the fragment associated with this LEX structure does not imply that
185 this table reference cannot be resolved as such at all.
186
187 @retval false On success: no errors reported, no memory allocations failed
188 @retval true Otherwise
189 */
190
resolve_references_to_cte(TABLE_LIST * tables,TABLE_LIST ** tables_last)191 bool LEX::resolve_references_to_cte(TABLE_LIST *tables,
192 TABLE_LIST **tables_last)
193 {
194 With_element *with_elem= 0;
195
196 for (TABLE_LIST *tbl= tables; tbl != *tables_last; tbl= tbl->next_global)
197 {
198 if (tbl->derived)
199 continue;
200 if (!tbl->db.str && !tbl->with)
201 tbl->with= tbl->select_lex->find_table_def_in_with_clauses(tbl);
202 if (!tbl->with) // no CTE matches table reference tbl
203 {
204 if (only_cte_resolution)
205 continue;
206 if (!tbl->db.str) // no database specified in table reference tbl
207 {
208 if (!thd->db.str) // no default database is set
209 {
210 my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
211 return true;
212 }
213 if (copy_db_to(&tbl->db))
214 return true;
215 if (!(tbl->table_options & TL_OPTION_ALIAS))
216 tbl->mdl_request.init(MDL_key::TABLE, tbl->db.str,
217 tbl->table_name.str,
218 tbl->mdl_type, MDL_TRANSACTION);
219 tbl->mdl_request.set_type((tbl->lock_type >= TL_WRITE_ALLOW_WRITE) ?
220 MDL_SHARED_WRITE : MDL_SHARED_READ);
221 }
222 continue;
223 }
224 with_elem= tbl->with;
225 if (tbl->is_recursive_with_table() &&
226 !tbl->is_with_table_recursive_reference())
227 {
228 tbl->with->rec_outer_references++;
229 while ((with_elem= with_elem->get_next_mutually_recursive()) !=
230 tbl->with)
231 with_elem->rec_outer_references++;
232 }
233 if (!with_elem->is_used_in_query || with_elem->is_recursive)
234 {
235 tbl->derived= with_elem->spec;
236 if (tbl->derived != tbl->select_lex->master_unit() &&
237 !with_elem->is_recursive &&
238 !tbl->is_with_table_recursive_reference())
239 {
240 tbl->derived->move_as_slave(tbl->select_lex);
241 }
242 with_elem->is_used_in_query= true;
243 }
244 else
245 {
246 if (!(tbl->derived= tbl->with->clone_parsed_spec(thd->lex, tbl)))
247 return true;
248 }
249 tbl->db.str= empty_c_string;
250 tbl->db.length= 0;
251 tbl->schema_table= 0;
252 if (tbl->derived)
253 {
254 tbl->derived->first_select()->set_linkage(DERIVED_TABLE_TYPE);
255 tbl->select_lex->add_statistics(tbl->derived);
256 }
257 if (tbl->with->is_recursive && tbl->is_with_table_recursive_reference())
258 continue;
259 with_elem->inc_references();
260 }
261 return false;
262 }
263
264
265 /**
266 @brief
267 Find out dependencies between CTEs, resolve references to them
268
269 @details
270 The function can be called in two modes. With this->with_cte_resolution
271 set to false the function only finds out all dependencies between CTEs
272 used in a query expression with a WITH clause whose parsing has been
273 just finished. Based on these dependencies recursive CTEs are detected.
274 If this->with_cte_resolution is set to true the function additionally
275 resolves all references to CTE occurred in this query expression.
276
277 @retval
278 true on failure
279 false on success
280 */
281
282 bool
check_cte_dependencies_and_resolve_references()283 LEX::check_cte_dependencies_and_resolve_references()
284 {
285 if (check_dependencies_in_with_clauses())
286 return true;
287 if (!with_cte_resolution)
288 return false;
289 if (resolve_references_to_cte(query_tables, query_tables_last))
290 return true;
291 if (resolve_references_to_cte_in_hanging_cte())
292 return true;
293 return false;
294 }
295
296
297 /**
298 @brief
299 Check dependencies between tables defined in this with clause
300
301 @details
302 The method performs the following for this with clause:
303 - checks that there are no definitions of the tables with the same name
304 - for each table T defined in this with clause looks for the tables
305 from the same with clause that are used in the query that specifies T
306 and set the dependencies of T on these tables in a bitmap.
307 - builds the transitive closure of the above direct dependencies
308 to find out all recursive definitions.
309
310 @retval
311 true if an error is reported
312 false otherwise
313 */
314
check_dependencies()315 bool With_clause::check_dependencies()
316 {
317 if (dependencies_are_checked)
318 return false;
319 /*
320 Look for for definitions with the same query name.
321 When found report an error and return true immediately.
322 For each table T defined in this with clause look for all other tables
323 from the same with clause that are used in the specification of T.
324 For each such table set the dependency bit in the dependency map of
325 the with element for T.
326 */
327 for (With_element *with_elem= with_list.first;
328 with_elem;
329 with_elem= with_elem->next)
330 {
331 for (With_element *elem= with_list.first;
332 elem != with_elem;
333 elem= elem->next)
334 {
335 if (lex_string_cmp(system_charset_info, with_elem->get_name(),
336 elem->get_name()) == 0)
337 {
338 my_error(ER_DUP_QUERY_NAME, MYF(0),
339 with_elem->get_name_str());
340 return true;
341 }
342 }
343 if (with_elem->check_dependencies_in_spec())
344 return true;
345 }
346 /* Build the transitive closure of the direct dependencies found above */
347 for (With_element *with_elem= with_list.first;
348 with_elem;
349 with_elem= with_elem->next)
350 with_elem->derived_dep_map= with_elem->base_dep_map;
351 for (With_element *with_elem= with_list.first;
352 with_elem;
353 with_elem= with_elem->next)
354 {
355 table_map with_elem_map= with_elem->get_elem_map();
356 for (With_element *elem= with_list.first; elem; elem= elem->next)
357 {
358 if (elem->derived_dep_map & with_elem_map)
359 elem->derived_dep_map |= with_elem->derived_dep_map;
360 }
361 }
362
363 /*
364 Mark those elements where tables are defined with direct or indirect
365 recursion.
366 */
367 for (With_element *with_elem= with_list.first;
368 with_elem;
369 with_elem= with_elem->next)
370 {
371 if (with_elem->derived_dep_map & with_elem->get_elem_map())
372 with_elem->is_recursive= true;
373 }
374
375 dependencies_are_checked= true;
376 return false;
377 }
378
379
380 /*
381 This structure describes an element of the stack of embedded units.
382 The stack is used when looking for a definition of a table in
383 with clauses. The definition can be found only in the scopes
384 of the with clauses attached to the units from the stack.
385 The with clauses are looked through from starting from the top
386 element of the stack.
387 */
388
389 struct st_unit_ctxt_elem
390 {
391 st_unit_ctxt_elem *prev; // the previous element of the stack
392 st_select_lex_unit *unit;
393 };
394
395
396 /**
397 @brief
398 Find the dependencies of this element on its siblings in its specification
399
400 @details
401 For each table reference ref(T) from the FROM list of every select sl
402 immediately contained in the specification query of this element this
403 method searches for the definition of T in the the with clause which
404 this element belongs to. If such definition is found then the dependency
405 on it is set in sl->with_dep and in this->base_dep_map.
406 */
407
check_dependencies_in_spec()408 bool With_element::check_dependencies_in_spec()
409 {
410 for (st_select_lex *sl= spec->first_select(); sl; sl= sl->next_select())
411 {
412 st_unit_ctxt_elem ctxt0= {NULL, owner->owner};
413 st_unit_ctxt_elem ctxt1= {&ctxt0, spec};
414 check_dependencies_in_select(sl, &ctxt1, false, &sl->with_dep);
415 base_dep_map|= sl->with_dep;
416 }
417 return false;
418 }
419
420
421 /**
422 @brief
423 Search for the definition of a table among the elements of this with clause
424
425 @param table The reference to the table that is looked for
426 @param barrier The barrier with element for the search
427
428 @details
429 The function looks through the elements of this with clause trying to find
430 the definition of the given table. When it encounters the element with
431 the same query name as the table's name it returns this element. If no
432 such definitions are found the function returns NULL.
433
434 @retval
435 found with element if the search succeeded
436 NULL - otherwise
437 */
438
find_table_def(TABLE_LIST * table,With_element * barrier)439 With_element *With_clause::find_table_def(TABLE_LIST *table,
440 With_element *barrier)
441 {
442 for (With_element *with_elem= with_list.first;
443 with_elem != barrier;
444 with_elem= with_elem->next)
445 {
446 if (my_strcasecmp(system_charset_info, with_elem->get_name_str(),
447 table->table_name.str) == 0 &&
448 !table->is_fqtn)
449 {
450 table->set_derived();
451 with_elem->referenced= true;
452 return with_elem;
453 }
454 }
455 return NULL;
456 }
457
458
459 /**
460 @brief
461 Search for the definition of a table in with clauses
462
463 @param tbl The reference to the table that is looked for
464 @param ctxt The context describing in what with clauses of the upper
465 levels the table has to be searched for.
466
467 @details
468 The function looks for the definition of the table tbl in the definitions
469 of the with clauses from the upper levels specified by the parameter ctxt.
470 When it encounters the element with the same query name as the table's name
471 it returns this element. If no such definitions are found the function
472 returns NULL.
473
474 @retval
475 found with element if the search succeeded
476 NULL - otherwise
477 */
478
find_table_def_in_with_clauses(TABLE_LIST * tbl,st_unit_ctxt_elem * ctxt)479 With_element *find_table_def_in_with_clauses(TABLE_LIST *tbl,
480 st_unit_ctxt_elem *ctxt)
481 {
482 With_element *barrier= NULL;
483 for (st_unit_ctxt_elem *unit_ctxt_elem= ctxt;
484 unit_ctxt_elem;
485 unit_ctxt_elem= unit_ctxt_elem->prev)
486 {
487 st_select_lex_unit *unit= unit_ctxt_elem->unit;
488 With_clause *with_clause= unit->with_clause;
489 if (with_clause &&
490 (tbl->with= with_clause->find_table_def(tbl, barrier)))
491 return tbl->with;
492 barrier= NULL;
493 if (unit->with_element && !unit->with_element->get_owner()->with_recursive)
494 {
495 /*
496 This unit is the specification if the with element unit->with_element.
497 The with element belongs to a with clause without the specifier RECURSIVE.
498 So when searching for the matching definition of tbl this with clause must
499 be looked up to this with element
500 */
501 barrier= unit->with_element;
502 }
503 }
504 return NULL;
505 }
506
507
508 /**
509 @brief
510 Find the dependencies of this element on its siblings in a select
511
512 @param sl The select where to look for the dependencies
513 @param ctxt The structure specifying the scope of the definitions
514 of the with elements of the upper levels
515 @param in_sbq if true mark dependencies found in subqueries in
516 this->sq_dep_map
517 @param dep_map IN/OUT The bit where to mark the found dependencies
518
519 @details
520 For each table reference ref(T) from the FROM list of the select sl
521 the method searches in with clauses for the definition of the table T.
522 If the found definition belongs to the same with clause as this with
523 element then the method set dependency on T in the in/out parameter
524 dep_map, add if required - in this->sq_dep_map.
525 The parameter ctxt describes the proper context for the search
526 of the definition of T.
527 */
528
check_dependencies_in_select(st_select_lex * sl,st_unit_ctxt_elem * ctxt,bool in_subq,table_map * dep_map)529 void With_element::check_dependencies_in_select(st_select_lex *sl,
530 st_unit_ctxt_elem *ctxt,
531 bool in_subq,
532 table_map *dep_map)
533 {
534 With_clause *with_clause= sl->get_with_clause();
535 for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local)
536 {
537 if (tbl->derived || tbl->nested_join)
538 continue;
539 tbl->with_internal_reference_map= 0;
540 /*
541 If there is a with clause attached to the unit containing sl
542 look first for the definition of tbl in this with clause.
543 If such definition is not found there look in the with
544 clauses of the upper levels.
545 If the definition of tbl is found somewhere in with clauses
546 then tbl->with is set to point to this definition
547 */
548 if (with_clause && !tbl->with)
549 tbl->with= with_clause->find_table_def(tbl, NULL);
550 if (!tbl->with)
551 tbl->with= find_table_def_in_with_clauses(tbl, ctxt);
552
553 if (tbl->with && tbl->with->owner== this->owner)
554 {
555 /*
556 The found definition T of tbl belongs to the same
557 with clause as this with element. In this case:
558 - set the dependence on T in the bitmap dep_map
559 - set tbl->with_internal_reference_map with
560 the bitmap for this definition
561 - set the dependence on T in the bitmap this->sq_dep_map
562 if needed
563 */
564 *dep_map|= tbl->with->get_elem_map();
565 tbl->with_internal_reference_map= get_elem_map();
566 if (in_subq)
567 sq_dep_map|= tbl->with->get_elem_map();
568 else
569 top_level_dep_map|= tbl->with->get_elem_map();
570 }
571 }
572 /* Now look for the dependencies in the subqueries of sl */
573 st_select_lex_unit *inner_unit= sl->first_inner_unit();
574 for (; inner_unit; inner_unit= inner_unit->next_unit())
575 {
576 if (!inner_unit->with_element)
577 check_dependencies_in_unit(inner_unit, ctxt, in_subq, dep_map);
578 }
579 }
580
581
582 /**
583 @brief
584 Find a recursive reference to this with element in subqueries of a select
585
586 @param sel The select in whose subqueries the reference
587 to be looked for
588
589 @details
590 The function looks for a recursive reference to this with element in
591 subqueries of select sl. When the first such reference is found
592 it is returned as the result.
593 The function assumes that the identification of all CTE references
594 has been performed earlier.
595
596 @retval
597 Pointer to the found recursive reference if the search succeeded
598 NULL - otherwise
599 */
600
find_first_sq_rec_ref_in_select(st_select_lex * sel)601 TABLE_LIST *With_element::find_first_sq_rec_ref_in_select(st_select_lex *sel)
602 {
603 TABLE_LIST *rec_ref= NULL;
604 st_select_lex_unit *inner_unit= sel->first_inner_unit();
605 for (; inner_unit; inner_unit= inner_unit->next_unit())
606 {
607 st_select_lex *sl= inner_unit->first_select();
608 for (; sl; sl= sl->next_select())
609 {
610 for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local)
611 {
612 if (tbl->derived || tbl->nested_join)
613 continue;
614 if (tbl->with && tbl->with->owner== this->owner &&
615 (tbl->with_internal_reference_map & mutually_recursive))
616 {
617 rec_ref= tbl;
618 return rec_ref;
619 }
620 }
621 if ((rec_ref= find_first_sq_rec_ref_in_select(sl)))
622 return rec_ref;
623 }
624 }
625 return 0;
626 }
627
628
629 /**
630 @brief
631 Find the dependencies of this element on its siblings in a unit
632
633 @param unit The unit where to look for the dependencies
634 @param ctxt The structure specifying the scope of the definitions
635 of the with elements of the upper levels
636 @param in_sbq if true mark dependencies found in subqueries in
637 this->sq_dep_map
638 @param dep_map IN/OUT The bit where to mark the found dependencies
639
640 @details
641 This method searches in the unit 'unit' for the the references in FROM
642 lists of all selects contained in this unit and in the with clause
643 attached to this unit that refer to definitions of tables from the
644 same with clause as this element.
645 If such definitions are found then the dependencies on them are
646 set in the in/out parameter dep_map and optionally in this->sq_dep_map.
647 The parameter ctxt describes the proper context for the search.
648 */
649
check_dependencies_in_unit(st_select_lex_unit * unit,st_unit_ctxt_elem * ctxt,bool in_subq,table_map * dep_map)650 void With_element::check_dependencies_in_unit(st_select_lex_unit *unit,
651 st_unit_ctxt_elem *ctxt,
652 bool in_subq,
653 table_map *dep_map)
654 {
655 if (unit->with_clause)
656 check_dependencies_in_with_clause(unit->with_clause, ctxt, in_subq, dep_map);
657 in_subq |= unit->item != NULL;
658 st_unit_ctxt_elem unit_ctxt_elem= {ctxt, unit};
659 st_select_lex *sl= unit->first_select();
660 for (; sl; sl= sl->next_select())
661 {
662 check_dependencies_in_select(sl, &unit_ctxt_elem, in_subq, dep_map);
663 }
664 }
665
666
667 /**
668 @brief
669 Find the dependencies of this element on its siblings in a with clause
670
671 @param witt_clause The with clause where to look for the dependencies
672 @param ctxt The structure specifying the scope of the definitions
673 of the with elements of the upper levels
674 @param in_sbq if true mark dependencies found in subqueries in
675 this->sq_dep_map
676 @param dep_map IN/OUT The bit where to mark the found dependencies
677
678 @details
679 This method searches in the with_clause for the the references in FROM
680 lists of all selects contained in the specifications of the with elements
681 from this with_clause that refer to definitions of tables from the
682 same with clause as this element.
683 If such definitions are found then the dependencies on them are
684 set in the in/out parameter dep_map and optionally in this->sq_dep_map.
685 The parameter ctxt describes the proper context for the search.
686 */
687
688 void
check_dependencies_in_with_clause(With_clause * with_clause,st_unit_ctxt_elem * ctxt,bool in_subq,table_map * dep_map)689 With_element::check_dependencies_in_with_clause(With_clause *with_clause,
690 st_unit_ctxt_elem *ctxt,
691 bool in_subq,
692 table_map *dep_map)
693 {
694 for (With_element *with_elem= with_clause->with_list.first;
695 with_elem;
696 with_elem= with_elem->next)
697 {
698 check_dependencies_in_unit(with_elem->spec, ctxt, in_subq, dep_map);
699 }
700 }
701
702
703 /**
704 @brief
705 Find mutually recursive with elements and check that they have ancors
706
707 @details
708 This method performs the following:
709 - for each recursive with element finds all mutually recursive with it
710 - links each group of mutually recursive with elements into a ring chain
711 - checks that every group of mutually recursive with elements contains
712 at least one anchor
713 - checks that after removing any with element with anchor the remaining
714 with elements mutually recursive with the removed one are not recursive
715 anymore
716
717 @retval
718 true if an error is reported
719 false otherwise
720 */
721
check_anchors()722 bool With_clause::check_anchors()
723 {
724 for (With_element *with_elem= with_list.first;
725 with_elem;
726 with_elem= with_elem->next)
727 {
728 if (!with_elem->is_recursive)
729 continue;
730
731 /*
732 It with_elem is recursive with element find all elements mutually recursive
733 with it (any recursive element is mutually recursive with itself). Mark all
734 these elements in the bitmap->mutually_recursive. Also link all these
735 elements into a ring chain.
736 */
737 if (!with_elem->next_mutually_recursive)
738 {
739 With_element *last_mutually_recursive= with_elem;
740 table_map with_elem_dep= with_elem->derived_dep_map;
741 table_map with_elem_map= with_elem->get_elem_map();
742 for (With_element *elem= with_elem; elem; elem= elem->next)
743 {
744 if (!elem->is_recursive)
745 continue;
746
747 if (elem == with_elem ||
748 ((elem->derived_dep_map & with_elem_map) &&
749 (with_elem_dep & elem->get_elem_map())))
750 {
751 elem->next_mutually_recursive= with_elem;
752 last_mutually_recursive->next_mutually_recursive= elem;
753 last_mutually_recursive= elem;
754 with_elem->mutually_recursive|= elem->get_elem_map();
755 }
756 }
757 for (With_element *elem= with_elem->next_mutually_recursive;
758 elem != with_elem;
759 elem= elem->next_mutually_recursive)
760 elem->mutually_recursive= with_elem->mutually_recursive;
761 }
762
763 /*
764 For each select from the specification of 'with_elem' check whether
765 it is an anchor i.e. does not depend on any with elements mutually
766 recursive with 'with_elem".
767 */
768 for (st_select_lex *sl= with_elem->spec->first_select();
769 sl;
770 sl= sl->next_select())
771 {
772 if (with_elem->is_anchor(sl))
773 {
774 with_elem->with_anchor= true;
775 break;
776 }
777 }
778 }
779
780 /*
781 Check that for any group of mutually recursive with elements
782 - there is at least one anchor
783 - after removing any with element with anchor the remaining with elements
784 mutually recursive with the removed one are not recursive anymore
785 */
786 for (With_element *with_elem= with_list.first;
787 with_elem;
788 with_elem= with_elem->next)
789 {
790 if (!with_elem->is_recursive)
791 continue;
792
793 if (!with_elem->with_anchor)
794 {
795 /*
796 Check that the other with elements mutually recursive with 'with_elem'
797 contain at least one anchor.
798 */
799 With_element *elem= with_elem;
800 while ((elem= elem->get_next_mutually_recursive()) != with_elem)
801 {
802 if (elem->with_anchor)
803 break;
804 }
805 if (elem == with_elem)
806 {
807 my_error(ER_RECURSIVE_WITHOUT_ANCHORS, MYF(0),
808 with_elem->get_name_str());
809 return true;
810 }
811 }
812 else
813 {
814 /* 'with_elem' is a with element with an anchor */
815 With_element *elem= with_elem;
816 /*
817 For the other with elements mutually recursive with 'with_elem'
818 set dependency bits between those elements in the field work_dep_map
819 and build transitive closure of these dependencies
820 */
821 while ((elem= elem->get_next_mutually_recursive()) != with_elem)
822 elem->work_dep_map= elem->base_dep_map & elem->mutually_recursive;
823 elem= with_elem;
824 while ((elem= elem->get_next_mutually_recursive()) != with_elem)
825 {
826 table_map elem_map= elem->get_elem_map();
827 With_element *el= with_elem;
828 while ((el= el->get_next_mutually_recursive()) != with_elem)
829 {
830 if (el->work_dep_map & elem_map)
831 el->work_dep_map|= elem->work_dep_map;
832 }
833 }
834 /* If the transitive closure displays any cycle report an arror */
835 elem= with_elem;
836 while ((elem= elem->get_next_mutually_recursive()) != with_elem)
837 {
838 if (elem->work_dep_map & elem->get_elem_map())
839 {
840 my_error(ER_UNACCEPTABLE_MUTUAL_RECURSION, MYF(0),
841 with_elem->get_name_str());
842 return true;
843 }
844 }
845 }
846 }
847
848 return false;
849 }
850
851
852 /**
853 @brief
854 Move anchors at the beginning of the specifications for with elements
855
856 @details
857 This method moves anchors at the beginning of the specifications for
858 all recursive with elements.
859 */
860
move_anchors_ahead()861 void With_clause::move_anchors_ahead()
862 {
863 for (With_element *with_elem= with_list.first;
864 with_elem;
865 with_elem= with_elem->next)
866 {
867 if (with_elem->is_recursive)
868 with_elem->move_anchors_ahead();
869 }
870 }
871
872
873 /**
874 @brief
875 Move anchors at the beginning of the specification of this with element
876
877 @details
878 If the specification of this with element contains anchors the method
879 moves them at the very beginning of the specification.
880 Additionally for the other selects of the specification if none of them
881 contains a recursive reference to this with element or a mutually recursive
882 one the method looks for the first such reference in the first recursive
883 select and set a pointer to it in this->sq_rec_ref.
884 */
885
move_anchors_ahead()886 void With_element::move_anchors_ahead()
887 {
888 st_select_lex *next_sl;
889 st_select_lex *new_pos= spec->first_select();
890 new_pos->set_linkage(UNION_TYPE);
891 for (st_select_lex *sl= new_pos; sl; sl= next_sl)
892 {
893 next_sl= sl->next_select();
894 if (is_anchor(sl))
895 {
896 sl->move_node(new_pos);
897 if (new_pos == spec->first_select())
898 {
899 enum sub_select_type type= new_pos->get_linkage();
900 new_pos->set_linkage(sl->get_linkage());
901 sl->set_linkage(type);
902 new_pos->with_all_modifier= sl->with_all_modifier;
903 sl->with_all_modifier= false;
904 }
905 new_pos= sl->next_select();
906 }
907 else if (!sq_rec_ref && no_rec_ref_on_top_level())
908 {
909 sq_rec_ref= find_first_sq_rec_ref_in_select(sl);
910 DBUG_ASSERT(sq_rec_ref != NULL);
911 }
912 }
913 first_recursive= new_pos;
914 spec->first_select()->set_linkage(DERIVED_TABLE_TYPE);
915 }
916
917
918 /**
919 @brief
920 Perform context analysis for all unreferenced tables defined in with clause
921
922 @param thd The context of the statement containing this with clause
923
924 @details
925 For each unreferenced table T defined in this with clause the method
926 calls the method With_element::prepare_unreferenced that performs
927 context analysis of the element with the definition of T.
928
929 @retval
930 false If context analysis does not report any error
931 true Otherwise
932 */
933
prepare_unreferenced_elements(THD * thd)934 bool With_clause::prepare_unreferenced_elements(THD *thd)
935 {
936 for (With_element *with_elem= with_list.first;
937 with_elem;
938 with_elem= with_elem->next)
939 {
940 if ((with_elem->is_hanging_recursive() || !with_elem->is_referenced()) &&
941 with_elem->prepare_unreferenced(thd))
942 return true;
943 }
944
945 return false;
946 }
947
948
949 /**
950 @brief
951 Save the specification of the given with table as a string
952
953 @param thd The context of the statement containing this with element
954 @param spec_start The beginning of the specification in the input string
955 @param spec_end The end of the specification in the input string
956 @param spec_offset The offset of the specification in the input string
957
958 @details
959 The method creates for a string copy of the specification used in this
960 element. The method is called when the element is parsed. The copy may be
961 used to create clones of the specification whenever they are needed.
962
963 @retval
964 false on success
965 true on failure
966 */
967
set_unparsed_spec(THD * thd,const char * spec_start,const char * spec_end,my_ptrdiff_t spec_offset)968 bool With_element::set_unparsed_spec(THD *thd,
969 const char *spec_start,
970 const char *spec_end,
971 my_ptrdiff_t spec_offset)
972 {
973 stmt_prepare_mode= thd->m_parser_state->m_lip.stmt_prepare_mode;
974 unparsed_spec.length= spec_end - spec_start;
975
976 if (stmt_prepare_mode || !thd->lex->sphead)
977 unparsed_spec.str= spec_start;
978 else
979 unparsed_spec.str= thd->strmake(spec_start, unparsed_spec.length);
980 unparsed_spec_offset= spec_offset;
981
982 if (!unparsed_spec.str)
983 {
984 my_error(ER_OUTOFMEMORY, MYF(ME_FATAL),
985 static_cast<int>(unparsed_spec.length));
986 return true;
987 }
988 return false;
989 }
990
991
992 /**
993 @brief
994 Create a clone of the specification for the given with table
995
996 @param old_lex The LEX structure created for the query or CTE specification
997 where this With_element is defined
998 @param with_table The reference to the table defined in this element for which
999 the clone is created.
1000
1001 @details
1002 The method creates a clone of the specification used in this element.
1003 The clone is created for the given reference to the table defined by
1004 this element.
1005 The clone is created when the string with the specification saved in
1006 unparsed_spec is fed into the parser as an input string. The parsing
1007 this string a unit object representing the specification is built.
1008 A chain of all table references occurred in the specification is also
1009 formed.
1010 The method includes the new unit and its sub-unit into hierarchy of
1011 the units of the main query. I also insert the constructed chain of the
1012 table references into the chain of all table references of the main query.
1013 The method resolves all references to CTE in the clone.
1014
1015 @note
1016 Clones is created only for not first references to tables defined in
1017 the with clause. They are necessary for merged specifications because
1018 the optimizer handles any such specification as independent on the others.
1019 When a table defined in the with clause is materialized in a temporary table
1020 one could do without specification clones. However in this case they
1021 are created as well, because currently different table references to a
1022 the same temporary table cannot share the same definition structure.
1023
1024 @retval
1025 pointer to the built clone if succeeds
1026 NULL - otherwise
1027 */
1028
clone_parsed_spec(LEX * old_lex,TABLE_LIST * with_table)1029 st_select_lex_unit *With_element::clone_parsed_spec(LEX *old_lex,
1030 TABLE_LIST *with_table)
1031 {
1032 THD *thd= old_lex->thd;
1033 LEX *lex;
1034 st_select_lex_unit *res= NULL;
1035
1036 if (!(lex= (LEX*) new(thd->mem_root) st_lex_local))
1037 return res;
1038 thd->lex= lex;
1039
1040 bool parse_status= false;
1041 st_select_lex *with_select;
1042 st_select_lex *last_clone_select;
1043
1044 char save_end= unparsed_spec.str[unparsed_spec.length];
1045 ((char*) &unparsed_spec.str[unparsed_spec.length])[0]= '\0';
1046
1047 lex_start(thd);
1048 lex->clone_spec_offset= unparsed_spec_offset;
1049 lex->with_cte_resolution= true;
1050 /*
1051 There's no need to add SPs/SFs referenced in the clone to the global
1052 list of the SPs/SFs used in the query as they were added when the first
1053 reference to the cloned CTE was parsed. Yet the recursive call of the
1054 parser must to know that they were already included into the list.
1055 */
1056 lex->sroutines= old_lex->sroutines;
1057 lex->sroutines_list_own_last= old_lex->sroutines_list_own_last;
1058 lex->sroutines_list_own_elements= old_lex->sroutines_list_own_elements;
1059
1060 /*
1061 The specification of a CTE is to be parsed as a regular query.
1062 At the very end of the parsing query the function
1063 check_cte_dependencies_and_resolve_references() will be called.
1064 It will check the dependencies between CTEs that are defined
1065 within the query and will resolve CTE references in this query.
1066 If a table reference is not resolved as a CTE reference within
1067 this query it still can be resolved as a reference to a CTE defined
1068 in the same clause as the CTE whose specification is to be parsed
1069 or defined in an embedding CTE definition.
1070
1071 Example:
1072 with
1073 cte1 as ( ... ),
1074 cte2 as ([WITH ...] select ... from cte1 ...)
1075 select ... from cte2 as r, ..., cte2 as s ...
1076
1077 Here the specification of cte2 has be cloned for table reference
1078 with alias s1. The specification contains a reference to cte1
1079 that is defined outside this specification. If the reference to
1080 cte1 cannot be resolved within the specification of cte2 it's
1081 not necessarily has to be a reference to a non-CTE table. That's
1082 why the flag lex->only_cte_resolution has to be set to true
1083 before parsing of the specification of cte2 invoked by this
1084 function starts. Otherwise an mdl_lock would be requested for s
1085 and this would not be correct.
1086 */
1087
1088 lex->only_cte_resolution= true;
1089
1090 lex->stmt_lex= old_lex->stmt_lex ? old_lex->stmt_lex : old_lex;
1091
1092 parse_status= thd->sql_parser(old_lex, lex,
1093 (char*) unparsed_spec.str,
1094 (unsigned int)unparsed_spec.length,
1095 stmt_prepare_mode);
1096
1097 ((char*) &unparsed_spec.str[unparsed_spec.length])[0]= save_end;
1098 with_select= lex->unit.first_select();
1099
1100 if (parse_status)
1101 goto err;
1102
1103 /*
1104 The unit of the specification that just has been parsed is included
1105 as a slave of the select that contained in its from list the table
1106 reference for which the unit has been created.
1107 */
1108 lex->unit.include_down(with_table->select_lex);
1109 lex->unit.set_slave(with_select);
1110 lex->unit.cloned_from= spec;
1111
1112 /*
1113 Now all references to the CTE defined outside of the cloned specification
1114 has to be resolved. Additionally if old_lex->only_cte_resolution == false
1115 for the table references that has not been resolved requests for mdl_locks
1116 has to be set.
1117 */
1118 lex->only_cte_resolution= old_lex->only_cte_resolution;
1119 if (lex->resolve_references_to_cte(lex->query_tables,
1120 lex->query_tables_last))
1121 {
1122 res= NULL;
1123 goto err;
1124 }
1125
1126 /*
1127 The global chain of TABLE_LIST objects created for the specification that
1128 just has been parsed is added to such chain that contains the reference
1129 to the CTE whose specification is parsed right after the TABLE_LIST object
1130 created for the reference.
1131 */
1132 if (lex->query_tables)
1133 {
1134 head->tables_pos.set_start_pos(&with_table->next_global);
1135 head->tables_pos.set_end_pos(lex->query_tables_last);
1136 TABLE_LIST *next_tbl= with_table->next_global;
1137 if (next_tbl)
1138 {
1139 *(lex->query_tables->prev_global= next_tbl->prev_global)=
1140 lex->query_tables;
1141 *(next_tbl->prev_global= lex->query_tables_last)= next_tbl;
1142 }
1143 else
1144 {
1145 *(lex->query_tables->prev_global= old_lex->query_tables_last)=
1146 lex->query_tables;
1147 old_lex->query_tables_last= lex->query_tables_last;
1148 }
1149 }
1150 old_lex->sroutines_list_own_last= lex->sroutines_list_own_last;
1151 old_lex->sroutines_list_own_elements= lex->sroutines_list_own_elements;
1152 res= &lex->unit;
1153 res->with_element= this;
1154
1155 last_clone_select= lex->all_selects_list;
1156 while (last_clone_select->next_select_in_list())
1157 last_clone_select= last_clone_select->next_select_in_list();
1158 old_lex->all_selects_list=
1159 (st_select_lex*) (lex->all_selects_list->
1160 insert_chain_before(
1161 (st_select_lex_node **) &(old_lex->all_selects_list),
1162 last_clone_select));
1163
1164 lex->sphead= NULL; // in order not to delete lex->sphead
1165 lex_end(lex);
1166 err:
1167 thd->lex= old_lex;
1168 return res;
1169 }
1170
1171
1172 /**
1173 @brief
1174 Rename columns of the unit derived from the spec of this with element
1175 @param thd The context of the statement containing the with element
1176 @param unit The specification of the with element or its clone
1177
1178 @details
1179 The method assumes that the parameter unit is either specification itself
1180 of this with element or a clone of this specification. The looks through
1181 the column list in this with element. It reports an error if the cardinality
1182 of this list differs from the cardinality of select lists in 'unit'.
1183 Otherwise it renames the columns of the first select list and sets the flag
1184 unit->column_list_is_processed to true preventing renaming columns for the
1185 second time.
1186
1187 @retval
1188 true if an error was reported
1189 false otherwise
1190 */
1191
1192 bool
rename_columns_of_derived_unit(THD * thd,st_select_lex_unit * unit)1193 With_element::rename_columns_of_derived_unit(THD *thd,
1194 st_select_lex_unit *unit)
1195 {
1196 if (unit->columns_are_renamed)
1197 return false;
1198
1199 st_select_lex *select= unit->first_select();
1200
1201 if (column_list.elements) // The column list is optional
1202 {
1203 List_iterator_fast<Item> it(select->item_list);
1204 List_iterator_fast<LEX_CSTRING> nm(column_list);
1205 Item *item;
1206 LEX_CSTRING *name;
1207
1208 if (column_list.elements != select->item_list.elements)
1209 {
1210 my_error(ER_WITH_COL_WRONG_LIST, MYF(0));
1211 return true;
1212 }
1213
1214 Query_arena *arena, backup;
1215 arena= thd->activate_stmt_arena_if_needed(&backup);
1216
1217 /* Rename the columns of the first select in the unit */
1218 while ((item= it++, name= nm++))
1219 {
1220 item->set_name(thd, name->str, (uint) name->length, system_charset_info);
1221 item->is_autogenerated_name= false;
1222 }
1223
1224 if (arena)
1225 thd->restore_active_arena(arena, &backup);
1226 }
1227 else
1228 make_valid_column_names(thd, select->item_list);
1229
1230 unit->columns_are_renamed= true;
1231
1232 return false;
1233 }
1234
1235
1236 /**
1237 @brief
1238 Perform context analysis the definition of an unreferenced table
1239
1240 @param thd The context of the statement containing this with element
1241
1242 @details
1243 The method assumes that this with element contains the definition
1244 of a table that is not used anywhere. In this case one has to check
1245 that context conditions are met.
1246
1247 @retval
1248 true if an error was reported
1249 false otherwise
1250 */
1251
prepare_unreferenced(THD * thd)1252 bool With_element::prepare_unreferenced(THD *thd)
1253 {
1254 bool rc= false;
1255 st_select_lex *first_sl= spec->first_select();
1256
1257 /* Prevent name resolution for field references out of with elements */
1258 for (st_select_lex *sl= first_sl;
1259 sl;
1260 sl= sl->next_select())
1261 sl->context.outer_context= 0;
1262
1263 thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
1264 if (!spec->prepared &&
1265 (spec->prepare(spec->derived, 0, 0) ||
1266 rename_columns_of_derived_unit(thd, spec) ||
1267 check_duplicate_names(thd, first_sl->item_list, 1)))
1268 rc= true;
1269
1270 thd->lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED;
1271 return rc;
1272 }
1273
1274
is_anchor(st_select_lex * sel)1275 bool With_element::is_anchor(st_select_lex *sel)
1276 {
1277 return !(mutually_recursive & sel->with_dep);
1278 }
1279
1280
1281 /**
1282 @brief
1283 Search for the definition of the given table referred in this select node
1284
1285 @param table reference to the table whose definition is searched for
1286
1287 @details
1288 The method looks for the definition of the table whose reference is occurred
1289 in the FROM list of this select node. First it searches for it in the
1290 with clause attached to the unit this select node belongs to. If such a
1291 definition is not found then the embedding units are looked through.
1292
1293 @retval
1294 pointer to the found definition if the search has been successful
1295 NULL - otherwise
1296 */
1297
find_table_def_in_with_clauses(TABLE_LIST * table)1298 With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table)
1299 {
1300 With_element *found= NULL;
1301 With_clause *containing_with_clause= NULL;
1302 st_select_lex_unit *master_unit;
1303 st_select_lex *outer_sl;
1304 for (st_select_lex *sl= this; sl; sl= outer_sl)
1305 {
1306 /*
1307 If sl->master_unit() is the spec of a with element then the search for
1308 a definition was already done by With_element::check_dependencies_in_spec
1309 and it was unsuccesful. Yet for units cloned from the spec it has not
1310 been done yet.
1311 */
1312 With_clause *attached_with_clause= sl->get_with_clause();
1313 if (attached_with_clause &&
1314 attached_with_clause != containing_with_clause &&
1315 (found= attached_with_clause->find_table_def(table, NULL)))
1316 break;
1317 master_unit= sl->master_unit();
1318 outer_sl= master_unit->outer_select();
1319 With_element *with_elem= sl->get_with_element();
1320 if (with_elem)
1321 {
1322 containing_with_clause= with_elem->get_owner();
1323 With_element *barrier= containing_with_clause->with_recursive ?
1324 NULL : with_elem;
1325 if ((found= containing_with_clause->find_table_def(table, barrier)))
1326 break;
1327 if (outer_sl && !outer_sl->get_with_element())
1328 break;
1329 }
1330 /* Do not look for the table's definition beyond the scope of the view */
1331 if (master_unit->is_view)
1332 break;
1333 }
1334 return found;
1335 }
1336
1337
is_recursive_with_table()1338 bool TABLE_LIST::is_recursive_with_table()
1339 {
1340 return with && with->is_recursive;
1341 }
1342
1343
1344 /*
1345 A reference to a with table T is recursive if it occurs somewhere
1346 in the query specifying T or in the query specifying one of the tables
1347 mutually recursive with T.
1348 */
1349
is_with_table_recursive_reference()1350 bool TABLE_LIST::is_with_table_recursive_reference()
1351 {
1352 return (with_internal_reference_map &&
1353 (with->get_mutually_recursive() & with_internal_reference_map));
1354 }
1355
1356
1357 /*
1358 Specifications of with tables with recursive table references
1359 in non-mergeable derived tables are not allowed in this
1360 implementation.
1361 */
1362
1363
1364 /*
1365 We say that the specification of a with table T is restricted
1366 if all below is true.
1367 1. Any immediate select of the specification contains at most one
1368 recursive table reference taking into account table references
1369 from mergeable derived tables.
1370 2. Any recursive table reference is not an inner operand of an
1371 outer join operation used in an immediate select of the
1372 specification.
1373 3. Any immediate select from the specification of T does not
1374 contain aggregate functions.
1375 4. The specification of T does not contain recursive table references.
1376
1377 If the specification of T is not restricted we call the corresponding
1378 with element unrestricted.
1379
1380 The SQL standards allows only with elements with restricted specification.
1381 By default we comply with the standards here.
1382
1383 Yet we allow unrestricted specification if the status variable
1384 'standards_compliant_cte' set to 'off'(0).
1385 */
1386
1387
1388 /**
1389 @brief
1390 Check if this select makes the including specification unrestricted
1391
1392 @param
1393 only_standards_compliant true if the system variable
1394 'standards_compliant_cte' is set to 'on'
1395 @details
1396 This method checks whether the conditions 1-4 (see the comment above)
1397 are satisfied for this select. If not then mark this element as
1398 unrestricted and report an error if 'only_standards_compliant' is true.
1399
1400 @retval
1401 true if an error is reported
1402 false otherwise
1403 */
1404
check_unrestricted_recursive(bool only_standard_compliant)1405 bool st_select_lex::check_unrestricted_recursive(bool only_standard_compliant)
1406 {
1407 With_element *with_elem= get_with_element();
1408 if (!with_elem ||!with_elem->is_recursive)
1409 {
1410 /*
1411 If this select is not from the specifiocation of a with elememt or
1412 if this not a recursive with element then there is nothing to check.
1413 */
1414 return false;
1415 }
1416
1417 /* Check conditions 1-2 for restricted specification*/
1418 table_map unrestricted= 0;
1419 table_map encountered= 0;
1420 if (with_elem->check_unrestricted_recursive(this,
1421 unrestricted,
1422 encountered))
1423 return true;
1424 with_elem->get_owner()->add_unrestricted(unrestricted);
1425
1426
1427 /* Check conditions 3-4 for restricted specification*/
1428 if ((with_sum_func && !with_elem->is_anchor(this)) ||
1429 (with_elem->contains_sq_with_recursive_reference()))
1430 with_elem->get_owner()->add_unrestricted(
1431 with_elem->get_mutually_recursive());
1432
1433 /* Report an error on unrestricted specification if this is required */
1434 if (only_standard_compliant && with_elem->is_unrestricted())
1435 {
1436 my_error(ER_NOT_STANDARD_COMPLIANT_RECURSIVE,
1437 MYF(0), with_elem->get_name_str());
1438 return true;
1439 }
1440
1441 return false;
1442 }
1443
1444
1445 /**
1446 @brief
1447 Check if a select from the spec of this with element is partially restricted
1448
1449 @param
1450 sel select from the specification of this element where to check
1451 whether conditions 1-2 are satisfied
1452 unrestricted IN/OUT bitmap where to mark unrestricted specs
1453 encountered IN/OUT bitmap where to mark encountered recursive references
1454 @details
1455 This method checks whether the conditions 1-2 (see the comment above)
1456 are satisfied for the select sel.
1457 This method is called recursively for derived tables.
1458
1459 @retval
1460 true if an error is reported
1461 false otherwise
1462 */
1463
check_unrestricted_recursive(st_select_lex * sel,table_map & unrestricted,table_map & encountered)1464 bool With_element::check_unrestricted_recursive(st_select_lex *sel,
1465 table_map &unrestricted,
1466 table_map &encountered)
1467 {
1468 /* Check conditions 1 for restricted specification*/
1469 List_iterator<TABLE_LIST> ti(sel->leaf_tables);
1470 TABLE_LIST *tbl;
1471 while ((tbl= ti++))
1472 {
1473 st_select_lex_unit *unit= tbl->get_unit();
1474 if (unit)
1475 {
1476 if(!tbl->is_with_table())
1477 {
1478 if (check_unrestricted_recursive(unit->first_select(),
1479 unrestricted,
1480 encountered))
1481 return true;
1482 }
1483 if (!(tbl->is_recursive_with_table() && unit->with_element->owner == owner))
1484 continue;
1485 With_element *with_elem= unit->with_element;
1486 if (encountered & with_elem->get_elem_map())
1487 unrestricted|= with_elem->mutually_recursive;
1488 else if (with_elem ==this)
1489 encountered|= with_elem->get_elem_map();
1490 }
1491 }
1492 for (With_element *with_elem= owner->with_list.first;
1493 with_elem;
1494 with_elem= with_elem->next)
1495 {
1496 if (!with_elem->is_recursive && (unrestricted & with_elem->get_elem_map()))
1497 continue;
1498 if (encountered & with_elem->get_elem_map())
1499 {
1500 uint cnt= 0;
1501 table_map encountered_mr= encountered & with_elem->mutually_recursive;
1502 for (table_map map= encountered_mr >> with_elem->number;
1503 map != 0;
1504 map>>= 1)
1505 {
1506 if (map & 1)
1507 {
1508 if (cnt)
1509 {
1510 unrestricted|= with_elem->mutually_recursive;
1511 break;
1512 }
1513 else
1514 cnt++;
1515 }
1516 }
1517 }
1518 }
1519
1520
1521 /* Check conditions 2 for restricted specification*/
1522 ti.rewind();
1523 while ((tbl= ti++))
1524 {
1525 if (!tbl->is_with_table_recursive_reference())
1526 continue;
1527 for (TABLE_LIST *tab= tbl; tab; tab= tab->embedding)
1528 {
1529 if (tab->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT))
1530 {
1531 unrestricted|= mutually_recursive;
1532 break;
1533 }
1534 }
1535 }
1536 return false;
1537 }
1538
1539
1540 /**
1541 @brief
1542 Check subqueries with recursive table references from FROM list of this select
1543
1544 @details
1545 For each recursive table reference from the FROM list of this select
1546 this method checks:
1547 - whether this reference is within a materialized derived table and
1548 if so it report an error
1549 - whether this reference is within a subquery and if so it set a flag
1550 in this subquery that disallows some optimization strategies for
1551 this subquery.
1552
1553 @retval
1554 true if an error is reported
1555 false otherwise
1556 */
1557
check_subqueries_with_recursive_references()1558 bool st_select_lex::check_subqueries_with_recursive_references()
1559 {
1560 List_iterator<TABLE_LIST> ti(leaf_tables);
1561 TABLE_LIST *tbl;
1562 while ((tbl= ti++))
1563 {
1564 if (!(tbl->is_with_table_recursive_reference()))
1565 continue;
1566 With_element *rec_elem= tbl->with;
1567 st_select_lex_unit *sl_master;
1568 for (st_select_lex *sl= this; sl; sl= sl_master->outer_select())
1569 {
1570 sl_master= sl->master_unit();
1571 if (sl_master->with_element &&
1572 sl_master->with_element->get_owner() == rec_elem->get_owner())
1573 break;
1574 sl->uncacheable|= UNCACHEABLE_DEPENDENT;
1575 sl_master->uncacheable|= UNCACHEABLE_DEPENDENT;
1576 if (sl_master->derived)
1577 sl_master->derived->register_as_derived_with_rec_ref(rec_elem);
1578 if (sl_master->item)
1579 {
1580 Item_subselect *subq= (Item_subselect *) (sl_master->item);
1581 subq->register_as_with_rec_ref(rec_elem);
1582 }
1583 }
1584 }
1585 return false;
1586 }
1587
1588
1589 /**
1590 @brief
1591 Print this with clause
1592
1593 @param str Where to print to
1594 @param query_type The mode of printing
1595
1596 @details
1597 The method prints a string representation of this clause in the
1598 string str. The parameter query_type specifies the mode of printing.
1599 */
1600
print(String * str,enum_query_type query_type)1601 void With_clause::print(String *str, enum_query_type query_type)
1602 {
1603 /*
1604 Any with clause contains just definitions of CTE tables.
1605 No data expansion is applied to these definitions.
1606 */
1607 query_type= (enum_query_type) (query_type | QT_NO_DATA_EXPANSION);
1608
1609 str->append(STRING_WITH_LEN("with "));
1610 if (with_recursive)
1611 str->append(STRING_WITH_LEN("recursive "));
1612 for (With_element *with_elem= with_list.first;
1613 with_elem;
1614 with_elem= with_elem->next)
1615 {
1616 if (with_elem != with_list.first)
1617 str->append(", ");
1618 with_elem->print(str, query_type);
1619 }
1620 }
1621
1622
1623 /**
1624 @brief
1625 Print this with element
1626
1627 @param str Where to print to
1628 @param query_type The mode of printing
1629
1630 @details
1631 The method prints a string representation of this with element in the
1632 string str. The parameter query_type specifies the mode of printing.
1633 */
1634
print(String * str,enum_query_type query_type)1635 void With_element::print(String *str, enum_query_type query_type)
1636 {
1637 str->append(get_name());
1638 if (column_list.elements)
1639 {
1640 List_iterator_fast<LEX_CSTRING> li(column_list);
1641 str->append('(');
1642 for (LEX_CSTRING *col_name= li++; ; )
1643 {
1644 str->append(col_name);
1645 col_name= li++;
1646 if (!col_name)
1647 {
1648 str->append(')');
1649 break;
1650 }
1651 str->append(',');
1652 }
1653 }
1654 str->append(STRING_WITH_LEN(" as "));
1655 str->append('(');
1656 spec->print(str, query_type);
1657 str->append(')');
1658 }
1659
1660
instantiate_tmp_tables()1661 bool With_element::instantiate_tmp_tables()
1662 {
1663 List_iterator_fast<TABLE_LIST> li(rec_result->rec_table_refs);
1664 TABLE_LIST *rec_tbl;
1665 while ((rec_tbl= li++))
1666 {
1667 TABLE *rec_table= rec_tbl->table;
1668 if (!rec_table->is_created() &&
1669 instantiate_tmp_table(rec_table,
1670 rec_table->s->key_info,
1671 rec_result->tmp_table_param.start_recinfo,
1672 &rec_result->tmp_table_param.recinfo,
1673 0))
1674 return true;
1675
1676 rec_table->file->extra(HA_EXTRA_WRITE_CACHE);
1677 rec_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
1678 }
1679 return false;
1680 }
1681
1682