1 | /* |
2 | Copyright (c) 2002, 2011, Oracle and/or its affiliates. |
3 | Copyright (c) 2010, 2015, MariaDB |
4 | |
5 | This program is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; version 2 of the License. |
8 | |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
17 | |
18 | |
19 | /* |
20 | Derived tables |
21 | These were introduced by Sinisa <sinisa@mysql.com> |
22 | */ |
23 | |
24 | |
25 | #include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ |
26 | #include "sql_priv.h" |
27 | #include "unireg.h" |
28 | #include "sql_derived.h" |
29 | #include "sql_select.h" |
30 | #include "sql_base.h" |
31 | #include "sql_view.h" // check_duplicate_names |
32 | #include "sql_acl.h" // SELECT_ACL |
33 | #include "sql_class.h" |
34 | #include "sql_cte.h" |
35 | |
36 | typedef bool (*dt_processor)(THD *thd, LEX *lex, TABLE_LIST *derived); |
37 | |
38 | bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived); |
39 | bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived); |
40 | bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived); |
41 | bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived); |
42 | bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived); |
43 | bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived); |
44 | bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived); |
45 | bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived); |
46 | |
47 | |
48 | dt_processor processors[]= |
49 | { |
50 | &mysql_derived_init, |
51 | &mysql_derived_prepare, |
52 | &mysql_derived_optimize, |
53 | &mysql_derived_merge, |
54 | &mysql_derived_merge_for_insert, |
55 | &mysql_derived_create, |
56 | &mysql_derived_fill, |
57 | &mysql_derived_reinit, |
58 | }; |
59 | |
60 | /* |
61 | Run specified phases on all derived tables/views in given LEX. |
62 | |
63 | @param lex LEX for this thread |
64 | @param phases phases to run derived tables/views through |
65 | |
66 | @return FALSE OK |
67 | @return TRUE Error |
68 | */ |
69 | bool |
70 | mysql_handle_derived(LEX *lex, uint phases) |
71 | { |
72 | bool res= FALSE; |
73 | THD *thd= lex->thd; |
74 | DBUG_ENTER("mysql_handle_derived" ); |
75 | DBUG_PRINT("enter" , ("phases: 0x%x" , phases)); |
76 | if (!lex->derived_tables) |
77 | DBUG_RETURN(FALSE); |
78 | |
79 | lex->thd->derived_tables_processing= TRUE; |
80 | |
81 | for (uint phase= 0; phase < DT_PHASES && !res; phase++) |
82 | { |
83 | uint phase_flag= DT_INIT << phase; |
84 | if (phase_flag > phases) |
85 | break; |
86 | if (!(phases & phase_flag)) |
87 | continue; |
88 | if (phase_flag >= DT_CREATE && !thd->fill_derived_tables()) |
89 | break; |
90 | |
91 | for (SELECT_LEX *sl= lex->all_selects_list; |
92 | sl && !res; |
93 | sl= sl->next_select_in_list()) |
94 | { |
95 | TABLE_LIST *cursor= sl->get_table_list(); |
96 | /* |
97 | DT_MERGE_FOR_INSERT is not needed for views/derived tables inside |
98 | subqueries. Views and derived tables of subqueries should be |
99 | processed normally. |
100 | */ |
101 | if (phases == DT_MERGE_FOR_INSERT && |
102 | cursor && cursor->top_table()->select_lex != &lex->select_lex) |
103 | continue; |
104 | for (; |
105 | cursor && !res; |
106 | cursor= cursor->next_local) |
107 | { |
108 | if (!cursor->is_view_or_derived() && phases == DT_MERGE_FOR_INSERT) |
109 | continue; |
110 | uint8 allowed_phases= (cursor->is_merged_derived() ? DT_PHASES_MERGE : |
111 | DT_PHASES_MATERIALIZE | DT_MERGE_FOR_INSERT); |
112 | /* |
113 | Skip derived tables to which the phase isn't applicable. |
114 | TODO: mark derived at the parse time, later set it's type |
115 | (merged or materialized) |
116 | */ |
117 | if ((phase_flag != DT_PREPARE && !(allowed_phases & phase_flag)) || |
118 | (cursor->merged_for_insert && phase_flag != DT_REINIT && |
119 | phase_flag != DT_PREPARE)) |
120 | continue; |
121 | res= (*processors[phase])(lex->thd, lex, cursor); |
122 | } |
123 | if (lex->describe) |
124 | { |
125 | /* |
126 | Force join->join_tmp creation, because we will use this JOIN |
127 | twice for EXPLAIN and we have to have unchanged join for EXPLAINing |
128 | */ |
129 | sl->uncacheable|= UNCACHEABLE_EXPLAIN; |
130 | sl->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN; |
131 | } |
132 | } |
133 | } |
134 | lex->thd->derived_tables_processing= FALSE; |
135 | DBUG_RETURN(res); |
136 | } |
137 | |
138 | /* |
139 | Run through phases for the given derived table/view. |
140 | |
141 | @param lex LEX for this thread |
142 | @param derived the derived table to handle |
143 | @param phase_map phases to process tables/views through |
144 | |
145 | @details |
146 | |
147 | This function process the derived table (view) 'derived' to performs all |
148 | actions that are to be done on the table at the phases specified by |
149 | phase_map. The processing is carried out starting from the actions |
150 | performed at the earlier phases (those having smaller ordinal numbers). |
151 | |
152 | @note |
153 | This function runs specified phases of the derived tables handling on the |
154 | given derived table/view. This function is used in the chain of calls: |
155 | SELECT_LEX::handle_derived -> |
156 | TABLE_LIST::handle_derived -> |
157 | mysql_handle_single_derived |
158 | This chain of calls implements the bottom-up handling of the derived tables: |
159 | i.e. most inner derived tables/views are handled first. This order is |
160 | required for the all phases except the merge and the create steps. |
161 | For the sake of code simplicity this order is kept for all phases. |
162 | |
163 | @return FALSE ok |
164 | @return TRUE error |
165 | */ |
166 | |
167 | bool |
168 | mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) |
169 | { |
170 | bool res= FALSE; |
171 | THD *thd= lex->thd; |
172 | uint8 allowed_phases= (derived->is_merged_derived() ? DT_PHASES_MERGE : |
173 | DT_PHASES_MATERIALIZE); |
174 | DBUG_ENTER("mysql_handle_single_derived" ); |
175 | DBUG_PRINT("enter" , ("phases: 0x%x allowed: 0x%x alias: '%s'" , |
176 | phases, allowed_phases, |
177 | (derived->alias.str ? derived->alias.str : "<NULL>" ))); |
178 | if (!lex->derived_tables) |
179 | DBUG_RETURN(FALSE); |
180 | |
181 | lex->thd->derived_tables_processing= TRUE; |
182 | |
183 | for (uint phase= 0; phase < DT_PHASES; phase++) |
184 | { |
185 | uint phase_flag= DT_INIT << phase; |
186 | if (phase_flag > phases) |
187 | break; |
188 | if (!(phases & phase_flag)) |
189 | continue; |
190 | /* Skip derived tables to which the phase isn't applicable. */ |
191 | if (phase_flag != DT_PREPARE && |
192 | !(allowed_phases & phase_flag)) |
193 | continue; |
194 | if (phase_flag >= DT_CREATE && !thd->fill_derived_tables()) |
195 | break; |
196 | |
197 | if ((res= (*processors[phase])(lex->thd, lex, derived))) |
198 | break; |
199 | } |
200 | lex->thd->derived_tables_processing= FALSE; |
201 | DBUG_RETURN(res); |
202 | } |
203 | |
204 | |
205 | /** |
206 | Run specified phases for derived tables/views in the given list |
207 | |
208 | @param lex LEX for this thread |
209 | @param table_list list of derived tables/view to handle |
210 | @param phase_map phases to process tables/views through |
211 | |
212 | @details |
213 | This function runs phases specified by the 'phases_map' on derived |
214 | tables/views found in the 'dt_list' with help of the |
215 | TABLE_LIST::handle_derived function. |
216 | 'lex' is passed as an argument to the TABLE_LIST::handle_derived. |
217 | |
218 | @return FALSE ok |
219 | @return TRUE error |
220 | */ |
221 | |
222 | bool |
223 | mysql_handle_list_of_derived(LEX *lex, TABLE_LIST *table_list, uint phases) |
224 | { |
225 | for (TABLE_LIST *tl= table_list; tl; tl= tl->next_local) |
226 | { |
227 | if (tl->is_view_or_derived() && |
228 | tl->handle_derived(lex, phases)) |
229 | return TRUE; |
230 | } |
231 | return FALSE; |
232 | } |
233 | |
234 | |
235 | /** |
236 | Merge a derived table/view into the embedding select |
237 | |
238 | @param thd thread handle |
239 | @param lex LEX of the embedding query. |
240 | @param derived reference to the derived table. |
241 | |
242 | @details |
243 | This function merges the given derived table / view into the parent select |
244 | construction. Any derived table/reference to view occurred in the FROM |
245 | clause of the embedding select is represented by a TABLE_LIST structure a |
246 | pointer to which is passed to the function as in the parameter 'derived'. |
247 | This structure contains the number/map, alias, a link to SELECT_LEX of the |
248 | derived table and other info. If the 'derived' table is used in a nested join |
249 | then additionally the structure contains a reference to the ON expression |
250 | for this join. |
251 | |
252 | The merge process results in elimination of the derived table (or the |
253 | reference to a view) such that: |
254 | - the FROM list of the derived table/view is wrapped into a nested join |
255 | after which the nest is added to the FROM list of the embedding select |
256 | - the WHERE condition of the derived table (view) is ANDed with the ON |
257 | condition attached to the table. |
258 | |
259 | @note |
260 | Tables are merged into the leaf_tables list, original derived table is removed |
261 | from this list also. SELECT_LEX::table_list list is left untouched. |
262 | Where expression is merged with derived table's on_expr and can be found after |
263 | the merge through the SELECT_LEX::table_list. |
264 | |
265 | Examples of the derived table/view merge: |
266 | |
267 | Schema: |
268 | Tables: t1(f1), t2(f2), t3(f3) |
269 | View v1: SELECT f1 FROM t1 WHERE f1 < 1 |
270 | |
271 | Example with a view: |
272 | Before merge: |
273 | |
274 | The query (Q1): SELECT f1,f2 FROM t2 LEFT JOIN v1 ON f1 = f2 |
275 | |
276 | (LEX of the main query) |
277 | | |
278 | (select_lex) |
279 | | |
280 | (FROM table list) |
281 | | |
282 | (join list)= t2, v1 |
283 | / \ |
284 | / (on_expr)= (f1 = f2) |
285 | | |
286 | (LEX of the v1 view) |
287 | | |
288 | (select_lex)= SELECT f1 FROM t1 WHERE f1 < 1 |
289 | |
290 | |
291 | After merge: |
292 | |
293 | The rewritten query Q1 (Q1'): |
294 | SELECT f1,f2 FROM t2 LEFT JOIN (t1) ON ((f1 = f2) and (f1 < 1)) |
295 | |
296 | (LEX of the main query) |
297 | | |
298 | (select_lex) |
299 | | |
300 | (FROM table list) |
301 | | |
302 | (join list)= t2, (t1) |
303 | \ |
304 | (on_expr)= (f1 = f2) and (f1 < 1) |
305 | |
306 | In this example table numbers are assigned as follows: |
307 | (outer select): t2 - 1, v1 - 2 |
308 | (inner select): t1 - 1 |
309 | After the merge table numbers will be: |
310 | (outer select): t2 - 1, t1 - 2 |
311 | |
312 | Example with a derived table: |
313 | The query Q2: |
314 | SELECT f1,f2 |
315 | FROM (SELECT f1 FROM t1, t3 WHERE f1=f3 and f1 < 1) tt, t2 |
316 | WHERE f1 = f2 |
317 | |
318 | Before merge: |
319 | (LEX of the main query) |
320 | | |
321 | (select_lex) |
322 | / \ |
323 | (FROM table list) (WHERE clause)= (f1 = f2) |
324 | | |
325 | (join list)= tt, t2 |
326 | / \ |
327 | / (on_expr)= (empty) |
328 | / |
329 | (select_lex)= SELECT f1 FROM t1, t3 WHERE f1 = f3 and f1 < 1 |
330 | |
331 | After merge: |
332 | |
333 | The rewritten query Q2 (Q2'): |
334 | SELECT f1,f2 |
335 | FROM (t1, t3) JOIN t2 ON (f1 = f3 and f1 < 1) |
336 | WHERE f1 = f2 |
337 | |
338 | (LEX of the main query) |
339 | | |
340 | (select_lex) |
341 | / \ |
342 | (FROM table list) (WHERE clause)= (f1 = f2) |
343 | | |
344 | (join list)= t2, (t1, t3) |
345 | \ |
346 | (on_expr)= (f1 = f3 and f1 < 1) |
347 | |
348 | In this example table numbers are assigned as follows: |
349 | (outer select): tt - 1, t2 - 2 |
350 | (inner select): t1 - 1, t3 - 2 |
351 | After the merge table numbers will be: |
352 | (outer select): t1 - 1, t2 - 2, t3 - 3 |
353 | |
354 | @return FALSE if derived table/view were successfully merged. |
355 | @return TRUE if an error occur. |
356 | */ |
357 | |
358 | bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) |
359 | { |
360 | bool res= FALSE; |
361 | SELECT_LEX *dt_select= derived->get_single_select(); |
362 | table_map map; |
363 | uint tablenr; |
364 | SELECT_LEX *parent_lex= derived->select_lex; |
365 | Query_arena *arena, backup; |
366 | DBUG_ENTER("mysql_derived_merge" ); |
367 | DBUG_PRINT("enter" , ("Alias: '%s' Unit: %p" , |
368 | (derived->alias.str ? derived->alias.str : "<NULL>" ), |
369 | derived->get_unit())); |
370 | |
371 | if (derived->merged) |
372 | { |
373 | |
374 | DBUG_PRINT("info" , ("Irreversibly merged: exit" )); |
375 | DBUG_RETURN(FALSE); |
376 | } |
377 | |
378 | if (dt_select->uncacheable & UNCACHEABLE_RAND) |
379 | { |
380 | /* There is random function => fall back to materialization. */ |
381 | derived->change_refs_to_fields(); |
382 | derived->set_materialized_derived(); |
383 | DBUG_RETURN(FALSE); |
384 | } |
385 | |
386 | if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI || |
387 | thd->lex->sql_command == SQLCOM_DELETE_MULTI) |
388 | thd->save_prep_leaf_list= TRUE; |
389 | |
390 | arena= thd->activate_stmt_arena_if_needed(&backup); // For easier test |
391 | |
392 | if (!derived->merged_for_insert || |
393 | (derived->is_multitable() && |
394 | (thd->lex->sql_command == SQLCOM_UPDATE_MULTI || |
395 | thd->lex->sql_command == SQLCOM_DELETE_MULTI))) |
396 | { |
397 | /* |
398 | Check whether there is enough free bits in table map to merge subquery. |
399 | If not - materialize it. This check isn't cached so when there is a big |
400 | and small subqueries, and the bigger one can't be merged it wouldn't |
401 | block the smaller one. |
402 | */ |
403 | if (parent_lex->get_free_table_map(&map, &tablenr)) |
404 | { |
405 | /* There is no enough table bits, fall back to materialization. */ |
406 | goto unconditional_materialization; |
407 | } |
408 | |
409 | if (dt_select->leaf_tables.elements + tablenr > MAX_TABLES) |
410 | { |
411 | /* There is no enough table bits, fall back to materialization. */ |
412 | goto unconditional_materialization; |
413 | } |
414 | |
415 | if (dt_select->options & OPTION_SCHEMA_TABLE) |
416 | parent_lex->options |= OPTION_SCHEMA_TABLE; |
417 | |
418 | if (!derived->get_unit()->prepared) |
419 | { |
420 | dt_select->leaf_tables.empty(); |
421 | make_leaves_list(thd, dt_select->leaf_tables, derived, TRUE, 0); |
422 | } |
423 | |
424 | derived->nested_join= (NESTED_JOIN*) thd->calloc(sizeof(NESTED_JOIN)); |
425 | if (!derived->nested_join) |
426 | { |
427 | res= TRUE; |
428 | goto exit_merge; |
429 | } |
430 | |
431 | /* Merge derived table's subquery in the parent select. */ |
432 | if (parent_lex->merge_subquery(thd, derived, dt_select, tablenr, map)) |
433 | { |
434 | res= TRUE; |
435 | goto exit_merge; |
436 | } |
437 | |
438 | /* |
439 | exclude select lex so it doesn't show up in explain. |
440 | do this only for derived table as for views this is already done. |
441 | |
442 | From sql_view.cc |
443 | Add subqueries units to SELECT into which we merging current view. |
444 | unit(->next)* chain starts with subqueries that are used by this |
445 | view and continues with subqueries that are used by other views. |
446 | We must not add any subquery twice (otherwise we'll form a loop), |
447 | to do this we remember in end_unit the first subquery that has |
448 | been already added. |
449 | */ |
450 | derived->get_unit()->exclude_level(); |
451 | if (parent_lex->join) |
452 | parent_lex->join->table_count+= dt_select->join->table_count - 1; |
453 | } |
454 | derived->merged= TRUE; |
455 | if (derived->get_unit()->prepared) |
456 | { |
457 | Item *expr= derived->on_expr; |
458 | expr= and_conds(thd, expr, dt_select->join ? dt_select->join->conds : 0); |
459 | if (expr) |
460 | expr->top_level_item(); |
461 | |
462 | if (expr && (derived->prep_on_expr || expr != derived->on_expr)) |
463 | { |
464 | derived->on_expr= expr; |
465 | derived->prep_on_expr= expr->copy_andor_structure(thd); |
466 | } |
467 | if (derived->on_expr && |
468 | ((!derived->on_expr->fixed && |
469 | derived->on_expr->fix_fields(thd, &derived->on_expr)) || |
470 | derived->on_expr->check_cols(1))) |
471 | { |
472 | res= TRUE; /* purecov: inspected */ |
473 | goto exit_merge; |
474 | } |
475 | // Update used tables cache according to new table map |
476 | if (derived->on_expr) |
477 | { |
478 | derived->on_expr->fix_after_pullout(parent_lex, &derived->on_expr, |
479 | TRUE); |
480 | fix_list_after_tbl_changes(parent_lex, &derived->nested_join->join_list); |
481 | } |
482 | } |
483 | |
484 | exit_merge: |
485 | if (arena) |
486 | thd->restore_active_arena(arena, &backup); |
487 | DBUG_RETURN(res); |
488 | |
489 | unconditional_materialization: |
490 | derived->change_refs_to_fields(); |
491 | derived->set_materialized_derived(); |
492 | if (!derived->table || !derived->table->is_created()) |
493 | res= mysql_derived_create(thd, lex, derived); |
494 | goto exit_merge; |
495 | } |
496 | |
497 | |
498 | /** |
499 | Merge a view for the embedding INSERT/UPDATE/DELETE |
500 | |
501 | @param thd thread handle |
502 | @param lex LEX of the embedding query. |
503 | @param derived reference to the derived table. |
504 | |
505 | @details |
506 | This function substitutes the derived table for the first table from |
507 | the query of the derived table thus making it a correct target table for the |
508 | INSERT/UPDATE/DELETE statements. As this operation is correct only for |
509 | single table views only, for multi table views this function does nothing. |
510 | The derived parameter isn't checked to be a view as derived tables aren't |
511 | allowed for INSERT/UPDATE/DELETE statements. |
512 | |
513 | @return FALSE if derived table/view were successfully merged. |
514 | @return TRUE if an error occur. |
515 | */ |
516 | |
517 | bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) |
518 | { |
519 | DBUG_ENTER("mysql_derived_merge_for_insert" ); |
520 | DBUG_PRINT("enter" , ("Alias: '%s' Unit: %p" , |
521 | (derived->alias.str ? derived->alias.str : "<NULL>" ), |
522 | derived->get_unit())); |
523 | DBUG_PRINT("info" , ("merged_for_insert: %d is_materialized_derived: %d " |
524 | "is_multitable: %d single_table_updatable: %d " |
525 | "merge_underlying_list: %d" , |
526 | derived->merged_for_insert, |
527 | derived->is_materialized_derived(), |
528 | derived->is_multitable(), |
529 | derived->single_table_updatable(), |
530 | derived->merge_underlying_list != 0)); |
531 | if (derived->merged_for_insert) |
532 | DBUG_RETURN(FALSE); |
533 | if (derived->init_derived(thd, FALSE)) |
534 | DBUG_RETURN(TRUE); |
535 | if (derived->is_materialized_derived()) |
536 | DBUG_RETURN(mysql_derived_prepare(thd, lex, derived)); |
537 | if ((thd->lex->sql_command == SQLCOM_UPDATE_MULTI || |
538 | thd->lex->sql_command == SQLCOM_DELETE_MULTI)) |
539 | DBUG_RETURN(FALSE); |
540 | if (!derived->is_multitable()) |
541 | { |
542 | if (!derived->single_table_updatable()) |
543 | DBUG_RETURN(derived->create_field_translation(thd)); |
544 | if (derived->merge_underlying_list) |
545 | { |
546 | derived->table= derived->merge_underlying_list->table; |
547 | derived->schema_table= derived->merge_underlying_list->schema_table; |
548 | derived->merged_for_insert= TRUE; |
549 | DBUG_ASSERT(derived->table); |
550 | } |
551 | } |
552 | DBUG_RETURN(FALSE); |
553 | } |
554 | |
555 | |
556 | /* |
557 | Initialize a derived table/view |
558 | |
559 | @param thd Thread handle |
560 | @param lex LEX of the embedding query. |
561 | @param derived reference to the derived table. |
562 | |
563 | @detail |
564 | Fill info about derived table/view without preparing an |
565 | underlying select. Such as: create a field translation for views, mark it as |
566 | a multitable if it is and so on. |
567 | |
568 | @return |
569 | false OK |
570 | true Error |
571 | */ |
572 | |
573 | |
574 | bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived) |
575 | { |
576 | SELECT_LEX_UNIT *unit= derived->get_unit(); |
577 | DBUG_ENTER("mysql_derived_init" ); |
578 | DBUG_PRINT("enter" , ("Alias: '%s' Unit: %p" , |
579 | (derived->alias.str ? derived->alias.str : "<NULL>" ), |
580 | derived->get_unit())); |
581 | |
582 | // Skip already prepared views/DT |
583 | if (!unit || unit->prepared) |
584 | DBUG_RETURN(FALSE); |
585 | |
586 | bool res= derived->init_derived(thd, TRUE); |
587 | |
588 | derived->updatable= derived->updatable && derived->is_view(); |
589 | |
590 | DBUG_RETURN(res); |
591 | } |
592 | |
593 | |
594 | /* |
595 | Create temporary table structure (but do not fill it) |
596 | |
597 | @param thd Thread handle |
598 | @param lex LEX of the embedding query. |
599 | @param derived reference to the derived table. |
600 | |
601 | @detail |
602 | Prepare underlying select for a derived table/view. To properly resolve |
603 | names in the embedding query the TABLE structure is created. Actual table |
604 | is created later by the mysql_derived_create function. |
605 | |
606 | This function is called before any command containing derived table |
607 | is executed. All types of derived tables are handled by this function: |
608 | - Anonymous derived tables, or |
609 | - Named derived tables (aka views). |
610 | |
611 | The table reference, contained in @c derived, is updated with the |
612 | fields of a new temporary table. |
613 | Derived tables are stored in @c thd->derived_tables and closed by |
614 | close_thread_tables(). |
615 | |
616 | This function is part of the procedure that starts in |
617 | open_and_lock_tables(), a procedure that - among other things - introduces |
618 | new table and table reference objects (to represent derived tables) that |
619 | don't exist in the privilege database. This means that normal privilege |
620 | checking cannot handle them. Hence this function does some extra tricks in |
621 | order to bypass normal privilege checking, by exploiting the fact that the |
622 | current state of privilege verification is attached as GRANT_INFO structures |
623 | on the relevant TABLE and TABLE_REF objects. |
624 | |
625 | For table references, the current state of accrued access is stored inside |
626 | TABLE_LIST::grant. Hence this function must update the state of fulfilled |
627 | privileges for the new TABLE_LIST, an operation which is normally performed |
628 | exclusively by the table and database access checking functions, |
629 | check_access() and check_grant(), respectively. This modification is done |
630 | for both views and anonymous derived tables: The @c SELECT privilege is set |
631 | as fulfilled by the user. However, if a view is referenced and the table |
632 | reference is queried against directly (see TABLE_LIST::referencing_view), |
633 | the state of privilege checking (GRANT_INFO struct) is copied as-is to the |
634 | temporary table. |
635 | |
636 | Only the TABLE structure is created here, actual table is created by the |
637 | mysql_derived_create function. |
638 | |
639 | @note This function sets @c SELECT_ACL for @c TEMPTABLE views as well as |
640 | anonymous derived tables, but this is ok since later access checking will |
641 | distinguish between them. |
642 | |
643 | @see mysql_handle_derived(), mysql_derived_fill(), GRANT_INFO |
644 | |
645 | @return |
646 | false OK |
647 | true Error |
648 | */ |
649 | |
650 | |
651 | bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) |
652 | { |
653 | SELECT_LEX_UNIT *unit= derived->get_unit(); |
654 | bool res= FALSE; |
655 | DBUG_ENTER("mysql_derived_prepare" ); |
656 | DBUG_PRINT("enter" , ("unit: %p table_list: %p alias: '%s'" , |
657 | unit, derived, derived->alias.str)); |
658 | |
659 | if (!unit) |
660 | DBUG_RETURN(FALSE); |
661 | |
662 | SELECT_LEX *first_select= unit->first_select(); |
663 | |
664 | if (derived->is_recursive_with_table() && |
665 | !derived->is_with_table_recursive_reference() && |
666 | !derived->with->rec_result && derived->with->get_sq_rec_ref()) |
667 | { |
668 | /* |
669 | This is a non-recursive reference to a recursive CTE whose |
670 | specification unit has not been prepared at the regular processing of |
671 | derived table references. This can happen only in the case when |
672 | the specification unit has no recursive references at the top level. |
673 | Force the preparation of the specification unit. Use a recursive |
674 | table reference from a subquery for this. |
675 | */ |
676 | DBUG_ASSERT(derived->with->get_sq_rec_ref()); |
677 | if (unlikely(mysql_derived_prepare(lex->thd, lex, |
678 | derived->with->get_sq_rec_ref()))) |
679 | DBUG_RETURN(TRUE); |
680 | } |
681 | |
682 | if (unit->prepared && derived->is_recursive_with_table() && |
683 | !derived->table) |
684 | { |
685 | /* |
686 | Here 'derived' is either a non-recursive table reference to a recursive |
687 | with table or a recursive table reference to a recursvive table whose |
688 | specification has been already prepared (a secondary recursive table |
689 | reference. |
690 | */ |
691 | if (!(derived->derived_result= new (thd->mem_root) select_unit(thd))) |
692 | DBUG_RETURN(TRUE); // out of memory |
693 | thd->create_tmp_table_for_derived= TRUE; |
694 | res= derived->derived_result->create_result_table( |
695 | thd, &unit->types, FALSE, |
696 | (first_select->options | |
697 | thd->variables.option_bits | |
698 | TMP_TABLE_ALL_COLUMNS), |
699 | &derived->alias, FALSE, FALSE, FALSE, 0); |
700 | thd->create_tmp_table_for_derived= FALSE; |
701 | |
702 | if (likely(!res) && !derived->table) |
703 | { |
704 | derived->derived_result->set_unit(unit); |
705 | derived->table= derived->derived_result->table; |
706 | if (derived->is_with_table_recursive_reference()) |
707 | { |
708 | /* Here 'derived" is a secondary recursive table reference */ |
709 | unit->with_element->rec_result->rec_tables.push_back(derived->table); |
710 | } |
711 | } |
712 | DBUG_ASSERT(derived->table || res); |
713 | goto exit; |
714 | } |
715 | |
716 | // Skip already prepared views/DT |
717 | if (unit->prepared || |
718 | (derived->merged_for_insert && |
719 | !(derived->is_multitable() && |
720 | (thd->lex->sql_command == SQLCOM_UPDATE_MULTI || |
721 | thd->lex->sql_command == SQLCOM_DELETE_MULTI)))) |
722 | DBUG_RETURN(FALSE); |
723 | |
724 | /* prevent name resolving out of derived table */ |
725 | for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select()) |
726 | { |
727 | sl->context.outer_context= 0; |
728 | if (!derived->is_with_table_recursive_reference() || |
729 | (!derived->with->with_anchor && |
730 | !derived->with->is_with_prepared_anchor())) |
731 | { |
732 | /* |
733 | Prepare underlying views/DT first unless 'derived' is a recursive |
734 | table reference and either the anchors from the specification of |
735 | 'derived' has been already prepared or there no anchor in this |
736 | specification |
737 | */ |
738 | if ((res= sl->handle_derived(lex, DT_PREPARE))) |
739 | goto exit; |
740 | } |
741 | if (derived->outer_join && sl->first_cond_optimization) |
742 | { |
743 | /* Mark that table is part of OUTER JOIN and fields may be NULL */ |
744 | for (TABLE_LIST *cursor= (TABLE_LIST*) sl->table_list.first; |
745 | cursor; |
746 | cursor= cursor->next_local) |
747 | cursor->outer_join|= JOIN_TYPE_OUTER; |
748 | } |
749 | } |
750 | |
751 | /* |
752 | Above cascade call of prepare is important for PS protocol, but after it |
753 | is called we can check if we really need prepare for this derived |
754 | */ |
755 | if (derived->merged) |
756 | { |
757 | DBUG_PRINT("info" , ("Irreversibly merged: exit" )); |
758 | DBUG_RETURN(FALSE); |
759 | } |
760 | |
761 | derived->fill_me= FALSE; |
762 | |
763 | if (!(derived->derived_result= new (thd->mem_root) select_unit(thd))) |
764 | DBUG_RETURN(TRUE); // out of memory |
765 | |
766 | lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; |
767 | // st_select_lex_unit::prepare correctly work for single select |
768 | if ((res= unit->prepare(derived, derived->derived_result, 0))) |
769 | goto exit; |
770 | if (derived->with && |
771 | (res= derived->with->rename_columns_of_derived_unit(thd, unit))) |
772 | goto exit; |
773 | lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED; |
774 | if ((res= check_duplicate_names(thd, unit->types, 0))) |
775 | goto exit; |
776 | |
777 | /* |
778 | Check whether we can merge this derived table into main select. |
779 | Depending on the result field translation will or will not |
780 | be created. |
781 | */ |
782 | if (derived->init_derived(thd, FALSE)) |
783 | goto exit; |
784 | |
785 | /* |
786 | Temp table is created so that it hounours if UNION without ALL is to be |
787 | processed |
788 | |
789 | As 'distinct' parameter we always pass FALSE (0), because underlying |
790 | query will control distinct condition by itself. Correct test of |
791 | distinct underlying query will be is_unit_op && |
792 | !unit->union_distinct->next_select() (i.e. it is union and last distinct |
793 | SELECT is last SELECT of UNION). |
794 | */ |
795 | thd->create_tmp_table_for_derived= TRUE; |
796 | if (!(derived->table) && |
797 | derived->derived_result->create_result_table(thd, &unit->types, FALSE, |
798 | (first_select->options | |
799 | thd->variables.option_bits | |
800 | TMP_TABLE_ALL_COLUMNS), |
801 | &derived->alias, |
802 | FALSE, FALSE, FALSE, |
803 | 0)) |
804 | { |
805 | thd->create_tmp_table_for_derived= FALSE; |
806 | goto exit; |
807 | } |
808 | thd->create_tmp_table_for_derived= FALSE; |
809 | |
810 | if (!derived->table) |
811 | derived->table= derived->derived_result->table; |
812 | DBUG_ASSERT(derived->table); |
813 | if (derived->is_derived() && derived->is_merged_derived()) |
814 | first_select->mark_as_belong_to_derived(derived); |
815 | |
816 | exit: |
817 | /* Hide "Unknown column" or "Unknown function" error */ |
818 | if (derived->view) |
819 | { |
820 | if (thd->is_error() && |
821 | (thd->get_stmt_da()->sql_errno() == ER_BAD_FIELD_ERROR || |
822 | thd->get_stmt_da()->sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION || |
823 | thd->get_stmt_da()->sql_errno() == ER_SP_DOES_NOT_EXIST)) |
824 | { |
825 | thd->clear_error(); |
826 | my_error(ER_VIEW_INVALID, MYF(0), derived->db.str, |
827 | derived->table_name.str); |
828 | } |
829 | } |
830 | |
831 | /* |
832 | if it is preparation PS only or commands that need only VIEW structure |
833 | then we do not need real data and we can skip execution (and parameters |
834 | is not defined, too) |
835 | */ |
836 | if (res) |
837 | { |
838 | if (!derived->is_with_table_recursive_reference()) |
839 | { |
840 | if (derived->table) |
841 | free_tmp_table(thd, derived->table); |
842 | delete derived->derived_result; |
843 | } |
844 | } |
845 | else |
846 | { |
847 | TABLE *table= derived->table; |
848 | table->derived_select_number= first_select->select_number; |
849 | table->s->tmp_table= INTERNAL_TMP_TABLE; |
850 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
851 | if (derived->is_view()) |
852 | table->grant= derived->grant; |
853 | else |
854 | { |
855 | DBUG_ASSERT(derived->is_derived()); |
856 | DBUG_ASSERT(derived->is_anonymous_derived_table()); |
857 | table->grant.privilege= SELECT_ACL; |
858 | derived->grant.privilege= SELECT_ACL; |
859 | } |
860 | #endif |
861 | /* Add new temporary table to list of open derived tables */ |
862 | if (!derived->is_with_table_recursive_reference()) |
863 | { |
864 | table->next= thd->derived_tables; |
865 | thd->derived_tables= table; |
866 | } |
867 | |
868 | /* If table is used by a left join, mark that any column may be null */ |
869 | if (derived->outer_join) |
870 | table->maybe_null= 1; |
871 | } |
872 | DBUG_RETURN(res); |
873 | } |
874 | |
875 | |
876 | /** |
877 | Runs optimize phase for a derived table/view. |
878 | |
879 | @param thd thread handle |
880 | @param lex LEX of the embedding query. |
881 | @param derived reference to the derived table. |
882 | |
883 | @details |
884 | Runs optimize phase for given 'derived' derived table/view. |
885 | If optimizer finds out that it's of the type "SELECT a_constant" then this |
886 | functions also materializes it. |
887 | |
888 | @return FALSE ok. |
889 | @return TRUE if an error occur. |
890 | */ |
891 | |
892 | bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) |
893 | { |
894 | SELECT_LEX_UNIT *unit= derived->get_unit(); |
895 | SELECT_LEX *first_select= unit->first_select(); |
896 | SELECT_LEX *save_current_select= lex->current_select; |
897 | bool res= FALSE; |
898 | DBUG_ENTER("mysql_derived_optimize" ); |
899 | DBUG_PRINT("enter" , ("Alias: '%s' Unit: %p" , |
900 | (derived->alias.str ? derived->alias.str : "<NULL>" ), |
901 | derived->get_unit())); |
902 | if (derived->merged) |
903 | { |
904 | DBUG_PRINT("info" , ("Irreversibly merged: exit" )); |
905 | DBUG_RETURN(FALSE); |
906 | } |
907 | |
908 | lex->current_select= first_select; |
909 | |
910 | if (unit->is_unit_op()) |
911 | { |
912 | if (unit->optimized) |
913 | DBUG_RETURN(FALSE); |
914 | // optimize union without execution |
915 | res= unit->optimize(); |
916 | } |
917 | else if (unit->derived) |
918 | { |
919 | if (!derived->is_merged_derived()) |
920 | { |
921 | JOIN *join= first_select->join; |
922 | unit->set_limit(unit->global_parameters()); |
923 | if (join && |
924 | join->optimization_state == JOIN::OPTIMIZATION_PHASE_1_DONE && |
925 | join->with_two_phase_optimization) |
926 | { |
927 | if (unit->optimized_2) |
928 | DBUG_RETURN(FALSE); |
929 | unit->optimized_2= TRUE; |
930 | } |
931 | else |
932 | { |
933 | if (unit->optimized) |
934 | DBUG_RETURN(FALSE); |
935 | unit->optimized= TRUE; |
936 | } |
937 | if ((res= join->optimize())) |
938 | goto err; |
939 | if (join->table_count == join->const_tables) |
940 | derived->fill_me= TRUE; |
941 | } |
942 | } |
943 | /* |
944 | Materialize derived tables/views of the "SELECT a_constant" type. |
945 | Such tables should be materialized at the optimization phase for |
946 | correct constant evaluation. |
947 | */ |
948 | if (!res && derived->fill_me && !derived->merged_for_insert) |
949 | { |
950 | if (derived->is_merged_derived()) |
951 | { |
952 | derived->change_refs_to_fields(); |
953 | derived->set_materialized_derived(); |
954 | } |
955 | if ((res= mysql_derived_create(thd, lex, derived))) |
956 | goto err; |
957 | if ((res= mysql_derived_fill(thd, lex, derived))) |
958 | goto err; |
959 | } |
960 | err: |
961 | lex->current_select= save_current_select; |
962 | DBUG_RETURN(res); |
963 | } |
964 | |
965 | |
966 | /** |
967 | Actually create result table for a materialized derived table/view. |
968 | |
969 | @param thd thread handle |
970 | @param lex LEX of the embedding query. |
971 | @param derived reference to the derived table. |
972 | |
973 | @details |
974 | This function actually creates the result table for given 'derived' |
975 | table/view, but it doesn't fill it. |
976 | 'thd' and 'lex' parameters are not used by this function. |
977 | |
978 | @return FALSE ok. |
979 | @return TRUE if an error occur. |
980 | */ |
981 | |
982 | bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived) |
983 | { |
984 | DBUG_ENTER("mysql_derived_create" ); |
985 | DBUG_PRINT("enter" , ("Alias: '%s' Unit: %p" , |
986 | (derived->alias.str ? derived->alias.str : "<NULL>" ), |
987 | derived->get_unit())); |
988 | TABLE *table= derived->table; |
989 | SELECT_LEX_UNIT *unit= derived->get_unit(); |
990 | |
991 | if (table->is_created()) |
992 | DBUG_RETURN(FALSE); |
993 | select_unit *result= derived->derived_result; |
994 | if (table->s->db_type() == TMP_ENGINE_HTON) |
995 | { |
996 | result->tmp_table_param.keyinfo= table->s->key_info; |
997 | if (create_internal_tmp_table(table, result->tmp_table_param.keyinfo, |
998 | result->tmp_table_param.start_recinfo, |
999 | &result->tmp_table_param.recinfo, |
1000 | (unit->first_select()->options | |
1001 | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS))) |
1002 | DBUG_RETURN(TRUE); |
1003 | } |
1004 | if (open_tmp_table(table)) |
1005 | DBUG_RETURN(TRUE); |
1006 | table->file->extra(HA_EXTRA_WRITE_CACHE); |
1007 | table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); |
1008 | DBUG_RETURN(FALSE); |
1009 | } |
1010 | |
1011 | |
1012 | void TABLE_LIST::register_as_derived_with_rec_ref(With_element *rec_elem) |
1013 | { |
1014 | rec_elem->derived_with_rec_ref.link_in_list(this, &this->next_with_rec_ref); |
1015 | is_derived_with_recursive_reference= true; |
1016 | get_unit()->uncacheable|= UNCACHEABLE_DEPENDENT; |
1017 | } |
1018 | |
1019 | |
1020 | bool TABLE_LIST::is_nonrecursive_derived_with_rec_ref() |
1021 | { |
1022 | return is_derived_with_recursive_reference; |
1023 | } |
1024 | |
1025 | |
1026 | /** |
1027 | @brief |
1028 | Fill the recursive with table |
1029 | |
1030 | @param thd The thread handle |
1031 | |
1032 | @details |
1033 | The method is called only for recursive with tables. |
1034 | The method executes the recursive part of the specification |
1035 | of this with table until no more rows are added to the table |
1036 | or the number of the performed iteration reaches the allowed |
1037 | maximum. |
1038 | |
1039 | @retval |
1040 | false on success |
1041 | true on failure |
1042 | */ |
1043 | |
1044 | bool TABLE_LIST::fill_recursive(THD *thd) |
1045 | { |
1046 | bool rc= false; |
1047 | st_select_lex_unit *unit= get_unit(); |
1048 | rc= with->instantiate_tmp_tables(); |
1049 | while (!rc && !with->all_are_stabilized()) |
1050 | { |
1051 | if (with->level > thd->variables.max_recursive_iterations) |
1052 | break; |
1053 | with->prepare_for_next_iteration(); |
1054 | rc= unit->exec_recursive(); |
1055 | } |
1056 | if (!rc) |
1057 | { |
1058 | TABLE *src= with->rec_result->table; |
1059 | rc =src->insert_all_rows_into_tmp_table(thd, |
1060 | table, |
1061 | &with->rec_result->tmp_table_param, |
1062 | true); |
1063 | } |
1064 | return rc; |
1065 | } |
1066 | |
1067 | |
1068 | /* |
1069 | Execute subquery of a materialized derived table/view and fill the result |
1070 | table. |
1071 | |
1072 | @param thd Thread handle |
1073 | @param lex LEX for this thread |
1074 | @param derived reference to the derived table. |
1075 | |
1076 | @details |
1077 | Execute subquery of given 'derived' table/view and fill the result |
1078 | table. After result table is filled, if this is not the EXPLAIN statement |
1079 | and the table is not specified with a recursion the entire unit / node |
1080 | is deleted. unit is deleted if UNION is used for derived table and node |
1081 | is deleted is it is a simple SELECT. |
1082 | 'lex' is unused and 'thd' is passed as an argument to an underlying function. |
1083 | |
1084 | @note |
1085 | If you use this function, make sure it's not called at prepare. |
1086 | Due to evaluation of LIMIT clause it can not be used at prepared stage. |
1087 | |
1088 | @return FALSE OK |
1089 | @return TRUE Error |
1090 | */ |
1091 | |
1092 | |
1093 | bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) |
1094 | { |
1095 | Field_iterator_table field_iterator; |
1096 | SELECT_LEX_UNIT *unit= derived->get_unit(); |
1097 | bool derived_is_recursive= derived->is_recursive_with_table(); |
1098 | bool res= FALSE; |
1099 | DBUG_ENTER("mysql_derived_fill" ); |
1100 | DBUG_PRINT("enter" , ("Alias: '%s' Unit: %p" , |
1101 | (derived->alias.str ? derived->alias.str : "<NULL>" ), |
1102 | derived->get_unit())); |
1103 | |
1104 | if (unit->executed && !unit->uncacheable && !unit->describe && |
1105 | !derived_is_recursive) |
1106 | DBUG_RETURN(FALSE); |
1107 | /*check that table creation passed without problems. */ |
1108 | DBUG_ASSERT(derived->table && derived->table->is_created()); |
1109 | select_unit *derived_result= derived->derived_result; |
1110 | SELECT_LEX *save_current_select= lex->current_select; |
1111 | |
1112 | if (unit->executed && !derived_is_recursive && |
1113 | (unit->uncacheable & UNCACHEABLE_DEPENDENT)) |
1114 | { |
1115 | if ((res= derived->table->file->ha_delete_all_rows())) |
1116 | goto err; |
1117 | JOIN *join= unit->first_select()->join; |
1118 | join->first_record= false; |
1119 | for (uint i= join->top_join_tab_count; |
1120 | i < join->top_join_tab_count + join->aggr_tables; |
1121 | i++) |
1122 | { |
1123 | if ((res= join->join_tab[i].table->file->ha_delete_all_rows())) |
1124 | goto err; |
1125 | } |
1126 | } |
1127 | |
1128 | if (derived_is_recursive) |
1129 | { |
1130 | if (derived->is_with_table_recursive_reference()) |
1131 | { |
1132 | /* Here only one iteration step is performed */ |
1133 | res= unit->exec_recursive(); |
1134 | } |
1135 | else |
1136 | { |
1137 | /* In this case all iteration are performed */ |
1138 | res= derived->fill_recursive(thd); |
1139 | } |
1140 | } |
1141 | else if (unit->is_unit_op()) |
1142 | { |
1143 | // execute union without clean up |
1144 | res= unit->exec(); |
1145 | } |
1146 | else |
1147 | { |
1148 | SELECT_LEX *first_select= unit->first_select(); |
1149 | unit->set_limit(unit->global_parameters()); |
1150 | if (unit->select_limit_cnt == HA_POS_ERROR) |
1151 | first_select->options&= ~OPTION_FOUND_ROWS; |
1152 | |
1153 | lex->current_select= first_select; |
1154 | res= mysql_select(thd, |
1155 | first_select->table_list.first, |
1156 | first_select->with_wild, |
1157 | first_select->item_list, first_select->where, |
1158 | (first_select->order_list.elements+ |
1159 | first_select->group_list.elements), |
1160 | first_select->order_list.first, |
1161 | first_select->group_list.first, |
1162 | first_select->having, (ORDER*) NULL, |
1163 | (first_select->options |thd->variables.option_bits | |
1164 | SELECT_NO_UNLOCK), |
1165 | derived_result, unit, first_select); |
1166 | } |
1167 | |
1168 | if (!res && !derived_is_recursive) |
1169 | { |
1170 | if (derived_result->flush()) |
1171 | res= TRUE; |
1172 | unit->executed= TRUE; |
1173 | |
1174 | if (derived->field_translation) |
1175 | { |
1176 | /* reset translation table to materialized table */ |
1177 | field_iterator.set_table(derived->table); |
1178 | for (uint i= 0; |
1179 | !field_iterator.end_of_fields(); |
1180 | field_iterator.next(), i= i + 1) |
1181 | { |
1182 | Item *item; |
1183 | |
1184 | if (!(item= field_iterator.create_item(thd))) |
1185 | { |
1186 | res= TRUE; |
1187 | break; |
1188 | } |
1189 | thd->change_item_tree(&derived->field_translation[i].item, item); |
1190 | } |
1191 | } |
1192 | } |
1193 | err: |
1194 | if (res || (!lex->describe && !derived_is_recursive && !unit->uncacheable)) |
1195 | unit->cleanup(); |
1196 | lex->current_select= save_current_select; |
1197 | |
1198 | DBUG_RETURN(res); |
1199 | } |
1200 | |
1201 | |
1202 | /** |
1203 | Re-initialize given derived table/view for the next execution. |
1204 | |
1205 | @param thd thread handle |
1206 | @param lex LEX for this thread |
1207 | @param derived reference to the derived table. |
1208 | |
1209 | @details |
1210 | Re-initialize given 'derived' table/view for the next execution. |
1211 | All underlying views/derived tables are recursively reinitialized prior |
1212 | to re-initialization of given derived table. |
1213 | 'thd' and 'lex' are passed as arguments to called functions. |
1214 | |
1215 | @return FALSE OK |
1216 | @return TRUE Error |
1217 | */ |
1218 | |
1219 | bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived) |
1220 | { |
1221 | DBUG_ENTER("mysql_derived_reinit" ); |
1222 | DBUG_PRINT("enter" , ("Alias: '%s' Unit: %p" , |
1223 | (derived->alias.str ? derived->alias.str : "<NULL>" ), |
1224 | derived->get_unit())); |
1225 | st_select_lex_unit *unit= derived->get_unit(); |
1226 | |
1227 | derived->merged_for_insert= FALSE; |
1228 | unit->unclean(); |
1229 | unit->types.empty(); |
1230 | /* for derived tables & PS (which can't be reset by Item_subselect) */ |
1231 | unit->reinit_exec_mechanism(); |
1232 | for (st_select_lex *sl= unit->first_select(); sl; sl= sl->next_select()) |
1233 | { |
1234 | sl->cond_pushed_into_where= NULL; |
1235 | sl->cond_pushed_into_having= NULL; |
1236 | } |
1237 | unit->set_thd(thd); |
1238 | DBUG_RETURN(FALSE); |
1239 | } |
1240 | |
1241 | |
1242 | /** |
1243 | @brief |
1244 | Extract the condition depended on derived table/view and pushed it there |
1245 | |
1246 | @param thd The thread handle |
1247 | @param cond The condition from which to extract the pushed condition |
1248 | @param derived The reference to the derived table/view |
1249 | |
1250 | @details |
1251 | This functiom builds the most restrictive condition depending only on |
1252 | the derived table/view that can be extracted from the condition cond. |
1253 | The built condition is pushed into the having clauses of the |
1254 | selects contained in the query specifying the derived table/view. |
1255 | The function also checks for each select whether any condition depending |
1256 | only on grouping fields can be extracted from the pushed condition. |
1257 | If so, it pushes the condition over grouping fields into the where |
1258 | clause of the select. |
1259 | |
1260 | @retval |
1261 | true if an error is reported |
1262 | false otherwise |
1263 | */ |
1264 | |
1265 | bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) |
1266 | { |
1267 | DBUG_ENTER("pushdown_cond_for_derived" ); |
1268 | if (!cond) |
1269 | DBUG_RETURN(false); |
1270 | |
1271 | st_select_lex_unit *unit= derived->get_unit(); |
1272 | st_select_lex *sl= unit->first_select(); |
1273 | |
1274 | if (derived->prohibit_cond_pushdown) |
1275 | DBUG_RETURN(false); |
1276 | |
1277 | /* Do not push conditions into constant derived */ |
1278 | if (unit->executed) |
1279 | DBUG_RETURN(false); |
1280 | |
1281 | /* Do not push conditions into recursive with tables */ |
1282 | if (derived->is_recursive_with_table()) |
1283 | DBUG_RETURN(false); |
1284 | |
1285 | /* Do not push conditions into unit with global ORDER BY ... LIMIT */ |
1286 | if (unit->fake_select_lex && unit->fake_select_lex->explicit_limit) |
1287 | DBUG_RETURN(false); |
1288 | |
1289 | /* Check whether any select of 'unit' allows condition pushdown */ |
1290 | bool some_select_allows_cond_pushdown= false; |
1291 | for (; sl; sl= sl->next_select()) |
1292 | { |
1293 | if (sl->cond_pushdown_is_allowed()) |
1294 | { |
1295 | some_select_allows_cond_pushdown= true; |
1296 | break; |
1297 | } |
1298 | } |
1299 | if (!some_select_allows_cond_pushdown) |
1300 | DBUG_RETURN(false); |
1301 | |
1302 | /* |
1303 | Build the most restrictive condition extractable from 'cond' |
1304 | that can be pushed into the derived table 'derived'. |
1305 | All subexpressions of this condition are cloned from the |
1306 | subexpressions of 'cond'. |
1307 | This condition has to be fixed yet. |
1308 | */ |
1309 | Item *; |
1310 | derived->check_pushable_cond_for_table(cond); |
1311 | extracted_cond= derived->build_pushable_cond_for_table(thd, cond); |
1312 | if (!extracted_cond) |
1313 | { |
1314 | /* Nothing can be pushed into the derived table */ |
1315 | DBUG_RETURN(false); |
1316 | } |
1317 | /* Push extracted_cond into every select of the unit specifying 'derived' */ |
1318 | st_select_lex *save_curr_select= thd->lex->current_select; |
1319 | for (; sl; sl= sl->next_select()) |
1320 | { |
1321 | Item *; |
1322 | if (!sl->cond_pushdown_is_allowed()) |
1323 | continue; |
1324 | thd->lex->current_select= sl; |
1325 | if (sl->have_window_funcs()) |
1326 | { |
1327 | if (sl->join->group_list || sl->join->implicit_grouping) |
1328 | continue; |
1329 | ORDER *common_partition_fields= |
1330 | sl->find_common_window_func_partition_fields(thd); |
1331 | if (!common_partition_fields) |
1332 | continue; |
1333 | extracted_cond_copy= !sl->next_select() ? |
1334 | extracted_cond : |
1335 | extracted_cond->build_clone(thd); |
1336 | if (!extracted_cond_copy) |
1337 | continue; |
1338 | |
1339 | Item *cond_over_partition_fields;; |
1340 | sl->collect_grouping_fields(thd, common_partition_fields); |
1341 | sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy, |
1342 | derived); |
1343 | cond_over_partition_fields= |
1344 | sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true); |
1345 | if (cond_over_partition_fields) |
1346 | cond_over_partition_fields= cond_over_partition_fields->transform(thd, |
1347 | &Item::derived_grouping_field_transformer_for_where, |
1348 | (uchar*) sl); |
1349 | if (cond_over_partition_fields) |
1350 | { |
1351 | cond_over_partition_fields->walk( |
1352 | &Item::cleanup_excluding_const_fields_processor, 0, 0); |
1353 | sl->cond_pushed_into_where= cond_over_partition_fields; |
1354 | } |
1355 | |
1356 | continue; |
1357 | } |
1358 | |
1359 | /* |
1360 | For each select of the unit except the last one |
1361 | create a clone of extracted_cond |
1362 | */ |
1363 | extracted_cond_copy= !sl->next_select() ? |
1364 | extracted_cond : |
1365 | extracted_cond->build_clone(thd); |
1366 | if (!extracted_cond_copy) |
1367 | continue; |
1368 | |
1369 | if (!sl->join->group_list && !sl->with_sum_func) |
1370 | { |
1371 | /* extracted_cond_copy is pushed into where of sl */ |
1372 | extracted_cond_copy= extracted_cond_copy->transform(thd, |
1373 | &Item::derived_field_transformer_for_where, |
1374 | (uchar*) sl); |
1375 | if (extracted_cond_copy) |
1376 | { |
1377 | extracted_cond_copy->walk( |
1378 | &Item::cleanup_excluding_const_fields_processor, 0, 0); |
1379 | sl->cond_pushed_into_where= extracted_cond_copy; |
1380 | } |
1381 | |
1382 | continue; |
1383 | } |
1384 | |
1385 | /* |
1386 | Figure out what can be extracted from the pushed condition |
1387 | that could be pushed into the where clause of sl |
1388 | */ |
1389 | Item *cond_over_grouping_fields; |
1390 | sl->collect_grouping_fields(thd, sl->join->group_list); |
1391 | sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy, |
1392 | derived); |
1393 | cond_over_grouping_fields= |
1394 | sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true); |
1395 | |
1396 | /* |
1397 | Transform the references to the 'derived' columns from the condition |
1398 | pushed into the where clause of sl to make them usable in the new context |
1399 | */ |
1400 | if (cond_over_grouping_fields) |
1401 | cond_over_grouping_fields= cond_over_grouping_fields->transform(thd, |
1402 | &Item::derived_grouping_field_transformer_for_where, |
1403 | (uchar*) sl); |
1404 | |
1405 | if (cond_over_grouping_fields) |
1406 | { |
1407 | /* |
1408 | In extracted_cond_copy remove top conjuncts that |
1409 | has been pushed into the where clause of sl |
1410 | */ |
1411 | extracted_cond_copy= remove_pushed_top_conjuncts(thd, extracted_cond_copy); |
1412 | |
1413 | cond_over_grouping_fields->walk( |
1414 | &Item::cleanup_excluding_const_fields_processor, 0, 0); |
1415 | sl->cond_pushed_into_where= cond_over_grouping_fields; |
1416 | |
1417 | if (!extracted_cond_copy) |
1418 | continue; |
1419 | } |
1420 | |
1421 | /* |
1422 | Transform the references to the 'derived' columns from the condition |
1423 | pushed into the having clause of sl to make them usable in the new context |
1424 | */ |
1425 | extracted_cond_copy= extracted_cond_copy->transform(thd, |
1426 | &Item::derived_field_transformer_for_having, |
1427 | (uchar*) sl); |
1428 | if (!extracted_cond_copy) |
1429 | continue; |
1430 | |
1431 | extracted_cond_copy->walk(&Item::cleanup_excluding_const_fields_processor, |
1432 | 0, 0); |
1433 | sl->cond_pushed_into_having= extracted_cond_copy; |
1434 | } |
1435 | thd->lex->current_select= save_curr_select; |
1436 | DBUG_RETURN(false); |
1437 | } |
1438 | |
1439 | |