1 | /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. |
2 | Copyright (c) 2010, 2017, Corporation |
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 | |
18 | /* |
19 | UNION of select's |
20 | UNION's were introduced by Monty and Sinisa <sinisa@mysql.com> |
21 | */ |
22 | |
23 | #include "mariadb.h" |
24 | #include "sql_priv.h" |
25 | #include "unireg.h" |
26 | #include "sql_union.h" |
27 | #include "sql_select.h" |
28 | #include "sql_cursor.h" |
29 | #include "sql_base.h" // fill_record |
30 | #include "filesort.h" // filesort_free_buffers |
31 | #include "sql_view.h" |
32 | #include "sql_cte.h" |
33 | |
34 | bool mysql_union(THD *thd, LEX *lex, select_result *result, |
35 | SELECT_LEX_UNIT *unit, ulong setup_tables_done_option) |
36 | { |
37 | DBUG_ENTER("mysql_union" ); |
38 | bool res; |
39 | if (!(res= unit->prepare(unit->derived, result, SELECT_NO_UNLOCK | |
40 | setup_tables_done_option))) |
41 | res= unit->exec(); |
42 | res|= unit->cleanup(); |
43 | DBUG_RETURN(res); |
44 | } |
45 | |
46 | |
47 | /*************************************************************************** |
48 | ** store records in temporary table for UNION |
49 | ***************************************************************************/ |
50 | |
51 | int select_unit::prepare(List<Item> &list, SELECT_LEX_UNIT *u) |
52 | { |
53 | unit= u; |
54 | return 0; |
55 | } |
56 | |
57 | /** |
58 | This called by SELECT_LEX_UNIT::exec when select changed |
59 | */ |
60 | |
61 | void select_unit::change_select() |
62 | { |
63 | uint current_select_number= thd->lex->current_select->select_number; |
64 | DBUG_ENTER("select_unit::change_select" ); |
65 | DBUG_PRINT("enter" , ("select in unit change: %u -> %u" , |
66 | curr_sel, current_select_number)); |
67 | DBUG_ASSERT(curr_sel != current_select_number); |
68 | curr_sel= current_select_number; |
69 | /* New SELECT processing starts */ |
70 | DBUG_ASSERT(table->file->inited == 0); |
71 | step= thd->lex->current_select->linkage; |
72 | switch (step) |
73 | { |
74 | case INTERSECT_TYPE: |
75 | intersect_mark->value= prev_step= curr_step; |
76 | curr_step= current_select_number; |
77 | break; |
78 | case EXCEPT_TYPE: |
79 | break; |
80 | default: |
81 | step= UNION_TYPE; |
82 | break; |
83 | } |
84 | DBUG_VOID_RETURN; |
85 | } |
86 | /** |
87 | Fill temporary tables for UNION/EXCEPT/INTERSECT |
88 | |
89 | @Note |
90 | UNION: |
91 | just add records to the table (with 'counter' field first if INTERSECT |
92 | present in the sequence). |
93 | EXCEPT: |
94 | looks for the record in the table (with 'counter' field first if |
95 | INTERSECT present in the sequence) and delete it if found |
96 | INTESECT: |
97 | looks for the same record with 'counter' field of previous operation, |
98 | put as a 'counter' number of the current SELECT. |
99 | We scan the table and remove all records which marked with not last |
100 | 'counter' after processing all records in send_eof and only if it last |
101 | SELECT of sequence of INTERSECTS. |
102 | |
103 | @param values List of record items to process. |
104 | |
105 | @retval 0 - OK |
106 | @retval -1 - duplicate |
107 | @retval 1 - error |
108 | */ |
109 | int select_unit::send_data(List<Item> &values) |
110 | { |
111 | int rc; |
112 | int not_reported_error= 0; |
113 | if (unit->offset_limit_cnt) |
114 | { // using limit offset,count |
115 | unit->offset_limit_cnt--; |
116 | return 0; |
117 | } |
118 | if (thd->killed == ABORT_QUERY) |
119 | return 0; |
120 | if (table->no_rows_with_nulls) |
121 | table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT; |
122 | if (intersect_mark) |
123 | { |
124 | fill_record(thd, table, table->field + 1, values, TRUE, FALSE); |
125 | table->field[0]->store((ulonglong) curr_step, 1); |
126 | } |
127 | else |
128 | fill_record(thd, table, table->field, values, TRUE, FALSE); |
129 | if (unlikely(thd->is_error())) |
130 | { |
131 | rc= 1; |
132 | goto end; |
133 | } |
134 | if (table->no_rows_with_nulls) |
135 | { |
136 | table->null_catch_flags&= ~CHECK_ROW_FOR_NULLS_TO_REJECT; |
137 | if (table->null_catch_flags) |
138 | { |
139 | rc= 0; |
140 | goto end; |
141 | } |
142 | } |
143 | |
144 | // select_unit::change_select() change step & Co correctly for each SELECT |
145 | switch (step) |
146 | { |
147 | case UNION_TYPE: |
148 | { |
149 | if (unlikely((write_err= |
150 | table->file->ha_write_tmp_row(table->record[0])))) |
151 | { |
152 | if (write_err == HA_ERR_FOUND_DUPP_KEY) |
153 | { |
154 | /* |
155 | Inform upper level that we found a duplicate key, that should not |
156 | be counted as part of limit |
157 | */ |
158 | rc= -1; |
159 | goto end; |
160 | } |
161 | bool is_duplicate= FALSE; |
162 | /* create_internal_tmp_table_from_heap will generate error if needed */ |
163 | if (table->file->is_fatal_error(write_err, HA_CHECK_DUP) && |
164 | create_internal_tmp_table_from_heap(thd, table, |
165 | tmp_table_param.start_recinfo, |
166 | &tmp_table_param.recinfo, |
167 | write_err, 1, &is_duplicate)) |
168 | { |
169 | rc= 1; |
170 | goto end; |
171 | } |
172 | |
173 | if (is_duplicate) |
174 | { |
175 | rc= -1; |
176 | goto end; |
177 | } |
178 | } |
179 | break; |
180 | } |
181 | case EXCEPT_TYPE: |
182 | { |
183 | int find_res; |
184 | /* |
185 | The temporary table uses very first index or constrain for |
186 | checking unique constrain. |
187 | */ |
188 | if (!(find_res= table->file->find_unique_row(table->record[0], 0))) |
189 | { |
190 | DBUG_ASSERT(!table->triggers); |
191 | table->status|= STATUS_DELETED; |
192 | not_reported_error= table->file->ha_delete_tmp_row(table->record[0]); |
193 | rc= MY_TEST(not_reported_error); |
194 | goto end; |
195 | } |
196 | else |
197 | { |
198 | if ((rc= not_reported_error= (find_res != 1))) |
199 | goto end; |
200 | } |
201 | break; |
202 | } |
203 | case INTERSECT_TYPE: |
204 | { |
205 | int find_res; |
206 | /* |
207 | The temporary table uses very first index or constrain for |
208 | checking unique constrain. |
209 | */ |
210 | if (!(find_res= table->file->find_unique_row(table->record[0], 0))) |
211 | { |
212 | DBUG_ASSERT(!table->triggers); |
213 | if (table->field[0]->val_int() != prev_step) |
214 | { |
215 | rc= 0; |
216 | goto end; |
217 | } |
218 | store_record(table, record[1]); |
219 | table->field[0]->store(curr_step, 0); |
220 | not_reported_error= table->file->ha_update_tmp_row(table->record[1], |
221 | table->record[0]); |
222 | rc= MY_TEST(not_reported_error); |
223 | DBUG_ASSERT(rc != HA_ERR_RECORD_IS_THE_SAME); |
224 | goto end; |
225 | } |
226 | else |
227 | { |
228 | if ((rc= not_reported_error= (find_res != 1))) |
229 | goto end; |
230 | } |
231 | break; |
232 | } |
233 | default: |
234 | DBUG_ASSERT(0); |
235 | } |
236 | rc= 0; |
237 | |
238 | end: |
239 | if (unlikely(not_reported_error)) |
240 | { |
241 | DBUG_ASSERT(rc); |
242 | table->file->print_error(not_reported_error, MYF(0)); |
243 | } |
244 | return rc; |
245 | } |
246 | |
247 | bool select_unit::send_eof() |
248 | { |
249 | if (step != INTERSECT_TYPE || |
250 | (thd->lex->current_select->next_select() && |
251 | thd->lex->current_select->next_select()->linkage == INTERSECT_TYPE)) |
252 | { |
253 | /* |
254 | it is not INTESECT or next SELECT in the sequence is INTERSECT so no |
255 | need filtering (the last INTERSECT in this sequence of intersects will |
256 | filter). |
257 | */ |
258 | return 0; |
259 | } |
260 | |
261 | /* |
262 | It is last select in the sequence of INTERSECTs so we should filter out |
263 | all records except marked with actual counter. |
264 | |
265 | TODO: as optimization for simple case this could be moved to |
266 | 'fake_select' WHERE condition |
267 | */ |
268 | handler *file= table->file; |
269 | int error; |
270 | |
271 | if (unlikely(file->ha_rnd_init_with_error(1))) |
272 | return 1; |
273 | |
274 | do |
275 | { |
276 | if (unlikely(error= file->ha_rnd_next(table->record[0]))) |
277 | { |
278 | if (error == HA_ERR_END_OF_FILE) |
279 | { |
280 | error= 0; |
281 | break; |
282 | } |
283 | break; |
284 | } |
285 | if (table->field[0]->val_int() != curr_step) |
286 | error= file->ha_delete_tmp_row(table->record[0]); |
287 | } while (likely(!error)); |
288 | file->ha_rnd_end(); |
289 | |
290 | if (unlikely(error)) |
291 | table->file->print_error(error, MYF(0)); |
292 | |
293 | return(MY_TEST(error)); |
294 | } |
295 | |
296 | |
297 | int select_union_recursive::send_data(List<Item> &values) |
298 | { |
299 | int rc= select_unit::send_data(values); |
300 | |
301 | if (rc == 0 && |
302 | write_err != HA_ERR_FOUND_DUPP_KEY && |
303 | write_err != HA_ERR_FOUND_DUPP_UNIQUE) |
304 | { |
305 | int err; |
306 | if ((err= incr_table->file->ha_write_tmp_row(table->record[0]))) |
307 | { |
308 | bool is_duplicate; |
309 | rc= create_internal_tmp_table_from_heap(thd, incr_table, |
310 | tmp_table_param.start_recinfo, |
311 | &tmp_table_param.recinfo, |
312 | err, 1, &is_duplicate); |
313 | } |
314 | } |
315 | |
316 | return rc; |
317 | } |
318 | |
319 | |
320 | bool select_unit::flush() |
321 | { |
322 | int error; |
323 | if (unlikely((error=table->file->extra(HA_EXTRA_NO_CACHE)))) |
324 | { |
325 | table->file->print_error(error, MYF(0)); |
326 | return 1; |
327 | } |
328 | return 0; |
329 | } |
330 | |
331 | |
332 | /* |
333 | Create a temporary table to store the result of select_union. |
334 | |
335 | SYNOPSIS |
336 | select_unit::create_result_table() |
337 | thd thread handle |
338 | column_types a list of items used to define columns of the |
339 | temporary table |
340 | is_union_distinct if set, the temporary table will eliminate |
341 | duplicates on insert |
342 | options create options |
343 | table_alias name of the temporary table |
344 | bit_fields_as_long convert bit fields to ulonglong |
345 | create_table whether to physically create result table |
346 | keep_row_order keep rows in order as they were inserted |
347 | hidden number of hidden fields (for INTERSECT) |
348 | |
349 | DESCRIPTION |
350 | Create a temporary table that is used to store the result of a UNION, |
351 | derived table, or a materialized cursor. |
352 | |
353 | RETURN VALUE |
354 | 0 The table has been created successfully. |
355 | 1 create_tmp_table failed. |
356 | */ |
357 | |
358 | bool |
359 | select_unit::create_result_table(THD *thd_arg, List<Item> *column_types, |
360 | bool is_union_distinct, ulonglong options, |
361 | const LEX_CSTRING *alias, |
362 | bool bit_fields_as_long, bool create_table, |
363 | bool keep_row_order, |
364 | uint hidden) |
365 | { |
366 | DBUG_ASSERT(table == 0); |
367 | tmp_table_param.init(); |
368 | tmp_table_param.field_count= column_types->elements; |
369 | tmp_table_param.bit_fields_as_long= bit_fields_as_long; |
370 | tmp_table_param.hidden_field_count= hidden; |
371 | |
372 | if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, |
373 | (ORDER*) 0, is_union_distinct, 1, |
374 | options, HA_POS_ERROR, alias, |
375 | !create_table, keep_row_order))) |
376 | return TRUE; |
377 | |
378 | table->keys_in_use_for_query.clear_all(); |
379 | for (uint i=0; i < table->s->fields; i++) |
380 | table->field[i]->flags &= ~PART_KEY_FLAG; |
381 | |
382 | if (create_table) |
383 | { |
384 | table->file->extra(HA_EXTRA_WRITE_CACHE); |
385 | table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); |
386 | } |
387 | return FALSE; |
388 | } |
389 | |
390 | bool |
391 | select_union_recursive::create_result_table(THD *thd_arg, |
392 | List<Item> *column_types, |
393 | bool is_union_distinct, |
394 | ulonglong options, |
395 | const LEX_CSTRING *alias, |
396 | bool bit_fields_as_long, |
397 | bool create_table, |
398 | bool keep_row_order, |
399 | uint hidden) |
400 | { |
401 | if (select_unit::create_result_table(thd_arg, column_types, |
402 | is_union_distinct, options, |
403 | &empty_clex_str, bit_fields_as_long, |
404 | create_table, keep_row_order, |
405 | hidden)) |
406 | return true; |
407 | |
408 | if (! (incr_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, |
409 | (ORDER*) 0, false, 1, |
410 | options, HA_POS_ERROR, &empty_clex_str, |
411 | true, keep_row_order))) |
412 | return true; |
413 | |
414 | incr_table->keys_in_use_for_query.clear_all(); |
415 | for (uint i=0; i < table->s->fields; i++) |
416 | incr_table->field[i]->flags &= ~PART_KEY_FLAG; |
417 | |
418 | TABLE *rec_table= 0; |
419 | if (! (rec_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, |
420 | (ORDER*) 0, false, 1, |
421 | options, HA_POS_ERROR, alias, |
422 | true, keep_row_order))) |
423 | return true; |
424 | |
425 | rec_table->keys_in_use_for_query.clear_all(); |
426 | for (uint i=0; i < table->s->fields; i++) |
427 | rec_table->field[i]->flags &= ~PART_KEY_FLAG; |
428 | |
429 | if (rec_tables.push_back(rec_table)) |
430 | return true; |
431 | |
432 | return false; |
433 | } |
434 | |
435 | |
436 | /** |
437 | Reset and empty the temporary table that stores the materialized query |
438 | result. |
439 | |
440 | @note The cleanup performed here is exactly the same as for the two temp |
441 | tables of JOIN - exec_tmp_table_[1 | 2]. |
442 | */ |
443 | |
444 | void select_unit::cleanup() |
445 | { |
446 | table->file->extra(HA_EXTRA_RESET_STATE); |
447 | table->file->ha_delete_all_rows(); |
448 | } |
449 | |
450 | |
451 | void select_union_recursive::cleanup() |
452 | { |
453 | if (table) |
454 | { |
455 | select_unit::cleanup(); |
456 | free_tmp_table(thd, table); |
457 | } |
458 | |
459 | if (incr_table) |
460 | { |
461 | if (incr_table->is_created()) |
462 | { |
463 | incr_table->file->extra(HA_EXTRA_RESET_STATE); |
464 | incr_table->file->ha_delete_all_rows(); |
465 | } |
466 | free_tmp_table(thd, incr_table); |
467 | } |
468 | |
469 | List_iterator<TABLE> it(rec_tables); |
470 | TABLE *tab; |
471 | while ((tab= it++)) |
472 | { |
473 | if (tab->is_created()) |
474 | { |
475 | tab->file->extra(HA_EXTRA_RESET_STATE); |
476 | tab->file->ha_delete_all_rows(); |
477 | } |
478 | /* |
479 | The table will be closed later in close_thread_tables(), |
480 | because it might be used in the statements like |
481 | ANALYZE WITH r AS (...) SELECT * from r |
482 | where r is defined through recursion. |
483 | */ |
484 | tab->next= thd->rec_tables; |
485 | thd->rec_tables= tab; |
486 | } |
487 | } |
488 | |
489 | |
490 | /** |
491 | Replace the current result with new_result and prepare it. |
492 | |
493 | @param new_result New result pointer |
494 | |
495 | @retval FALSE Success |
496 | @retval TRUE Error |
497 | */ |
498 | |
499 | bool select_union_direct::change_result(select_result *new_result) |
500 | { |
501 | result= new_result; |
502 | return (result->prepare(unit->types, unit) || result->prepare2(NULL)); |
503 | } |
504 | |
505 | |
506 | bool select_union_direct::postponed_prepare(List<Item> &types) |
507 | { |
508 | if (result != NULL) |
509 | return (result->prepare(types, unit) || result->prepare2(NULL)); |
510 | else |
511 | return false; |
512 | } |
513 | |
514 | |
515 | bool select_union_direct::send_result_set_metadata(List<Item> &list, uint flags) |
516 | { |
517 | if (done_send_result_set_metadata) |
518 | return false; |
519 | done_send_result_set_metadata= true; |
520 | |
521 | /* |
522 | Set global offset and limit to be used in send_data(). These can |
523 | be variables in prepared statements or stored programs, so they |
524 | must be reevaluated for each execution. |
525 | */ |
526 | offset= unit->global_parameters()->get_offset(); |
527 | limit= unit->global_parameters()->get_limit(); |
528 | if (limit + offset >= limit) |
529 | limit+= offset; |
530 | else |
531 | limit= HA_POS_ERROR; /* purecov: inspected */ |
532 | |
533 | return result->send_result_set_metadata(unit->types, flags); |
534 | } |
535 | |
536 | |
537 | int select_union_direct::send_data(List<Item> &items) |
538 | { |
539 | if (!limit) |
540 | return false; |
541 | limit--; |
542 | if (offset) |
543 | { |
544 | offset--; |
545 | return false; |
546 | } |
547 | |
548 | send_records++; |
549 | fill_record(thd, table, table->field, items, true, false); |
550 | if (unlikely(thd->is_error())) |
551 | return true; /* purecov: inspected */ |
552 | |
553 | return result->send_data(unit->item_list); |
554 | } |
555 | |
556 | |
557 | bool select_union_direct::initialize_tables (JOIN *join) |
558 | { |
559 | if (done_initialize_tables) |
560 | return false; |
561 | done_initialize_tables= true; |
562 | |
563 | return result->initialize_tables(join); |
564 | } |
565 | |
566 | |
567 | bool select_union_direct::send_eof() |
568 | { |
569 | // Reset for each SELECT_LEX, so accumulate here |
570 | limit_found_rows+= thd->limit_found_rows; |
571 | |
572 | if (unit->thd->lex->current_select == last_select_lex) |
573 | { |
574 | thd->limit_found_rows= limit_found_rows; |
575 | |
576 | // Reset and make ready for re-execution |
577 | done_send_result_set_metadata= false; |
578 | done_initialize_tables= false; |
579 | |
580 | return result->send_eof(); |
581 | } |
582 | else |
583 | return false; |
584 | } |
585 | |
586 | |
587 | /* |
588 | initialization procedures before fake_select_lex preparation() |
589 | |
590 | SYNOPSIS |
591 | st_select_lex_unit::init_prepare_fake_select_lex() |
592 | thd - thread handler |
593 | first_execution - TRUE at the first execution of the union |
594 | |
595 | RETURN |
596 | options of SELECT |
597 | */ |
598 | |
599 | void |
600 | st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg, |
601 | bool first_execution) |
602 | { |
603 | thd_arg->lex->current_select= fake_select_lex; |
604 | fake_select_lex->table_list.link_in_list(&result_table_list, |
605 | &result_table_list.next_local); |
606 | fake_select_lex->context.table_list= |
607 | fake_select_lex->context.first_name_resolution_table= |
608 | fake_select_lex->get_table_list(); |
609 | /* |
610 | The flag fake_select_lex->first_execution indicates whether this is |
611 | called at the first execution of the statement, while first_execution |
612 | shows whether this is called at the first execution of the union that |
613 | may form just a subselect. |
614 | */ |
615 | if (!fake_select_lex->first_execution && first_execution) |
616 | { |
617 | for (ORDER *order= global_parameters()->order_list.first; |
618 | order; |
619 | order= order->next) |
620 | order->item= &order->item_ptr; |
621 | } |
622 | for (ORDER *order= global_parameters()->order_list.first; |
623 | order; |
624 | order=order->next) |
625 | { |
626 | (*order->item)->walk(&Item::change_context_processor, 0, |
627 | &fake_select_lex->context); |
628 | (*order->item)->walk(&Item::set_fake_select_as_master_processor, 0, |
629 | fake_select_lex); |
630 | } |
631 | } |
632 | |
633 | |
634 | bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl, |
635 | select_result *tmp_result, |
636 | ulong additional_options, |
637 | bool is_union_select) |
638 | { |
639 | DBUG_ENTER("st_select_lex_unit::prepare_join" ); |
640 | TABLE_LIST *derived= sl->master_unit()->derived; |
641 | bool can_skip_order_by; |
642 | sl->options|= SELECT_NO_UNLOCK; |
643 | JOIN *join= new JOIN(thd_arg, sl->item_list, |
644 | (sl->options | thd_arg->variables.option_bits | |
645 | additional_options), |
646 | tmp_result); |
647 | if (!join) |
648 | DBUG_RETURN(true); |
649 | |
650 | thd_arg->lex->current_select= sl; |
651 | |
652 | can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit); |
653 | |
654 | saved_error= join->prepare(sl->table_list.first, |
655 | sl->with_wild, |
656 | (derived && derived->merged ? NULL : sl->where), |
657 | (can_skip_order_by ? 0 : |
658 | sl->order_list.elements) + |
659 | sl->group_list.elements, |
660 | can_skip_order_by ? |
661 | NULL : sl->order_list.first, |
662 | can_skip_order_by, |
663 | sl->group_list.first, |
664 | sl->having, |
665 | (is_union_select ? NULL : |
666 | thd_arg->lex->proc_list.first), |
667 | sl, this); |
668 | |
669 | /* There are no * in the statement anymore (for PS) */ |
670 | sl->with_wild= 0; |
671 | last_procedure= join->procedure; |
672 | |
673 | if (unlikely(saved_error || (saved_error= thd_arg->is_fatal_error))) |
674 | DBUG_RETURN(true); |
675 | /* |
676 | Remove all references from the select_lex_units to the subqueries that |
677 | are inside the ORDER BY clause. |
678 | */ |
679 | if (can_skip_order_by) |
680 | { |
681 | for (ORDER *ord= (ORDER *)sl->order_list.first; ord; ord= ord->next) |
682 | { |
683 | (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); |
684 | } |
685 | } |
686 | DBUG_RETURN(false); |
687 | } |
688 | |
689 | |
690 | /** |
691 | Aggregate data type handlers for the "count" leftmost UNION parts. |
692 | */ |
693 | bool st_select_lex_unit::join_union_type_handlers(THD *thd_arg, |
694 | Type_holder *holders, |
695 | uint count) |
696 | { |
697 | DBUG_ENTER("st_select_lex_unit::join_union_type_handlers" ); |
698 | SELECT_LEX *first_sl= first_select(), *sl= first_sl; |
699 | for (uint i= 0; i < count ; sl= sl->next_select(), i++) |
700 | { |
701 | Item *item; |
702 | List_iterator_fast<Item> it(sl->item_list); |
703 | for (uint pos= 0; (item= it++); pos++) |
704 | { |
705 | const Type_handler *item_type_handler= item->real_type_handler(); |
706 | if (sl == first_sl) |
707 | holders[pos].set_handler(item_type_handler); |
708 | else |
709 | { |
710 | DBUG_ASSERT(first_sl->item_list.elements == sl->item_list.elements); |
711 | if (holders[pos].aggregate_for_result(item_type_handler)) |
712 | { |
713 | my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), |
714 | holders[pos].type_handler()->name().ptr(), |
715 | item_type_handler->name().ptr(), |
716 | "UNION" ); |
717 | DBUG_RETURN(true); |
718 | } |
719 | } |
720 | } |
721 | } |
722 | DBUG_RETURN(false); |
723 | } |
724 | |
725 | |
726 | /** |
727 | Aggregate data type attributes for the "count" leftmost UNION parts. |
728 | */ |
729 | bool st_select_lex_unit::join_union_type_attributes(THD *thd_arg, |
730 | Type_holder *holders, |
731 | uint count) |
732 | { |
733 | DBUG_ENTER("st_select_lex_unit::join_union_type_attributes" ); |
734 | SELECT_LEX *sl, *first_sl= first_select(); |
735 | uint item_pos; |
736 | for (uint pos= 0; pos < first_sl->item_list.elements; pos++) |
737 | { |
738 | if (holders[pos].alloc_arguments(thd_arg, count)) |
739 | DBUG_RETURN(true); |
740 | } |
741 | for (item_pos= 0, sl= first_sl ; |
742 | item_pos < count; |
743 | sl= sl->next_select(), item_pos++) |
744 | { |
745 | Item *item_tmp; |
746 | List_iterator_fast<Item> itx(sl->item_list); |
747 | for (uint holder_pos= 0 ; (item_tmp= itx++); holder_pos++) |
748 | { |
749 | /* |
750 | If the outer query has a GROUP BY clause, an outer reference to this |
751 | query block may have been wrapped in a Item_outer_ref, which has not |
752 | been fixed yet. An Item_type_holder must be created based on a fixed |
753 | Item, so use the inner Item instead. |
754 | */ |
755 | DBUG_ASSERT(item_tmp->fixed || |
756 | (item_tmp->type() == Item::REF_ITEM && |
757 | ((Item_ref *)(item_tmp))->ref_type() == |
758 | Item_ref::OUTER_REF)); |
759 | if (!item_tmp->fixed) |
760 | item_tmp= item_tmp->real_item(); |
761 | holders[holder_pos].add_argument(item_tmp); |
762 | } |
763 | } |
764 | for (uint pos= 0; pos < first_sl->item_list.elements; pos++) |
765 | { |
766 | if (holders[pos].aggregate_attributes(thd_arg)) |
767 | DBUG_RETURN(true); |
768 | } |
769 | DBUG_RETURN(false); |
770 | } |
771 | |
772 | |
773 | /** |
774 | Join data types for the leftmost "count" UNION parts |
775 | and store corresponding Item_type_holder's into "types". |
776 | */ |
777 | bool st_select_lex_unit::join_union_item_types(THD *thd_arg, |
778 | List<Item> &types, |
779 | uint count) |
780 | { |
781 | DBUG_ENTER("st_select_lex_unit::join_union_select_list_types" ); |
782 | SELECT_LEX *first_sl= first_select(); |
783 | Type_holder *holders; |
784 | |
785 | if (!(holders= new (thd_arg->mem_root) |
786 | Type_holder[first_sl->item_list.elements]) || |
787 | join_union_type_handlers(thd_arg, holders, count) || |
788 | join_union_type_attributes(thd_arg, holders, count)) |
789 | DBUG_RETURN(true); |
790 | |
791 | bool is_recursive= with_element && with_element->is_recursive; |
792 | types.empty(); |
793 | List_iterator_fast<Item> it(first_sl->item_list); |
794 | Item *item_tmp; |
795 | for (uint pos= 0; (item_tmp= it++); pos++) |
796 | { |
797 | /* |
798 | SQL standard requires forced nullability only for |
799 | recursive columns. However type aggregation in our |
800 | implementation so far does not differentiate between |
801 | recursive and non-recursive columns of a recursive CTE. |
802 | TODO: this should be fixed. |
803 | */ |
804 | bool pos_maybe_null= is_recursive ? true : holders[pos].get_maybe_null(); |
805 | |
806 | /* Error's in 'new' will be detected after loop */ |
807 | types.push_back(new (thd_arg->mem_root) |
808 | Item_type_holder(thd_arg, |
809 | item_tmp, |
810 | holders[pos].type_handler(), |
811 | &holders[pos]/*Type_all_attributes*/, |
812 | pos_maybe_null)); |
813 | } |
814 | if (unlikely(thd_arg->is_fatal_error)) |
815 | DBUG_RETURN(true); // out of memory |
816 | DBUG_RETURN(false); |
817 | } |
818 | |
819 | |
820 | bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg, |
821 | select_result *sel_result, |
822 | ulong additional_options) |
823 | { |
824 | SELECT_LEX *lex_select_save= thd->lex->current_select; |
825 | SELECT_LEX *sl, *first_sl= first_select(); |
826 | bool is_recursive= with_element && with_element->is_recursive; |
827 | bool is_rec_result_table_created= false; |
828 | uint union_part_count= 0; |
829 | select_result *tmp_result; |
830 | bool is_union_select; |
831 | bool have_except= FALSE, have_intersect= FALSE; |
832 | bool instantiate_tmp_table= false; |
833 | bool single_tvc= !first_sl->next_select() && first_sl->tvc; |
834 | DBUG_ENTER("st_select_lex_unit::prepare" ); |
835 | DBUG_ASSERT(thd == current_thd); |
836 | |
837 | if (is_recursive && (sl= first_sl->next_select())) |
838 | { |
839 | SELECT_LEX *next_sl; |
840 | for ( ; ; sl= next_sl) |
841 | { |
842 | next_sl= sl->next_select(); |
843 | if (!next_sl) |
844 | break; |
845 | if (next_sl->with_all_modifier != sl->with_all_modifier) |
846 | { |
847 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), |
848 | "mix of ALL and DISTINCT UNION operations in recursive CTE spec" ); |
849 | DBUG_RETURN(TRUE); |
850 | } |
851 | } |
852 | } |
853 | |
854 | describe= additional_options & SELECT_DESCRIBE; |
855 | |
856 | /* |
857 | Save fake_select_lex in case we don't need it for anything but |
858 | global parameters. |
859 | */ |
860 | if (saved_fake_select_lex == NULL) // Don't overwrite on PS second prepare |
861 | saved_fake_select_lex= fake_select_lex; |
862 | |
863 | /* |
864 | result object should be reassigned even if preparing already done for |
865 | max/min subquery (ALL/ANY optimization) |
866 | */ |
867 | result= sel_result; |
868 | |
869 | if (prepared) |
870 | { |
871 | if (describe) |
872 | { |
873 | /* fast reinit for EXPLAIN */ |
874 | for (sl= first_sl; sl; sl= sl->next_select()) |
875 | { |
876 | if (sl->tvc) |
877 | { |
878 | sl->tvc->result= result; |
879 | if (result->prepare(sl->item_list, this)) |
880 | DBUG_RETURN(TRUE); |
881 | sl->tvc->select_options|= SELECT_DESCRIBE; |
882 | } |
883 | else |
884 | { |
885 | sl->join->result= result; |
886 | select_limit_cnt= HA_POS_ERROR; |
887 | offset_limit_cnt= 0; |
888 | if (!sl->join->procedure && |
889 | result->prepare(sl->join->fields_list, this)) |
890 | { |
891 | DBUG_RETURN(TRUE); |
892 | } |
893 | sl->join->select_options|= SELECT_DESCRIBE; |
894 | sl->join->reinit(); |
895 | } |
896 | } |
897 | } |
898 | DBUG_RETURN(FALSE); |
899 | } |
900 | prepared= 1; |
901 | saved_error= FALSE; |
902 | |
903 | thd->lex->current_select= sl= first_sl; |
904 | found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS; |
905 | is_union_select= is_unit_op() || fake_select_lex || single_tvc; |
906 | |
907 | for (SELECT_LEX *s= first_sl; s; s= s->next_select()) |
908 | { |
909 | switch (s->linkage) |
910 | { |
911 | case INTERSECT_TYPE: |
912 | have_intersect= TRUE; |
913 | break; |
914 | case EXCEPT_TYPE: |
915 | have_except= TRUE; |
916 | break; |
917 | default: |
918 | break; |
919 | } |
920 | } |
921 | /* Global option */ |
922 | |
923 | if (is_union_select || is_recursive) |
924 | { |
925 | if ((is_unit_op() && !union_needs_tmp_table() && |
926 | !have_except && !have_intersect) || single_tvc) |
927 | { |
928 | SELECT_LEX *last= first_select(); |
929 | while (last->next_select()) |
930 | last= last->next_select(); |
931 | if (!(tmp_result= union_result= |
932 | new (thd->mem_root) select_union_direct(thd, sel_result, |
933 | last))) |
934 | goto err; /* purecov: inspected */ |
935 | fake_select_lex= NULL; |
936 | instantiate_tmp_table= false; |
937 | } |
938 | else |
939 | { |
940 | if (!is_recursive) |
941 | union_result= new (thd->mem_root) select_unit(thd); |
942 | else |
943 | { |
944 | with_element->rec_result= |
945 | new (thd->mem_root) select_union_recursive(thd); |
946 | union_result= with_element->rec_result; |
947 | if (fake_select_lex) |
948 | { |
949 | if (fake_select_lex->order_list.first || |
950 | fake_select_lex->explicit_limit) |
951 | { |
952 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), |
953 | "global ORDER_BY/LIMIT in recursive CTE spec" ); |
954 | goto err; |
955 | } |
956 | fake_select_lex->cleanup(); |
957 | fake_select_lex= NULL; |
958 | } |
959 | } |
960 | if (!(tmp_result= union_result)) |
961 | goto err; /* purecov: inspected */ |
962 | instantiate_tmp_table= true; |
963 | } |
964 | } |
965 | else |
966 | tmp_result= sel_result; |
967 | |
968 | sl->context.resolve_in_select_list= TRUE; |
969 | |
970 | if (!is_union_select && !is_recursive) |
971 | { |
972 | if (sl->tvc) |
973 | { |
974 | if (sl->tvc->prepare(thd, sl, tmp_result, this)) |
975 | goto err; |
976 | } |
977 | else if (prepare_join(thd, first_sl, tmp_result, additional_options, |
978 | is_union_select)) |
979 | goto err; |
980 | types= first_sl->item_list; |
981 | goto cont; |
982 | } |
983 | |
984 | for (;sl; sl= sl->next_select(), union_part_count++) |
985 | { |
986 | if (sl->tvc) |
987 | { |
988 | if (sl->tvc->prepare(thd, sl, tmp_result, this)) |
989 | goto err; |
990 | } |
991 | else if (prepare_join(thd, sl, tmp_result, additional_options, |
992 | is_union_select)) |
993 | goto err; |
994 | |
995 | /* |
996 | setup_tables_done_option should be set only for very first SELECT, |
997 | because it protect from secont setup_tables call for select-like non |
998 | select commands (DELETE/INSERT/...) and they use only very first |
999 | SELECT (for union it can be only INSERT ... SELECT). |
1000 | */ |
1001 | additional_options&= ~OPTION_SETUP_TABLES_DONE; |
1002 | |
1003 | /* |
1004 | Use items list of underlaid select for derived tables to preserve |
1005 | information about fields lengths and exact types |
1006 | */ |
1007 | if (sl == first_sl) |
1008 | { |
1009 | if (with_element) |
1010 | { |
1011 | if (derived_arg->with->rename_columns_of_derived_unit(thd, this)) |
1012 | goto err; |
1013 | if (check_duplicate_names(thd, sl->item_list, 0)) |
1014 | goto err; |
1015 | } |
1016 | } |
1017 | else |
1018 | { |
1019 | if (first_sl->item_list.elements != sl->item_list.elements) |
1020 | { |
1021 | my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, |
1022 | ER_THD(thd, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), |
1023 | MYF(0)); |
1024 | goto err; |
1025 | } |
1026 | } |
1027 | if (is_recursive) |
1028 | { |
1029 | if (!with_element->is_anchor(sl)) |
1030 | sl->uncacheable|= UNCACHEABLE_UNITED; |
1031 | if (!is_rec_result_table_created && |
1032 | (!sl->next_select() || |
1033 | sl->next_select() == with_element->first_recursive)) |
1034 | { |
1035 | ulonglong create_options; |
1036 | create_options= (first_sl->options | thd->variables.option_bits | |
1037 | TMP_TABLE_ALL_COLUMNS); |
1038 | // Join data types for all non-recursive parts of a recursive UNION |
1039 | if (join_union_item_types(thd, types, union_part_count + 1)) |
1040 | goto err; |
1041 | if (union_result->create_result_table(thd, &types, |
1042 | MY_TEST(union_distinct), |
1043 | create_options, |
1044 | &derived_arg->alias, false, |
1045 | instantiate_tmp_table, false, |
1046 | 0)) |
1047 | goto err; |
1048 | if (!derived_arg->table) |
1049 | derived_arg->table= derived_arg->derived_result->table= |
1050 | with_element->rec_result->rec_tables.head(); |
1051 | with_element->mark_as_with_prepared_anchor(); |
1052 | is_rec_result_table_created= true; |
1053 | } |
1054 | } |
1055 | } |
1056 | // In case of a non-recursive UNION, join data types for all UNION parts. |
1057 | if (!is_recursive && join_union_item_types(thd, types, union_part_count)) |
1058 | goto err; |
1059 | |
1060 | cont: |
1061 | /* |
1062 | If the query is using select_union_direct, we have postponed |
1063 | preparation of the underlying select_result until column types |
1064 | are known. |
1065 | */ |
1066 | if (union_result != NULL && union_result->postponed_prepare(types)) |
1067 | DBUG_RETURN(true); |
1068 | |
1069 | if (is_union_select) |
1070 | { |
1071 | /* |
1072 | Check that it was possible to aggregate |
1073 | all collations together for UNION. |
1074 | */ |
1075 | List_iterator_fast<Item> tp(types); |
1076 | Item *type; |
1077 | ulonglong create_options; |
1078 | uint save_tablenr= 0; |
1079 | table_map save_map= 0; |
1080 | uint save_maybe_null= 0; |
1081 | |
1082 | while ((type= tp++)) |
1083 | { |
1084 | if (type->cmp_type() == STRING_RESULT && |
1085 | type->collation.derivation == DERIVATION_NONE) |
1086 | { |
1087 | my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), "UNION" ); |
1088 | goto err; |
1089 | } |
1090 | } |
1091 | |
1092 | /* |
1093 | Disable the usage of fulltext searches in the last union branch. |
1094 | This is a temporary 5.x limitation because of the way the fulltext |
1095 | search functions are handled by the optimizer. |
1096 | This is manifestation of the more general problems of "taking away" |
1097 | parts of a SELECT statement post-fix_fields(). This is generally not |
1098 | doable since various flags are collected in various places (e.g. |
1099 | SELECT_LEX) that carry information about the presence of certain |
1100 | expressions or constructs in the parts of the query. |
1101 | When part of the query is taken away it's not clear how to "divide" |
1102 | the meaning of these accumulated flags and what to carry over to the |
1103 | recipient query (SELECT_LEX). |
1104 | */ |
1105 | if (global_parameters()->ftfunc_list->elements && |
1106 | global_parameters()->order_list.elements && |
1107 | global_parameters() != fake_select_lex) |
1108 | { |
1109 | ORDER *ord; |
1110 | Item_func::Functype ft= Item_func::FT_FUNC; |
1111 | for (ord= global_parameters()->order_list.first; ord; ord= ord->next) |
1112 | if ((*ord->item)->walk (&Item::find_function_processor, FALSE, &ft)) |
1113 | { |
1114 | my_error (ER_CANT_USE_OPTION_HERE, MYF(0), "MATCH()" ); |
1115 | goto err; |
1116 | } |
1117 | } |
1118 | |
1119 | |
1120 | create_options= (first_sl->options | thd->variables.option_bits | |
1121 | TMP_TABLE_ALL_COLUMNS); |
1122 | /* |
1123 | Force the temporary table to be a MyISAM table if we're going to use |
1124 | fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading |
1125 | from it (this should be removed in 5.2 when fulltext search is moved |
1126 | out of MyISAM). |
1127 | */ |
1128 | if (global_parameters()->ftfunc_list->elements) |
1129 | create_options= create_options | TMP_TABLE_FORCE_MYISAM; |
1130 | |
1131 | if (!is_recursive) |
1132 | { |
1133 | uint hidden= 0; |
1134 | if (have_intersect) |
1135 | { |
1136 | hidden= 1; |
1137 | if (!intersect_mark) |
1138 | { |
1139 | /* |
1140 | For intersect we add a hidden column first that contains |
1141 | the current select number of the time when the row was |
1142 | added to the temporary table |
1143 | */ |
1144 | |
1145 | Query_arena *arena, backup_arena; |
1146 | arena= thd->activate_stmt_arena_if_needed(&backup_arena); |
1147 | |
1148 | intersect_mark= new (thd->mem_root) Item_int(thd, 0); |
1149 | |
1150 | if (arena) |
1151 | thd->restore_active_arena(arena, &backup_arena); |
1152 | |
1153 | if (!intersect_mark) |
1154 | goto err; |
1155 | } |
1156 | else |
1157 | intersect_mark->value= 0; //reset |
1158 | types.push_front(union_result->intersect_mark= intersect_mark); |
1159 | union_result->intersect_mark->name.str= "___" ; |
1160 | union_result->intersect_mark->name.length= 3; |
1161 | } |
1162 | bool error= |
1163 | union_result->create_result_table(thd, &types, |
1164 | MY_TEST(union_distinct), |
1165 | create_options, &empty_clex_str, false, |
1166 | instantiate_tmp_table, false, |
1167 | hidden); |
1168 | if (intersect_mark) |
1169 | types.pop(); |
1170 | if (unlikely(error)) |
1171 | goto err; |
1172 | } |
1173 | if (fake_select_lex && !fake_select_lex->first_cond_optimization) |
1174 | { |
1175 | save_tablenr= result_table_list.tablenr_exec; |
1176 | save_map= result_table_list.map_exec; |
1177 | save_maybe_null= result_table_list.maybe_null_exec; |
1178 | } |
1179 | bzero((char*) &result_table_list, sizeof(result_table_list)); |
1180 | result_table_list.db.str= (char*) "" ; |
1181 | result_table_list.db.length= 0; |
1182 | result_table_list.table_name.str= result_table_list.alias.str= "union" ; |
1183 | result_table_list.table_name.length= result_table_list.alias.length= sizeof("union" )-1; |
1184 | result_table_list.table= table= union_result->table; |
1185 | if (fake_select_lex && !fake_select_lex->first_cond_optimization) |
1186 | { |
1187 | result_table_list.tablenr_exec= save_tablenr; |
1188 | result_table_list.map_exec= save_map; |
1189 | result_table_list.maybe_null_exec= save_maybe_null; |
1190 | } |
1191 | |
1192 | thd->lex->current_select= lex_select_save; |
1193 | if (!item_list.elements) |
1194 | { |
1195 | Query_arena *arena, backup_arena; |
1196 | |
1197 | arena= thd->activate_stmt_arena_if_needed(&backup_arena); |
1198 | |
1199 | saved_error= table->fill_item_list(&item_list); |
1200 | // Item_list is inherited from 'types', so there could be the counter |
1201 | if (intersect_mark) |
1202 | item_list.pop(); // remove intersect counter |
1203 | |
1204 | if (arena) |
1205 | thd->restore_active_arena(arena, &backup_arena); |
1206 | |
1207 | if (unlikely(saved_error)) |
1208 | goto err; |
1209 | |
1210 | if (fake_select_lex != NULL && |
1211 | (thd->stmt_arena->is_stmt_prepare() || |
1212 | (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW))) |
1213 | { |
1214 | /* Validate the global parameters of this union */ |
1215 | |
1216 | init_prepare_fake_select_lex(thd, TRUE); |
1217 | /* Should be done only once (the only item_list per statement) */ |
1218 | DBUG_ASSERT(fake_select_lex->join == 0); |
1219 | if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->variables.option_bits, |
1220 | result))) |
1221 | { |
1222 | fake_select_lex->table_list.empty(); |
1223 | DBUG_RETURN(TRUE); |
1224 | } |
1225 | |
1226 | /* |
1227 | Fake st_select_lex should have item list for correct ref_array |
1228 | allocation. |
1229 | */ |
1230 | fake_select_lex->item_list= item_list; |
1231 | |
1232 | thd->lex->current_select= fake_select_lex; |
1233 | |
1234 | /* |
1235 | We need to add up n_sum_items in order to make the correct |
1236 | allocation in setup_ref_array(). |
1237 | */ |
1238 | fake_select_lex->n_child_sum_items+= global_parameters()->n_sum_items; |
1239 | |
1240 | saved_error= fake_select_lex->join-> |
1241 | prepare(fake_select_lex->table_list.first, |
1242 | 0, 0, |
1243 | global_parameters()->order_list.elements, // og_num |
1244 | global_parameters()->order_list.first, // order |
1245 | false, NULL, NULL, NULL, |
1246 | fake_select_lex, this); |
1247 | fake_select_lex->table_list.empty(); |
1248 | } |
1249 | } |
1250 | else |
1251 | { |
1252 | /* |
1253 | We're in execution of a prepared statement or stored procedure: |
1254 | reset field items to point at fields from the created temporary table. |
1255 | */ |
1256 | table->reset_item_list(&item_list, intersect_mark ? 1 : 0); |
1257 | } |
1258 | } |
1259 | |
1260 | thd->lex->current_select= lex_select_save; |
1261 | |
1262 | DBUG_RETURN(saved_error || thd->is_fatal_error); |
1263 | |
1264 | err: |
1265 | thd->lex->current_select= lex_select_save; |
1266 | (void) cleanup(); |
1267 | DBUG_RETURN(TRUE); |
1268 | } |
1269 | |
1270 | |
1271 | /** |
1272 | Run optimization phase. |
1273 | |
1274 | @return FALSE unit successfully passed optimization phase. |
1275 | @return TRUE an error occur. |
1276 | */ |
1277 | bool st_select_lex_unit::optimize() |
1278 | { |
1279 | SELECT_LEX *lex_select_save= thd->lex->current_select; |
1280 | SELECT_LEX *select_cursor=first_select(); |
1281 | DBUG_ENTER("st_select_lex_unit::optimize" ); |
1282 | |
1283 | if (optimized && !uncacheable && !describe) |
1284 | DBUG_RETURN(FALSE); |
1285 | |
1286 | if (with_element && with_element->is_recursive && optimize_started) |
1287 | DBUG_RETURN(FALSE); |
1288 | optimize_started= true; |
1289 | |
1290 | if (uncacheable || !item || !item->assigned() || describe) |
1291 | { |
1292 | if (item) |
1293 | item->reset_value_registration(); |
1294 | if (optimized && item) |
1295 | { |
1296 | if (item->assigned()) |
1297 | { |
1298 | item->assigned(0); // We will reinit & rexecute unit |
1299 | item->reset(); |
1300 | } |
1301 | if (table->is_created()) |
1302 | { |
1303 | table->file->ha_delete_all_rows(); |
1304 | table->file->info(HA_STATUS_VARIABLE); |
1305 | } |
1306 | /* re-enabling indexes for next subselect iteration */ |
1307 | if (union_distinct && table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL)) |
1308 | { |
1309 | DBUG_ASSERT(0); |
1310 | } |
1311 | } |
1312 | for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) |
1313 | { |
1314 | if (sl->tvc) |
1315 | { |
1316 | sl->tvc->select_options= |
1317 | (select_limit_cnt == HA_POS_ERROR || sl->braces) ? |
1318 | sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union; |
1319 | if (sl->tvc->optimize(thd)) |
1320 | { |
1321 | thd->lex->current_select= lex_select_save; |
1322 | DBUG_RETURN(TRUE); |
1323 | } |
1324 | continue; |
1325 | } |
1326 | thd->lex->current_select= sl; |
1327 | |
1328 | if (optimized) |
1329 | saved_error= sl->join->reinit(); |
1330 | else |
1331 | { |
1332 | set_limit(sl); |
1333 | if (sl == global_parameters() || describe) |
1334 | { |
1335 | offset_limit_cnt= 0; |
1336 | /* |
1337 | We can't use LIMIT at this stage if we are using ORDER BY for the |
1338 | whole query |
1339 | */ |
1340 | if (sl->order_list.first || describe) |
1341 | select_limit_cnt= HA_POS_ERROR; |
1342 | } |
1343 | |
1344 | /* |
1345 | When using braces, SQL_CALC_FOUND_ROWS affects the whole query: |
1346 | we don't calculate found_rows() per union part. |
1347 | Otherwise, SQL_CALC_FOUND_ROWS should be done on all sub parts. |
1348 | */ |
1349 | sl->join->select_options= |
1350 | (select_limit_cnt == HA_POS_ERROR || sl->braces) ? |
1351 | sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union; |
1352 | |
1353 | saved_error= sl->join->optimize(); |
1354 | } |
1355 | |
1356 | if (unlikely(saved_error)) |
1357 | { |
1358 | thd->lex->current_select= lex_select_save; |
1359 | DBUG_RETURN(saved_error); |
1360 | } |
1361 | } |
1362 | } |
1363 | optimized= 1; |
1364 | |
1365 | thd->lex->current_select= lex_select_save; |
1366 | DBUG_RETURN(saved_error); |
1367 | } |
1368 | |
1369 | |
1370 | bool st_select_lex_unit::exec() |
1371 | { |
1372 | SELECT_LEX *lex_select_save= thd->lex->current_select; |
1373 | SELECT_LEX *select_cursor=first_select(); |
1374 | ulonglong add_rows=0; |
1375 | ha_rows examined_rows= 0; |
1376 | bool first_execution= !executed; |
1377 | DBUG_ENTER("st_select_lex_unit::exec" ); |
1378 | bool was_executed= executed; |
1379 | |
1380 | if (executed && !uncacheable && !describe) |
1381 | DBUG_RETURN(FALSE); |
1382 | executed= 1; |
1383 | if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item && |
1384 | !item->with_recursive_reference) |
1385 | item->make_const(); |
1386 | |
1387 | saved_error= optimize(); |
1388 | |
1389 | create_explain_query_if_not_exists(thd->lex, thd->mem_root); |
1390 | |
1391 | if (!saved_error && !was_executed) |
1392 | save_union_explain(thd->lex->explain); |
1393 | |
1394 | if (unlikely(saved_error)) |
1395 | DBUG_RETURN(saved_error); |
1396 | |
1397 | if (union_result) |
1398 | { |
1399 | union_result->init(); |
1400 | if (uncacheable & UNCACHEABLE_DEPENDENT && |
1401 | union_result->table && union_result->table->is_created()) |
1402 | { |
1403 | union_result->table->file->ha_delete_all_rows(); |
1404 | union_result->table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL); |
1405 | } |
1406 | } |
1407 | |
1408 | if (uncacheable || !item || !item->assigned() || describe) |
1409 | { |
1410 | if (!fake_select_lex && !(with_element && with_element->is_recursive)) |
1411 | union_result->cleanup(); |
1412 | for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) |
1413 | { |
1414 | ha_rows records_at_start= 0; |
1415 | thd->lex->current_select= sl; |
1416 | if (union_result) |
1417 | union_result->change_select(); |
1418 | if (fake_select_lex) |
1419 | { |
1420 | if (sl != &thd->lex->select_lex) |
1421 | fake_select_lex->uncacheable|= sl->uncacheable; |
1422 | else |
1423 | fake_select_lex->uncacheable= 0; |
1424 | } |
1425 | |
1426 | { |
1427 | set_limit(sl); |
1428 | if (sl == global_parameters() || describe) |
1429 | { |
1430 | offset_limit_cnt= 0; |
1431 | /* |
1432 | We can't use LIMIT at this stage if we are using ORDER BY for the |
1433 | whole query |
1434 | */ |
1435 | if (sl->order_list.first || describe) |
1436 | select_limit_cnt= HA_POS_ERROR; |
1437 | } |
1438 | |
1439 | /* |
1440 | When using braces, SQL_CALC_FOUND_ROWS affects the whole query: |
1441 | we don't calculate found_rows() per union part. |
1442 | Otherwise, SQL_CALC_FOUND_ROWS should be done on all sub parts. |
1443 | */ |
1444 | if (sl->tvc) |
1445 | { |
1446 | sl->tvc->select_options= |
1447 | (select_limit_cnt == HA_POS_ERROR || sl->braces) ? |
1448 | sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union; |
1449 | saved_error= sl->tvc->optimize(thd); |
1450 | } |
1451 | else |
1452 | { |
1453 | sl->join->select_options= |
1454 | (select_limit_cnt == HA_POS_ERROR || sl->braces) ? |
1455 | sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union; |
1456 | saved_error= sl->join->optimize(); |
1457 | } |
1458 | } |
1459 | if (likely(!saved_error)) |
1460 | { |
1461 | records_at_start= table->file->stats.records; |
1462 | if (sl->tvc) |
1463 | sl->tvc->exec(sl); |
1464 | else |
1465 | sl->join->exec(); |
1466 | if (sl == union_distinct && !(with_element && with_element->is_recursive)) |
1467 | { |
1468 | // This is UNION DISTINCT, so there should be a fake_select_lex |
1469 | DBUG_ASSERT(fake_select_lex != NULL); |
1470 | if (unlikely(table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))) |
1471 | DBUG_RETURN(TRUE); |
1472 | table->no_keyread=1; |
1473 | } |
1474 | if (!sl->tvc) |
1475 | saved_error= sl->join->error; |
1476 | offset_limit_cnt= (ha_rows)(sl->offset_limit ? |
1477 | sl->offset_limit->val_uint() : |
1478 | 0); |
1479 | if (likely(!saved_error)) |
1480 | { |
1481 | examined_rows+= thd->get_examined_row_count(); |
1482 | thd->set_examined_row_count(0); |
1483 | if (union_result->flush()) |
1484 | { |
1485 | thd->lex->current_select= lex_select_save; |
1486 | DBUG_RETURN(1); |
1487 | } |
1488 | } |
1489 | } |
1490 | if (unlikely(saved_error)) |
1491 | { |
1492 | thd->lex->current_select= lex_select_save; |
1493 | DBUG_RETURN(saved_error); |
1494 | } |
1495 | if (fake_select_lex != NULL) |
1496 | { |
1497 | /* Needed for the following test and for records_at_start in next loop */ |
1498 | int error= table->file->info(HA_STATUS_VARIABLE); |
1499 | if (unlikely(error)) |
1500 | { |
1501 | table->file->print_error(error, MYF(0)); |
1502 | DBUG_RETURN(1); |
1503 | } |
1504 | } |
1505 | if (found_rows_for_union && !sl->braces && |
1506 | select_limit_cnt != HA_POS_ERROR) |
1507 | { |
1508 | /* |
1509 | This is a union without braces. Remember the number of rows that |
1510 | could also have been part of the result set. |
1511 | We get this from the difference of between total number of possible |
1512 | rows and actual rows added to the temporary table. |
1513 | */ |
1514 | add_rows+= (ulonglong) (thd->limit_found_rows - (ulonglong) |
1515 | ((table->file->stats.records - records_at_start))); |
1516 | } |
1517 | if (thd->killed == ABORT_QUERY) |
1518 | { |
1519 | /* |
1520 | Stop execution of the remaining queries in the UNIONS, and produce |
1521 | the current result. |
1522 | */ |
1523 | push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, |
1524 | ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT, |
1525 | ER_THD(thd, ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT), |
1526 | thd->accessed_rows_and_keys, |
1527 | thd->lex->limit_rows_examined->val_uint()); |
1528 | thd->reset_killed(); |
1529 | break; |
1530 | } |
1531 | } |
1532 | } |
1533 | |
1534 | DBUG_EXECUTE_IF("show_explain_probe_union_read" , |
1535 | dbug_serve_apcs(thd, 1);); |
1536 | { |
1537 | List<Item_func_match> empty_list; |
1538 | empty_list.empty(); |
1539 | /* |
1540 | Disable LIMIT ROWS EXAMINED in order to produce the possibly incomplete |
1541 | result of the UNION without interruption due to exceeding the limit. |
1542 | */ |
1543 | thd->lex->limit_rows_examined_cnt= ULONGLONG_MAX; |
1544 | |
1545 | // Check if EOM |
1546 | if (fake_select_lex != NULL && likely(!thd->is_fatal_error)) |
1547 | { |
1548 | /* Send result to 'result' */ |
1549 | saved_error= true; |
1550 | |
1551 | set_limit(global_parameters()); |
1552 | init_prepare_fake_select_lex(thd, first_execution); |
1553 | JOIN *join= fake_select_lex->join; |
1554 | saved_error= false; |
1555 | if (!join) |
1556 | { |
1557 | /* |
1558 | allocate JOIN for fake select only once (prevent |
1559 | mysql_select automatic allocation) |
1560 | TODO: The above is nonsense. mysql_select() will not allocate the |
1561 | join if one already exists. There must be some other reason why we |
1562 | don't let it allocate the join. Perhaps this is because we need |
1563 | some special parameter values passed to join constructor? |
1564 | */ |
1565 | if (unlikely(!(fake_select_lex->join= |
1566 | new JOIN(thd, item_list, fake_select_lex->options, |
1567 | result)))) |
1568 | { |
1569 | fake_select_lex->table_list.empty(); |
1570 | goto err; |
1571 | } |
1572 | fake_select_lex->join->no_const_tables= TRUE; |
1573 | |
1574 | /* |
1575 | Fake st_select_lex should have item list for correct ref_array |
1576 | allocation. |
1577 | */ |
1578 | fake_select_lex->item_list= item_list; |
1579 | |
1580 | /* |
1581 | We need to add up n_sum_items in order to make the correct |
1582 | allocation in setup_ref_array(). |
1583 | Don't add more sum_items if we have already done JOIN::prepare |
1584 | for this (with a different join object) |
1585 | */ |
1586 | if (fake_select_lex->ref_pointer_array.is_null()) |
1587 | fake_select_lex->n_child_sum_items+= global_parameters()->n_sum_items; |
1588 | |
1589 | if (!was_executed) |
1590 | save_union_explain_part2(thd->lex->explain); |
1591 | |
1592 | saved_error= mysql_select(thd, |
1593 | &result_table_list, |
1594 | 0, item_list, NULL, |
1595 | global_parameters()->order_list.elements, |
1596 | global_parameters()->order_list.first, |
1597 | NULL, NULL, NULL, |
1598 | fake_select_lex->options | SELECT_NO_UNLOCK, |
1599 | result, this, fake_select_lex); |
1600 | } |
1601 | else |
1602 | { |
1603 | if (describe) |
1604 | { |
1605 | /* |
1606 | In EXPLAIN command, constant subqueries that do not use any |
1607 | tables are executed two times: |
1608 | - 1st time is a real evaluation to get the subquery value |
1609 | - 2nd time is to produce EXPLAIN output rows. |
1610 | 1st execution sets certain members (e.g. select_result) to perform |
1611 | subquery execution rather than EXPLAIN line production. In order |
1612 | to reset them back, we re-do all of the actions (yes it is ugly): |
1613 | */ // psergey-todo: is the above really necessary anymore?? |
1614 | join->init(thd, item_list, fake_select_lex->options, result); |
1615 | saved_error= mysql_select(thd, |
1616 | &result_table_list, |
1617 | 0, item_list, NULL, |
1618 | global_parameters()->order_list.elements, |
1619 | global_parameters()->order_list.first, |
1620 | NULL, NULL, NULL, |
1621 | fake_select_lex->options | SELECT_NO_UNLOCK, |
1622 | result, this, fake_select_lex); |
1623 | } |
1624 | else |
1625 | { |
1626 | join->join_examined_rows= 0; |
1627 | saved_error= join->reinit(); |
1628 | join->exec(); |
1629 | } |
1630 | } |
1631 | |
1632 | fake_select_lex->table_list.empty(); |
1633 | if (likely(!saved_error)) |
1634 | { |
1635 | thd->limit_found_rows = (ulonglong)table->file->stats.records + add_rows; |
1636 | thd->inc_examined_row_count(examined_rows); |
1637 | } |
1638 | /* |
1639 | Mark for slow query log if any of the union parts didn't use |
1640 | indexes efficiently |
1641 | */ |
1642 | } |
1643 | } |
1644 | thd->lex->current_select= lex_select_save; |
1645 | err: |
1646 | thd->lex->set_limit_rows_examined(); |
1647 | DBUG_RETURN(saved_error); |
1648 | } |
1649 | |
1650 | |
1651 | /** |
1652 | @brief |
1653 | Execute the union of the specification of a recursive with table |
1654 | |
1655 | @details |
1656 | The method is performed only for the units that are specifications |
1657 | if recursive with table T. If the specification contains an anchor |
1658 | part then the first call of this method executes only this part |
1659 | while the following calls execute the recursive part. If there are |
1660 | no anchors each call executes the whole unit. |
1661 | Before the excution the method cleans up the temporary table |
1662 | to where the new rows of the recursive table are sent. |
1663 | After the execution the unit these rows are copied to the |
1664 | temporary tables created for recursive references of T. |
1665 | If the specification if T is restricted (standards compliant) |
1666 | then these temporary tables are cleaned up before new rows |
1667 | are copied into them. |
1668 | |
1669 | @retval |
1670 | false on success |
1671 | true on failure |
1672 | */ |
1673 | |
1674 | bool st_select_lex_unit::exec_recursive() |
1675 | { |
1676 | st_select_lex *lex_select_save= thd->lex->current_select; |
1677 | st_select_lex *start= with_element->first_recursive; |
1678 | TABLE *incr_table= with_element->rec_result->incr_table; |
1679 | st_select_lex *end= NULL; |
1680 | bool is_unrestricted= with_element->is_unrestricted(); |
1681 | List_iterator_fast<TABLE> li(with_element->rec_result->rec_tables); |
1682 | TMP_TABLE_PARAM *tmp_table_param= &with_element->rec_result->tmp_table_param; |
1683 | ha_rows examined_rows= 0; |
1684 | bool was_executed= executed; |
1685 | TABLE *rec_table; |
1686 | |
1687 | DBUG_ENTER("st_select_lex_unit::exec_recursive" ); |
1688 | |
1689 | executed= 1; |
1690 | create_explain_query_if_not_exists(thd->lex, thd->mem_root); |
1691 | if (!was_executed) |
1692 | save_union_explain(thd->lex->explain); |
1693 | |
1694 | if (with_element->level == 0) |
1695 | { |
1696 | if (!incr_table->is_created() && |
1697 | instantiate_tmp_table(incr_table, |
1698 | tmp_table_param->keyinfo, |
1699 | tmp_table_param->start_recinfo, |
1700 | &tmp_table_param->recinfo, |
1701 | 0)) |
1702 | DBUG_RETURN(1); |
1703 | incr_table->file->extra(HA_EXTRA_WRITE_CACHE); |
1704 | incr_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); |
1705 | start= first_select(); |
1706 | if (with_element->with_anchor) |
1707 | end= with_element->first_recursive; |
1708 | } |
1709 | else if (unlikely((saved_error= incr_table->file->ha_delete_all_rows()))) |
1710 | goto err; |
1711 | |
1712 | for (st_select_lex *sl= start ; sl != end; sl= sl->next_select()) |
1713 | { |
1714 | if (with_element->level) |
1715 | { |
1716 | for (TABLE_LIST *derived= with_element->derived_with_rec_ref.first; |
1717 | derived; |
1718 | derived= derived->next_with_rec_ref) |
1719 | { |
1720 | if (derived->is_materialized_derived()) |
1721 | { |
1722 | if (derived->table->is_created()) |
1723 | derived->table->file->ha_delete_all_rows(); |
1724 | derived->table->reginfo.join_tab->preread_init_done= false; |
1725 | } |
1726 | } |
1727 | } |
1728 | thd->lex->current_select= sl; |
1729 | if (sl->tvc) |
1730 | sl->tvc->exec(sl); |
1731 | else |
1732 | { |
1733 | sl->join->exec(); |
1734 | saved_error= sl->join->error; |
1735 | } |
1736 | if (likely(!saved_error)) |
1737 | { |
1738 | examined_rows+= thd->get_examined_row_count(); |
1739 | thd->set_examined_row_count(0); |
1740 | if (unlikely(union_result->flush())) |
1741 | { |
1742 | thd->lex->current_select= lex_select_save; |
1743 | DBUG_RETURN(1); |
1744 | } |
1745 | } |
1746 | if (unlikely(saved_error)) |
1747 | { |
1748 | thd->lex->current_select= lex_select_save; |
1749 | goto err; |
1750 | |
1751 | } |
1752 | } |
1753 | |
1754 | thd->inc_examined_row_count(examined_rows); |
1755 | |
1756 | incr_table->file->info(HA_STATUS_VARIABLE); |
1757 | if (with_element->level && incr_table->file->stats.records == 0) |
1758 | with_element->set_as_stabilized(); |
1759 | else |
1760 | with_element->level++; |
1761 | |
1762 | while ((rec_table= li++)) |
1763 | { |
1764 | saved_error= |
1765 | incr_table->insert_all_rows_into_tmp_table(thd, rec_table, |
1766 | tmp_table_param, |
1767 | !is_unrestricted); |
1768 | if (!with_element->rec_result->first_rec_table_to_update) |
1769 | with_element->rec_result->first_rec_table_to_update= rec_table; |
1770 | if (with_element->level == 1 && rec_table->reginfo.join_tab) |
1771 | rec_table->reginfo.join_tab->preread_init_done= true; |
1772 | } |
1773 | for (Item_subselect *sq= with_element->sq_with_rec_ref.first; |
1774 | sq; |
1775 | sq= sq->next_with_rec_ref) |
1776 | { |
1777 | sq->reset(); |
1778 | sq->engine->force_reexecution(); |
1779 | } |
1780 | |
1781 | thd->lex->current_select= lex_select_save; |
1782 | err: |
1783 | thd->lex->set_limit_rows_examined(); |
1784 | DBUG_RETURN(saved_error); |
1785 | } |
1786 | |
1787 | |
1788 | bool st_select_lex_unit::cleanup() |
1789 | { |
1790 | bool error= 0; |
1791 | DBUG_ENTER("st_select_lex_unit::cleanup" ); |
1792 | |
1793 | if (cleaned) |
1794 | { |
1795 | DBUG_RETURN(FALSE); |
1796 | } |
1797 | cleaned= 1; |
1798 | |
1799 | for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) |
1800 | error|= sl->cleanup(); |
1801 | |
1802 | if (fake_select_lex) |
1803 | { |
1804 | error|= fake_select_lex->cleanup(); |
1805 | /* |
1806 | There are two cases when we should clean order items: |
1807 | 1. UNION with SELECTs which all enclosed into braces |
1808 | in this case global_parameters == fake_select_lex |
1809 | 2. UNION where last SELECT is not enclosed into braces |
1810 | in this case global_parameters == 'last select' |
1811 | So we should use global_parameters->order_list for |
1812 | proper order list clean up. |
1813 | Note: global_parameters and fake_select_lex are always |
1814 | initialized for UNION |
1815 | */ |
1816 | DBUG_ASSERT(global_parameters()); |
1817 | if (global_parameters()->order_list.elements) |
1818 | { |
1819 | ORDER *ord; |
1820 | for (ord= global_parameters()->order_list.first; ord; ord= ord->next) |
1821 | (*ord->item)->walk (&Item::cleanup_processor, 0, 0); |
1822 | } |
1823 | } |
1824 | |
1825 | if (with_element && with_element->is_recursive) |
1826 | { |
1827 | if (union_result ) |
1828 | { |
1829 | ((select_union_recursive *) union_result)->cleanup(); |
1830 | delete union_result; |
1831 | union_result= 0; |
1832 | } |
1833 | with_element->mark_as_cleaned(); |
1834 | } |
1835 | else |
1836 | { |
1837 | if (union_result) |
1838 | { |
1839 | delete union_result; |
1840 | union_result=0; // Safety |
1841 | if (table) |
1842 | free_tmp_table(thd, table); |
1843 | table= 0; // Safety |
1844 | } |
1845 | } |
1846 | |
1847 | DBUG_RETURN(error); |
1848 | } |
1849 | |
1850 | |
1851 | void st_select_lex_unit::reinit_exec_mechanism() |
1852 | { |
1853 | prepared= optimized= optimized_2= executed= 0; |
1854 | optimize_started= 0; |
1855 | if (with_element && with_element->is_recursive) |
1856 | with_element->reset_recursive_for_exec(); |
1857 | } |
1858 | |
1859 | |
1860 | /** |
1861 | Change the select_result object used to return the final result of |
1862 | the unit, replacing occurences of old_result with new_result. |
1863 | |
1864 | @param new_result New select_result object |
1865 | @param old_result Old select_result object |
1866 | |
1867 | @retval false Success |
1868 | @retval true Error |
1869 | */ |
1870 | |
1871 | bool st_select_lex_unit::change_result(select_result_interceptor *new_result, |
1872 | select_result_interceptor *old_result) |
1873 | { |
1874 | for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) |
1875 | { |
1876 | if (sl->join) |
1877 | if (sl->join->change_result(new_result, old_result)) |
1878 | return true; /* purecov: inspected */ |
1879 | } |
1880 | /* |
1881 | If there were a fake_select_lex->join, we would have to change the |
1882 | result of that also, but change_result() is called before such an |
1883 | object is created. |
1884 | */ |
1885 | DBUG_ASSERT(fake_select_lex == NULL || fake_select_lex->join == NULL); |
1886 | return false; |
1887 | } |
1888 | |
1889 | /* |
1890 | Get column type information for this unit. |
1891 | |
1892 | SYNOPSIS |
1893 | st_select_lex_unit::get_column_types() |
1894 | @param for_cursor if true return the list the fields |
1895 | retrieved by the cursor |
1896 | |
1897 | DESCRIPTION |
1898 | For a single-select the column types are taken |
1899 | from the list of selected items. For a union this function |
1900 | assumes that st_select_lex_unit::prepare has been called |
1901 | and returns the type holders that were created for unioned |
1902 | column types of all selects. |
1903 | |
1904 | NOTES |
1905 | The implementation of this function should be in sync with |
1906 | st_select_lex_unit::prepare() |
1907 | */ |
1908 | |
1909 | List<Item> *st_select_lex_unit::get_column_types(bool for_cursor) |
1910 | { |
1911 | SELECT_LEX *sl= first_select(); |
1912 | bool is_procedure= !sl->tvc && sl->join->procedure ; |
1913 | |
1914 | if (is_procedure) |
1915 | { |
1916 | /* Types for "SELECT * FROM t1 procedure analyse()" |
1917 | are generated during execute */ |
1918 | return &sl->join->procedure_fields_list; |
1919 | } |
1920 | |
1921 | |
1922 | if (is_unit_op()) |
1923 | { |
1924 | DBUG_ASSERT(prepared); |
1925 | /* Types are generated during prepare */ |
1926 | return &types; |
1927 | } |
1928 | |
1929 | return for_cursor ? sl->join->fields : &sl->item_list; |
1930 | } |
1931 | |
1932 | |
1933 | static void cleanup_order(ORDER *order) |
1934 | { |
1935 | for (; order; order= order->next) |
1936 | order->counter_used= 0; |
1937 | } |
1938 | |
1939 | |
1940 | bool st_select_lex::cleanup() |
1941 | { |
1942 | bool error= FALSE; |
1943 | DBUG_ENTER("st_select_lex::cleanup()" ); |
1944 | |
1945 | cleanup_order(order_list.first); |
1946 | cleanup_order(group_list.first); |
1947 | cleanup_ftfuncs(this); |
1948 | |
1949 | if (join) |
1950 | { |
1951 | DBUG_ASSERT((st_select_lex*)join->select_lex == this); |
1952 | error= join->destroy(); |
1953 | delete join; |
1954 | join= 0; |
1955 | } |
1956 | for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ; |
1957 | lex_unit= lex_unit->next_unit()) |
1958 | { |
1959 | error= (bool) ((uint) error | (uint) lex_unit->cleanup()); |
1960 | } |
1961 | inner_refs_list.empty(); |
1962 | exclude_from_table_unique_test= FALSE; |
1963 | hidden_bit_fields= 0; |
1964 | DBUG_RETURN(error); |
1965 | } |
1966 | |
1967 | |
1968 | void st_select_lex::cleanup_all_joins(bool full) |
1969 | { |
1970 | SELECT_LEX_UNIT *unit; |
1971 | SELECT_LEX *sl; |
1972 | DBUG_ENTER("st_select_lex::cleanup_all_joins" ); |
1973 | |
1974 | if (join) |
1975 | join->cleanup(full); |
1976 | |
1977 | for (unit= first_inner_unit(); unit; unit= unit->next_unit()) |
1978 | for (sl= unit->first_select(); sl; sl= sl->next_select()) |
1979 | sl->cleanup_all_joins(full); |
1980 | DBUG_VOID_RETURN; |
1981 | } |
1982 | |
1983 | |
1984 | /** |
1985 | Set exclude_from_table_unique_test for selects of this unit and all |
1986 | underlying selects. |
1987 | |
1988 | @note used to exclude materialized derived tables (views) from unique |
1989 | table check. |
1990 | */ |
1991 | |
1992 | void st_select_lex_unit::set_unique_exclude() |
1993 | { |
1994 | for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) |
1995 | { |
1996 | sl->exclude_from_table_unique_test= TRUE; |
1997 | for (SELECT_LEX_UNIT *unit= sl->first_inner_unit(); |
1998 | unit; |
1999 | unit= unit->next_unit()) |
2000 | { |
2001 | unit->set_unique_exclude(); |
2002 | } |
2003 | } |
2004 | } |
2005 | |