1/* Copyright (c) 2017, MariaDB
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "mariadb.h"
17#include "sql_list.h"
18#include "sql_tvc.h"
19#include "sql_class.h"
20#include "opt_range.h"
21#include "sql_select.h"
22#include "sql_explain.h"
23#include "sql_parse.h"
24#include "sql_cte.h"
25
26/**
27 @brief
28 Fix fields for TVC values
29
30 @param
31 @param thd The context of the statement
32 @param li The iterator on the list of lists
33
34 @details
35 Call fix_fields procedure for TVC values.
36
37 @retval
38 true if an error was reported
39 false otherwise
40*/
41
42bool fix_fields_for_tvc(THD *thd, List_iterator_fast<List_item> &li)
43{
44 DBUG_ENTER("fix_fields_for_tvc");
45 List_item *lst;
46 li.rewind();
47
48 while ((lst= li++))
49 {
50 List_iterator_fast<Item> it(*lst);
51 Item *item;
52
53 while ((item= it++))
54 {
55 if (item->fix_fields(thd, 0))
56 DBUG_RETURN(true);
57 }
58 }
59 DBUG_RETURN(false);
60}
61
62
63/**
64 @brief
65 Defines types of matrix columns elements where matrix rows are defined by
66 some lists of values.
67
68 @param
69 @param thd The context of the statement
70 @param li The iterator on the list of lists
71 @param holders The structure where types of matrix columns are stored
72 @param first_list_el_count Count of the list values. It should be the same
73 for each list of lists elements. It contains
74 number of elements of the first list from list of
75 lists.
76
77 @details
78 For each list list_a from list of lists the procedure gets its elements
79 types and aggregates them with the previous ones stored in holders. If
80 list_a is the first one in the list of lists its elements types are put in
81 holders. The errors can be reported when count of list_a elements is
82 different from the first_list_el_count. Also error can be reported whe
83 n aggregation can't be made.
84
85 @retval
86 true if an error was reported
87 false otherwise
88*/
89
90bool join_type_handlers_for_tvc(THD *thd, List_iterator_fast<List_item> &li,
91 Type_holder *holders, uint first_list_el_count)
92{
93 DBUG_ENTER("join_type_handlers_for_tvc");
94 List_item *lst;
95 li.rewind();
96 bool first= true;
97
98 while ((lst= li++))
99 {
100 List_iterator_fast<Item> it(*lst);
101 Item *item;
102
103 if (first_list_el_count != lst->elements)
104 {
105 my_message(ER_WRONG_NUMBER_OF_VALUES_IN_TVC,
106 ER_THD(thd, ER_WRONG_NUMBER_OF_VALUES_IN_TVC),
107 MYF(0));
108 DBUG_RETURN(true);
109 }
110 for (uint pos= 0; (item=it++); pos++)
111 {
112 const Type_handler *item_type_handler= item->real_type_handler();
113 if (first)
114 holders[pos].set_handler(item_type_handler);
115 else if (holders[pos].aggregate_for_result(item_type_handler))
116 {
117 my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
118 holders[pos].type_handler()->name().ptr(),
119 item_type_handler->name().ptr(),
120 "TABLE VALUE CONSTRUCTOR");
121 DBUG_RETURN(true);
122 }
123 }
124 first= false;
125 }
126 DBUG_RETURN(false);
127}
128
129
130/**
131 @brief
132 Define attributes of matrix columns elements where matrix rows are defined
133 by some lists of values.
134
135 @param
136 @param thd The context of the statement
137 @param li The iterator on the list of lists
138 @param holders The structure where names of matrix columns are stored
139 @param count_of_lists Count of list of lists elements
140 @param first_list_el_count Count of the list values. It should be the same
141 for each list of lists elements. It contains
142 number of elements of the first list from list
143 of lists.
144
145 @details
146 For each list list_a from list of lists the procedure gets its elements
147 attributes and aggregates them with the previous ones stored in holders.
148 The errors can be reported when aggregation can't be made.
149
150 @retval
151 true if an error was reported
152 false otherwise
153*/
154
155bool get_type_attributes_for_tvc(THD *thd,
156 List_iterator_fast<List_item> &li,
157 Type_holder *holders, uint count_of_lists,
158 uint first_list_el_count)
159{
160 DBUG_ENTER("get_type_attributes_for_tvc");
161 List_item *lst;
162 li.rewind();
163
164 for (uint pos= 0; pos < first_list_el_count; pos++)
165 {
166 if (holders[pos].alloc_arguments(thd, count_of_lists))
167 DBUG_RETURN(true);
168 }
169
170 while ((lst= li++))
171 {
172 List_iterator_fast<Item> it(*lst);
173 Item *item;
174 for (uint holder_pos= 0 ; (item= it++); holder_pos++)
175 {
176 DBUG_ASSERT(item->fixed);
177 holders[holder_pos].add_argument(item);
178 }
179 }
180
181 for (uint pos= 0; pos < first_list_el_count; pos++)
182 {
183 if (holders[pos].aggregate_attributes(thd))
184 DBUG_RETURN(true);
185 }
186 DBUG_RETURN(false);
187}
188
189
190/**
191 @brief
192 Prepare of TVC
193
194 @param
195 @param thd The context of the statement
196 @param sl The select where this TVC is defined
197 @param tmp_result Structure that contains the information
198 about where to send the result of the query
199 @param unit_arg The union where sl is defined
200
201 @details
202 Gets types and attributes of values of this TVC that will be used
203 for temporary table creation for this TVC. It creates Item_type_holders
204 for each element of the first list from list of lists (VALUES from tvc),
205 using its elements name, defined type and attribute.
206
207 @retval
208 true if an error was reported
209 false otherwise
210*/
211
212bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl,
213 select_result *tmp_result,
214 st_select_lex_unit *unit_arg)
215{
216 DBUG_ENTER("table_value_constr::prepare");
217 select_lex->in_tvc= true;
218 List_iterator_fast<List_item> li(lists_of_values);
219
220 List_item *first_elem= li++;
221 uint cnt= first_elem->elements;
222 Type_holder *holders;
223
224 if (cnt == 0)
225 {
226 my_error(ER_EMPTY_ROW_IN_TVC, MYF(0));
227 DBUG_RETURN(true);
228 }
229
230 if (fix_fields_for_tvc(thd, li))
231 DBUG_RETURN(true);
232
233 if (!(holders= new (thd->mem_root)
234 Type_holder[cnt]) ||
235 join_type_handlers_for_tvc(thd, li, holders,
236 cnt) ||
237 get_type_attributes_for_tvc(thd, li, holders,
238 lists_of_values.elements, cnt))
239 DBUG_RETURN(true);
240
241 List_iterator_fast<Item> it(*first_elem);
242 Item *item;
243
244 sl->item_list.empty();
245 for (uint pos= 0; (item= it++); pos++)
246 {
247 /* Error's in 'new' will be detected after loop */
248 Item_type_holder *new_holder= new (thd->mem_root)
249 Item_type_holder(thd,
250 item,
251 holders[pos].type_handler(),
252 &holders[pos]/*Type_all_attributes*/,
253 holders[pos].get_maybe_null());
254 new_holder->fix_fields(thd, 0);
255 sl->item_list.push_back(new_holder);
256 }
257
258 if (unlikely(thd->is_fatal_error))
259 DBUG_RETURN(true); // out of memory
260
261 result= tmp_result;
262
263 if (result && result->prepare(sl->item_list, unit_arg))
264 DBUG_RETURN(true);
265
266 select_lex->in_tvc= false;
267 DBUG_RETURN(false);
268}
269
270
271/**
272 Save Query Plan Footprint
273*/
274
275int table_value_constr::save_explain_data_intern(THD *thd,
276 Explain_query *output)
277{
278 const char *message= "No tables used";
279 DBUG_ENTER("table_value_constr::save_explain_data_intern");
280 DBUG_PRINT("info", ("Select %p, type %s, message %s",
281 select_lex, select_lex->type,
282 message));
283 DBUG_ASSERT(have_query_plan == QEP_AVAILABLE);
284
285 /* There should be no attempts to save query plans for merged selects */
286 DBUG_ASSERT(!select_lex->master_unit()->derived ||
287 select_lex->master_unit()->derived->is_materialized_derived() ||
288 select_lex->master_unit()->derived->is_with_table());
289
290 explain= new (output->mem_root) Explain_select(output->mem_root,
291 thd->lex->analyze_stmt);
292 if (!explain)
293 DBUG_RETURN(1);
294
295 select_lex->set_explain_type(true);
296
297 explain->select_id= select_lex->select_number;
298 explain->select_type= select_lex->type;
299 explain->linkage= select_lex->linkage;
300 explain->using_temporary= false;
301 explain->using_filesort= false;
302 /* Setting explain->message means that all other members are invalid */
303 explain->message= message;
304
305 if (select_lex->master_unit()->derived)
306 explain->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
307
308 output->add_node(explain);
309
310 if (select_lex->is_top_level_node())
311 output->query_plan_ready();
312
313 DBUG_RETURN(0);
314}
315
316
317/**
318 Optimization of TVC
319*/
320
321bool table_value_constr::optimize(THD *thd)
322{
323 create_explain_query_if_not_exists(thd->lex, thd->mem_root);
324 have_query_plan= QEP_AVAILABLE;
325
326 if (select_lex->select_number != UINT_MAX &&
327 select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
328 have_query_plan != QEP_NOT_PRESENT_YET &&
329 thd->lex->explain && // for "SET" command in SPs.
330 (!thd->lex->explain->get_select(select_lex->select_number)))
331 {
332 return save_explain_data_intern(thd, thd->lex->explain);
333 }
334 return 0;
335}
336
337
338/**
339 Execute of TVC
340*/
341
342bool table_value_constr::exec(SELECT_LEX *sl)
343{
344 DBUG_ENTER("table_value_constr::exec");
345 List_iterator_fast<List_item> li(lists_of_values);
346 List_item *elem;
347
348 if (select_options & SELECT_DESCRIBE)
349 DBUG_RETURN(false);
350
351 if (result->send_result_set_metadata(sl->item_list,
352 Protocol::SEND_NUM_ROWS |
353 Protocol::SEND_EOF))
354 {
355 DBUG_RETURN(true);
356 }
357
358 while ((elem= li++))
359 {
360 result->send_data(*elem);
361 }
362
363 if (result->send_eof())
364 DBUG_RETURN(true);
365
366 DBUG_RETURN(false);
367}
368
369
370/**
371 @brief
372 Print list
373
374 @param str The reference on the string representation of the list
375 @param list The list that needed to be print
376 @param query_type The mode of printing
377
378 @details
379 The method saves a string representation of list in the
380 string str.
381*/
382
383void print_list_item(String *str, List_item *list,
384 enum_query_type query_type)
385{
386 bool is_first_elem= true;
387 List_iterator_fast<Item> it(*list);
388 Item *item;
389
390 str->append('(');
391
392 while ((item= it++))
393 {
394 if (is_first_elem)
395 is_first_elem= false;
396 else
397 str->append(',');
398
399 item->print(str, query_type);
400 }
401
402 str->append(')');
403}
404
405
406/**
407 @brief
408 Print this TVC
409
410 @param thd The context of the statement
411 @param str The reference on the string representation of this TVC
412 @param query_type The mode of printing
413
414 @details
415 The method saves a string representation of this TVC in the
416 string str.
417*/
418
419void table_value_constr::print(THD *thd, String *str,
420 enum_query_type query_type)
421{
422 DBUG_ASSERT(thd);
423
424 str->append(STRING_WITH_LEN("values "));
425
426 bool is_first_elem= true;
427 List_iterator_fast<List_item> li(lists_of_values);
428 List_item *list;
429
430 while ((list= li++))
431 {
432 if (is_first_elem)
433 is_first_elem= false;
434 else
435 str->append(',');
436
437 print_list_item(str, list, query_type);
438 }
439}
440
441
442/**
443 @brief
444 Create list of lists for TVC from the list of this IN predicate
445
446 @param thd The context of the statement
447 @param values TVC list of values
448
449 @details
450 The method uses the list of values of this IN predicate to build
451 an equivalent list of values that can be used in TVC.
452
453 E.g.:
454
455 <value_list> = 5,2,7
456 <transformed_value_list> = (5),(2),(7)
457
458 <value_list> = (5,2),(7,1)
459 <transformed_value_list> = (5,2),(7,1)
460
461 @retval
462 false if the method succeeds
463 true otherwise
464*/
465
466bool Item_func_in::create_value_list_for_tvc(THD *thd,
467 List< List<Item> > *values)
468{
469 bool is_list_of_rows= args[1]->type() == Item::ROW_ITEM;
470
471 for (uint i=1; i < arg_count; i++)
472 {
473 List<Item> *tvc_value;
474 if (!(tvc_value= new (thd->mem_root) List<Item>()))
475 return true;
476
477 if (is_list_of_rows)
478 {
479 Item_row *row_list= (Item_row *)(args[i]);
480
481 for (uint j=0; j < row_list->cols(); j++)
482 {
483 if (tvc_value->push_back(row_list->element_index(j),
484 thd->mem_root))
485 return true;
486 }
487 }
488 else if (tvc_value->push_back(args[i]->real_item()))
489 return true;
490
491 if (values->push_back(tvc_value, thd->mem_root))
492 return true;
493 }
494 return false;
495}
496
497
498/**
499 @brief
500 Create name for the derived table defined by TVC
501
502 @param thd The context of the statement
503 @param parent_select The SELECT where derived table is used
504 @param alias The returned created name
505
506 @details
507 Create name for the derived table using current TVC number
508 for this parent_select stored in parent_select
509
510 @retval
511 true if creation fails
512 false otherwise
513*/
514
515static bool create_tvc_name(THD *thd, st_select_lex *parent_select,
516 LEX_CSTRING *alias)
517{
518 char buff[6];
519
520 alias->length= my_snprintf(buff, sizeof(buff),
521 "tvc_%u", parent_select->curr_tvc_name);
522 alias->str= thd->strmake(buff, alias->length);
523 if (!alias->str)
524 return true;
525
526 return false;
527}
528
529
530bool Item_subselect::wrap_tvc_in_derived_table(THD *thd,
531 st_select_lex *tvc_sl)
532{
533 LEX *lex= thd->lex;
534 /* SELECT_LEX object where the transformation is performed */
535 SELECT_LEX *parent_select= lex->current_select;
536 uint8 save_derived_tables= lex->derived_tables;
537
538 Query_arena backup;
539 Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup);
540
541 /*
542 Create SELECT_LEX of the subquery SQ used in the result of transformation
543 */
544 lex->current_select= tvc_sl;
545 if (mysql_new_select(lex, 0, NULL))
546 goto err;
547 mysql_init_select(lex);
548 /* Create item list as '*' for the subquery SQ */
549 Item *item;
550 SELECT_LEX *sq_select; // select for IN subquery;
551 sq_select= lex->current_select;
552 sq_select->linkage= tvc_sl->linkage;
553 sq_select->parsing_place= SELECT_LIST;
554 item= new (thd->mem_root) Item_field(thd, &sq_select->context,
555 NULL, NULL, &star_clex_str);
556 if (item == NULL || add_item_to_list(thd, item))
557 goto err;
558 (sq_select->with_wild)++;
559
560 /* Exclude SELECT with TVC */
561 tvc_sl->exclude();
562 /*
563 Create derived table DT that will wrap TVC in the result of transformation
564 */
565 SELECT_LEX *tvc_select; // select for tvc
566 SELECT_LEX_UNIT *derived_unit; // unit for tvc_select
567 if (mysql_new_select(lex, 1, tvc_sl))
568 goto err;
569 tvc_select= lex->current_select;
570 derived_unit= tvc_select->master_unit();
571 tvc_select->linkage= DERIVED_TABLE_TYPE;
572
573 lex->current_select= sq_select;
574
575 /*
576 Create the name of the wrapping derived table and
577 add it to the FROM list of the subquery SQ
578 */
579 Table_ident *ti;
580 LEX_CSTRING alias;
581 TABLE_LIST *derived_tab;
582 if (!(ti= new (thd->mem_root) Table_ident(derived_unit)) ||
583 create_tvc_name(thd, parent_select, &alias))
584 goto err;
585 if (!(derived_tab=
586 sq_select->add_table_to_list(thd,
587 ti, &alias, 0,
588 TL_READ, MDL_SHARED_READ)))
589 goto err;
590 sq_select->add_joined_table(derived_tab);
591 sq_select->add_where_field(derived_unit->first_select());
592 sq_select->context.table_list= sq_select->table_list.first;
593 sq_select->context.first_name_resolution_table= sq_select->table_list.first;
594 sq_select->table_list.first->derived_type= DTYPE_TABLE | DTYPE_MATERIALIZE;
595 lex->derived_tables|= DERIVED_SUBQUERY;
596
597 sq_select->where= 0;
598 sq_select->set_braces(false);
599 derived_unit->set_with_clause(0);
600
601 if (engine->engine_type() == subselect_engine::SINGLE_SELECT_ENGINE)
602 ((subselect_single_select_engine *) engine)->change_select(sq_select);
603
604 if (arena)
605 thd->restore_active_arena(arena, &backup);
606 lex->current_select= sq_select;
607 return false;
608
609err:
610 if (arena)
611 thd->restore_active_arena(arena, &backup);
612 lex->derived_tables= save_derived_tables;
613 lex->current_select= parent_select;
614 return true;
615}
616
617
618/**
619 @brief
620 Transform IN predicate into IN subquery
621
622 @param thd The context of the statement
623 @param arg Not used
624
625 @details
626 The method transforms this IN predicate into in equivalent IN subquery:
627
628 <left_expr> IN (<value_list>)
629 =>
630 <left_expr> IN (SELECT * FROM (VALUES <transformed_value_list>) AS tvc_#)
631
632 E.g.:
633
634 <value_list> = 5,2,7
635 <transformed_value_list> = (5),(2),(7)
636
637 <value_list> = (5,2),(7,1)
638 <transformed_value_list> = (5,2),(7,1)
639
640 If the transformation succeeds the method returns the result IN subquery,
641 otherwise this IN predicate is returned.
642
643 @retval
644 pointer to the result of transformation if succeeded
645 pointer to this IN predicate otherwise
646*/
647
648Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
649 uchar *arg)
650{
651 if (!transform_into_subq)
652 return this;
653
654 transform_into_subq= false;
655
656 List<List_item> values;
657
658 LEX *lex= thd->lex;
659 /* SELECT_LEX object where the transformation is performed */
660 SELECT_LEX *parent_select= lex->current_select;
661 uint8 save_derived_tables= lex->derived_tables;
662
663 for (uint i=1; i < arg_count; i++)
664 {
665 if (!args[i]->const_item())
666 return this;
667 }
668
669 Query_arena backup;
670 Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup);
671
672 /*
673 Create SELECT_LEX of the subquery SQ used in the result of transformation
674 */
675 if (mysql_new_select(lex, 1, NULL))
676 goto err;
677 mysql_init_select(lex);
678 /* Create item list as '*' for the subquery SQ */
679 Item *item;
680 SELECT_LEX *sq_select; // select for IN subquery;
681 sq_select= lex->current_select;
682 sq_select->parsing_place= SELECT_LIST;
683 item= new (thd->mem_root) Item_field(thd, &sq_select->context,
684 NULL, NULL, &star_clex_str);
685 if (item == NULL || add_item_to_list(thd, item))
686 goto err;
687 (sq_select->with_wild)++;
688 /*
689 Create derived table DT that will wrap TVC in the result of transformation
690 */
691 SELECT_LEX *tvc_select; // select for tvc
692 SELECT_LEX_UNIT *derived_unit; // unit for tvc_select
693 if (mysql_new_select(lex, 1, NULL))
694 goto err;
695 mysql_init_select(lex);
696 tvc_select= lex->current_select;
697 derived_unit= tvc_select->master_unit();
698 tvc_select->linkage= DERIVED_TABLE_TYPE;
699
700 /* Create TVC used in the transformation */
701 if (create_value_list_for_tvc(thd, &values))
702 goto err;
703 if (!(tvc_select->tvc=
704 new (thd->mem_root)
705 table_value_constr(values,
706 tvc_select,
707 tvc_select->options)))
708 goto err;
709
710 lex->current_select= sq_select;
711
712 /*
713 Create the name of the wrapping derived table and
714 add it to the FROM list of the subquery SQ
715 */
716 Table_ident *ti;
717 LEX_CSTRING alias;
718 TABLE_LIST *derived_tab;
719 if (!(ti= new (thd->mem_root) Table_ident(derived_unit)) ||
720 create_tvc_name(thd, parent_select, &alias))
721 goto err;
722 if (!(derived_tab=
723 sq_select->add_table_to_list(thd,
724 ti, &alias, 0,
725 TL_READ, MDL_SHARED_READ)))
726 goto err;
727 sq_select->add_joined_table(derived_tab);
728 sq_select->add_where_field(derived_unit->first_select());
729 sq_select->context.table_list= sq_select->table_list.first;
730 sq_select->context.first_name_resolution_table= sq_select->table_list.first;
731 sq_select->table_list.first->derived_type= DTYPE_TABLE | DTYPE_MATERIALIZE;
732 lex->derived_tables|= DERIVED_SUBQUERY;
733
734 sq_select->where= 0;
735 sq_select->set_braces(false);
736 derived_unit->set_with_clause(0);
737
738 /* Create IN subquery predicate */
739 sq_select->parsing_place= parent_select->parsing_place;
740 Item_in_subselect *in_subs;
741 Item *sq;
742 if (!(in_subs=
743 new (thd->mem_root) Item_in_subselect(thd, args[0], sq_select)))
744 goto err;
745 sq= in_subs;
746 if (negated)
747 sq= negate_expression(thd, in_subs);
748 else
749 in_subs->emb_on_expr_nest= emb_on_expr_nest;
750
751 if (arena)
752 thd->restore_active_arena(arena, &backup);
753 thd->lex->current_select= parent_select;
754
755 if (sq->fix_fields(thd, (Item **)&sq))
756 goto err;
757
758 parent_select->curr_tvc_name++;
759 return sq;
760
761err:
762 if (arena)
763 thd->restore_active_arena(arena, &backup);
764 lex->derived_tables= save_derived_tables;
765 thd->lex->current_select= parent_select;
766 return NULL;
767}
768
769
770/**
771 @brief
772 Check if this IN-predicate can be transformed in IN-subquery
773 with TVC
774
775 @param thd The context of the statement
776
777 @details
778 Compare the number of elements in the list of
779 values in this IN-predicate with the
780 in_subquery_conversion_threshold special variable
781
782 @retval
783 true if transformation can be made
784 false otherwise
785*/
786
787bool Item_func_in::to_be_transformed_into_in_subq(THD *thd)
788{
789 uint values_count= arg_count-1;
790
791 if (args[1]->type() == Item::ROW_ITEM)
792 values_count*= ((Item_row *)(args[1]))->cols();
793
794 if (values_count < thd->variables.in_subquery_conversion_threshold)
795 return false;
796
797 return true;
798}
799
800
801/**
802 @brief
803 Transform IN predicates into IN subqueries in WHERE and ON expressions
804
805 @param thd The context of the statement
806
807 @details
808 For each IN predicate from AND parts of the WHERE condition and/or
809 ON expressions of the SELECT for this join the method performs
810 the intransformation into an equivalent IN sunquery if it's needed.
811
812 @retval
813 false always
814*/
815
816bool JOIN::transform_in_predicates_into_in_subq(THD *thd)
817{
818 DBUG_ENTER("JOIN::transform_in_predicates_into_in_subq");
819 if (!select_lex->in_funcs.elements)
820 DBUG_RETURN(false);
821
822 SELECT_LEX *save_current_select= thd->lex->current_select;
823 enum_parsing_place save_parsing_place= select_lex->parsing_place;
824 thd->lex->current_select= select_lex;
825 if (conds)
826 {
827 select_lex->parsing_place= IN_WHERE;
828 conds=
829 conds->transform(thd,
830 &Item::in_predicate_to_in_subs_transformer,
831 (uchar*) 0);
832 if (!conds)
833 DBUG_RETURN(true);
834 select_lex->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
835 select_lex->where= conds;
836 }
837
838 if (join_list)
839 {
840 TABLE_LIST *table;
841 List_iterator<TABLE_LIST> li(*join_list);
842 select_lex->parsing_place= IN_ON;
843
844 while ((table= li++))
845 {
846 if (table->on_expr)
847 {
848 table->on_expr=
849 table->on_expr->transform(thd,
850 &Item::in_predicate_to_in_subs_transformer,
851 (uchar*) 0);
852 if (!table->on_expr)
853 DBUG_RETURN(true);
854 table->prep_on_expr= table->on_expr ?
855 table->on_expr->copy_andor_structure(thd) : 0;
856 }
857 }
858 }
859
860 select_lex->in_funcs.empty();
861 select_lex->parsing_place= save_parsing_place;
862 thd->lex->current_select= save_current_select;
863 DBUG_RETURN(false);
864}
865
866