1 /*
2    Copyright (c) 2019 MariaDB
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
16 
17 #include <typeinfo>
18 #include <string>
19 
20 #include "ha_mcs_pushdown.h"
21 
22 void check_walk(const Item* item, void* arg);
23 
24 
disable_indices_for_CEJ(THD * thd_)25 void disable_indices_for_CEJ(THD *thd_)
26 {
27     TABLE_LIST* global_list;
28     for (global_list = thd_->lex->query_tables; global_list; global_list = global_list->next_global)
29     {
30         // MCOL-652 - doing this with derived tables can cause bad things to happen
31         if (!global_list->derived)
32         {
33             global_list->index_hints= new (thd_->mem_root) List<Index_hint>();
34 
35             global_list->index_hints->push_front(new (thd_->mem_root)
36                                     Index_hint(INDEX_HINT_USE,
37                                     INDEX_HINT_MASK_JOIN,
38                                     NULL,
39                                     0), thd_->mem_root);
40 
41         }
42     }
43 }
44 
mutate_optimizer_flags(THD * thd_)45 void mutate_optimizer_flags(THD *thd_)
46 {
47     // MCOL-2178 Disable all optimizer flags as it was in the fork.
48     // CS restores it later in SH::scan_end() and in case of an error
49     // in SH::scan_init()
50 
51     ulonglong flags_to_set = OPTIMIZER_SWITCH_IN_TO_EXISTS |
52         OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED |
53         OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING;
54 
55     if (thd_->variables.optimizer_switch == flags_to_set)
56         return;
57 
58     set_original_optimizer_flags(thd_->variables.optimizer_switch, thd_);
59     thd_->variables.optimizer_switch = flags_to_set;
60 }
61 
restore_optimizer_flags(THD * thd_)62 void restore_optimizer_flags(THD *thd_)
63 {
64     // MCOL-2178 restore original optimizer flags after SH, DH
65     ulonglong orig_flags = get_original_optimizer_flags(thd_);
66     if (orig_flags)
67     {
68         thd_->variables.optimizer_switch = orig_flags;
69         set_original_optimizer_flags(0, thd_);
70     }
71 }
72 
73 /*@brief  find_tables - This traverses Item              */
74 /**********************************************************
75 * DESCRIPTION:
76 * This f() pushes TABLE of an Item_field to a list
77 * provided. The list is used for JOIN predicate check in
78 * is_joinkeys_predicate().
79 * PARAMETERS:
80 *    Item * Item to check
81 * RETURN:
82 ***********************************************************/
find_tables(const Item * item,void * arg)83 void find_tables(const Item* item, void* arg)
84 {
85     if (typeid(*item) == typeid(Item_field))
86     {
87         Item_field *ifp= (Item_field*)item;
88         List<TABLE> *tables_list= (List<TABLE>*)arg;
89         tables_list->push_back(ifp->field->table);
90     }
91 }
92 
93 /*@brief  is_joinkeys_predicate - This traverses Item_func*/
94 /***********************************************************
95 * DESCRIPTION:
96 * This f() walks Item_func and checks whether it contains
97 * JOIN predicate
98 * PARAMETERS:
99 *    Item_func * Item to walk
100 * RETURN:
101 *    BOOL false if Item_func isn't a JOIN predicate
102 *    BOOL true otherwise
103 ***********************************************************/
is_joinkeys_predicate(const Item_func * ifp)104 bool is_joinkeys_predicate(const Item_func *ifp)
105 {
106     bool result = false;
107     if(ifp->argument_count() == 2)
108     {
109         if (ifp->arguments()[0]->type() == Item::FIELD_ITEM &&
110           ifp->arguments()[1]->type() == Item::FIELD_ITEM)
111         {
112             Item_field* left= reinterpret_cast<Item_field*>(ifp->arguments()[0]);
113             Item_field* right= reinterpret_cast<Item_field*>(ifp->arguments()[1]);
114 
115             // If MDB crashes here with non-fixed Item_field and field == NULL
116             // there must be a check over on_expr for a different SELECT_LEX.
117             // e.g. checking subquery with ON from upper query.
118             if (left->field->table != right->field->table)
119             {
120                 result= true;
121             }
122         }
123         else
124         {
125             List<TABLE>llt; List<TABLE>rlt;
126             Item *left= ifp->arguments()[0];
127             Item *right= ifp->arguments()[1];
128             // Search for tables inside left and right expressions
129             // and compare them
130             left->traverse_cond(find_tables, (void*)&llt, Item::POSTFIX);
131             right->traverse_cond(find_tables, (void*)&rlt, Item::POSTFIX);
132             // TODO Find the way to have more then one element or prove
133             // the idea is useless.
134             if (llt.elements && rlt.elements && (llt.elem(0) != rlt.elem(0)))
135             {
136                 result= true;
137             }
138         }
139     }
140     return result;
141 }
142 
143 /*@brief  find_nonequi_join - This traverses Item          */
144 /************************************************************
145 * DESCRIPTION:
146 * This f() walks Item and looks for a non-equi join
147 * predicates
148 * PARAMETERS:
149 *    Item * Item to walk
150 * RETURN:
151 ***********************************************************/
find_nonequi_join(const Item * item,void * arg)152 void find_nonequi_join(const Item* item, void *arg)
153 {
154     bool *unsupported_feature  = reinterpret_cast<bool*>(arg);
155     if ( *unsupported_feature )
156         return;
157 
158     if (item->type() == Item::FUNC_ITEM)
159     {
160         const Item_func* ifp = reinterpret_cast<const Item_func*>(item);
161         //TODO Check for IN
162         //NOT IN + correlated subquery
163         if (ifp->functype() != Item_func::EQ_FUNC)
164         {
165             if (is_joinkeys_predicate(ifp))
166                 *unsupported_feature = true;
167             else if (ifp->functype() == Item_func::NOT_FUNC
168                        && ifp->arguments()[0]->type() == Item::EXPR_CACHE_ITEM)
169             {
170                 check_walk(ifp->arguments()[0], arg);
171             }
172         }
173     }
174 }
175 
176 /*@brief  find_join - This traverses Item                  */
177 /************************************************************
178 * DESCRIPTION:
179 * This f() walks traverses Item looking for JOIN, SEMI-JOIN
180 * predicates.
181 * PARAMETERS:
182 *    Item * Item to traverse
183 * RETURN:
184 ***********************************************************/
find_join(const Item * item,void * arg)185 void find_join(const Item* item, void* arg)
186 {
187     bool *unsupported_feature  = reinterpret_cast<bool*>(arg);
188     if ( *unsupported_feature )
189         return;
190 
191     if (item->type() == Item::FUNC_ITEM)
192     {
193         const Item_func* ifp = reinterpret_cast<const Item_func*>(item);
194         //TODO Check for IN
195         //NOT IN + correlated subquery
196         {
197             if (is_joinkeys_predicate(ifp))
198                 *unsupported_feature = true;
199             else if (ifp->functype() == Item_func::NOT_FUNC
200                        && ifp->arguments()[0]->type() == Item::EXPR_CACHE_ITEM)
201             {
202                 check_walk(ifp->arguments()[0], arg);
203             }
204         }
205     }
206 }
207 
208 /*@brief  save_join_predicate - This traverses Item        */
209 /************************************************************
210 * DESCRIPTION:
211 * This f() walks Item and saves found JOIN predicates into
212 * a List. The list will be used for a simple CROSS JOIN
213 * check in create_DH.
214 * PARAMETERS:
215 *    Item * Item to walk
216 * RETURN:
217 ***********************************************************/
save_join_predicates(const Item * item,void * arg)218 void save_join_predicates(const Item* item, void* arg)
219 {
220     if (item->type() == Item::FUNC_ITEM)
221     {
222         const Item_func* ifp= reinterpret_cast<const Item_func*>(item);
223         if (is_joinkeys_predicate(ifp))
224         {
225             List<Item> *join_preds_list= (List<Item>*)arg;
226             join_preds_list->push_back(const_cast<Item*>(item));
227         }
228     }
229 }
230 
231 /*@brief  check_walk - It traverses filter conditions      */
232 /************************************************************
233 * DESCRIPTION:
234 * It traverses filter predicates looking for unsupported
235 * JOIN types: non-equi JOIN, e.g  t1.c1 > t2.c2;
236 * logical OR.
237 * PARAMETERS:
238 *    thd - THD pointer.
239 *    derived - TABLE_LIST* to work with.
240 * RETURN:
241 ***********************************************************/
check_walk(const Item * item,void * arg)242 void check_walk(const Item* item, void* arg)
243 {
244     bool *unsupported_feature  = reinterpret_cast<bool*>(arg);
245     if ( *unsupported_feature )
246         return;
247 
248     switch (item->type())
249     {
250         case Item::FUNC_ITEM:
251         {
252             find_nonequi_join(item, arg);
253             break;
254         }
255         case Item::EXPR_CACHE_ITEM: // IN + correlated subquery
256         {
257             const Item_cache_wrapper* icw = reinterpret_cast<const Item_cache_wrapper*>(item);
258             if ( icw->get_orig_item()->type() == Item::FUNC_ITEM )
259             {
260                 const Item_func *ifp = reinterpret_cast<const Item_func*>(icw->get_orig_item());
261                 if ( ifp->argument_count() == 2 &&
262                     ( ifp->arguments()[0]->type() == Item::Item::SUBSELECT_ITEM
263                     || ifp->arguments()[1]->type() == Item::Item::SUBSELECT_ITEM ))
264                 {
265                     *unsupported_feature = true;
266                     return;
267                 }
268             }
269             break;
270         }
271         case Item::COND_ITEM: // OR contains JOIN conds thats is unsupported yet
272         {
273             Item_cond* icp = (Item_cond*)item;
274             if ( is_cond_or(icp) )
275             {
276                 bool left_flag= false, right_flag= false;
277                 if (icp->argument_list()->elements >= 2)
278                 {
279                     Item *left; Item *right;
280                     List_iterator<Item> li(*icp->argument_list());
281                     left = li++; right = li++;
282                     left->traverse_cond(find_join, (void*)&left_flag, Item::POSTFIX);
283                     right->traverse_cond(find_join, (void*)&right_flag, Item::POSTFIX);
284                     if (left_flag && right_flag)
285                     {
286                         *unsupported_feature = true;
287                     }
288                 }
289             }
290             break;
291         }
292         default:
293         {
294             break;
295         }
296     }
297 }
298 
299 /*@brief  check_user_var_func - This traverses Item        */
300 /************************************************************
301 * DESCRIPTION:
302 * This f() walks Item looking for the existence of
303 * "set_user_var" or "get_user_var" functions.
304 * PARAMETERS:
305 *    Item * Item to traverse
306 * RETURN:
307 ***********************************************************/
check_user_var_func(const Item * item,void * arg)308 void check_user_var_func(const Item* item, void* arg)
309 {
310     bool* unsupported_feature  = reinterpret_cast<bool*>(arg);
311 
312     if (*unsupported_feature)
313         return;
314 
315     if (item->type() == Item::FUNC_ITEM)
316     {
317         const Item_func* ifp = reinterpret_cast<const Item_func*>(item);
318         std::string funcname = ifp->func_name();
319         if (funcname == "set_user_var")
320         {
321             *unsupported_feature = true;
322         }
323     }
324 }
325 
item_check(Item * item,bool * unsupported_feature)326 void item_check(Item* item, bool* unsupported_feature)
327 {
328     switch (item->type())
329     {
330         case Item::COND_ITEM:
331         {
332             Item_cond *icp = reinterpret_cast<Item_cond*>(item);
333             icp->traverse_cond(check_user_var_func, unsupported_feature, Item::POSTFIX);
334             break;
335         }
336         case Item::FUNC_ITEM:
337         {
338             Item_func *ifp = reinterpret_cast<Item_func*>(item);
339             ifp->traverse_cond(check_user_var_func, unsupported_feature, Item::POSTFIX);
340             break;
341         }
342         default:
343         {
344             item->traverse_cond(check_user_var_func, unsupported_feature, Item::POSTFIX);
345             break;
346         }
347     }
348 }
349 
check_user_var(SELECT_LEX * select_lex)350 bool check_user_var(SELECT_LEX* select_lex)
351 {
352     List_iterator_fast<Item> it(select_lex->item_list);
353     Item* item;
354     bool is_user_var_func = false;
355 
356     while ((item = it++))
357     {
358         item_check(item, &is_user_var_func);
359 
360         if (is_user_var_func)
361         {
362             return true;
363         }
364     }
365 
366     JOIN *join = select_lex->join;
367 
368     if (join->conds)
369     {
370         Item_cond* icp = reinterpret_cast<Item_cond*>(join->conds);
371 
372         icp->traverse_cond(check_user_var_func, &is_user_var_func, Item::POSTFIX);
373     }
374 
375     return is_user_var_func;
376 }
377 
378 /*@brief  create_columnstore_group_by_handler- Creates handler*/
379 /***********************************************************
380  * DESCRIPTION:
381  * Creates a group_by pushdown handler if there is no:
382  *  non-equi JOIN, e.g * t1.c1 > t2.c2
383  *  logical OR in the filter predicates
384  *  Impossible WHERE
385  *  Impossible HAVING
386  * and there is either GROUP BY or aggregation function
387  * exists at the top level.
388  * Valid queries with the last two crashes the server if
389  * processed.
390  * Details are in server/sql/group_by_handler.h
391  * PARAMETERS:
392  *    thd - THD pointer
393  *    query - Query structure LFM in group_by_handler.h
394  * RETURN:
395  *    group_by_handler if success
396  *    NULL in other case
397  ***********************************************************/
398 group_by_handler*
create_columnstore_group_by_handler(THD * thd,Query * query)399 create_columnstore_group_by_handler(THD* thd, Query* query)
400 {
401     ha_mcs_group_by_handler* handler = NULL;
402     // Disable GBH.
403     return handler;
404 
405     // same as thd->lex->current_select
406     SELECT_LEX *select_lex = query->from->select_lex;
407 
408     // MCOL-2178 Disable SP support in the group_by_handler for now
409     // Check the session variable value to enable/disable use of
410     // group_by_handler. There is no GBH if SH works for the query.
411     if (get_select_handler(thd) || !get_group_by_handler(thd) || (thd->lex)->sphead)
412     {
413         return handler;
414     }
415 
416     // Create a handler if query is valid. See comments for details.
417     if ( query->group_by || select_lex->with_sum_func )
418     {
419         bool unsupported_feature = false;
420         // revisit SELECT_LEX for all units
421         for(TABLE_LIST* tl = query->from; !unsupported_feature && tl; tl = tl->next_global)
422         {
423             select_lex = tl->select_lex;
424             // Correlation subquery. Comming soon so fail on this yet.
425             unsupported_feature = select_lex->is_correlated;
426 
427             // Impossible HAVING or WHERE
428             if (!unsupported_feature &&
429                 (select_lex->having_value == Item::COND_FALSE
430                   || select_lex->cond_value == Item::COND_FALSE ))
431             {
432                 unsupported_feature = true;
433             }
434 
435             // Unsupported JOIN conditions
436             if ( !unsupported_feature )
437             {
438                 JOIN *join = select_lex->join;
439                 Item_cond *icp = 0;
440 
441                 if (join != 0)
442                     icp = reinterpret_cast<Item_cond*>(join->conds);
443 
444                 if (unsupported_feature == false && icp)
445                 {
446                     icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX);
447                 }
448 
449                 // Optimizer could move some join conditions into where
450                 if (select_lex->where != 0)
451                     icp = reinterpret_cast<Item_cond*>(select_lex->where);
452 
453                 if (unsupported_feature == false && icp)
454                 {
455                     icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX);
456                 }
457             }
458 
459             // Iterate and traverse through the item list and the JOIN cond
460             // and do not create GBH if the unsupported (set_user_var)
461             // function is present.
462             if (check_user_var(select_lex))
463             {
464                 return handler;
465             }
466         } // unsupported features check ends here
467 
468         if (!unsupported_feature)
469         {
470             handler = new ha_mcs_group_by_handler(thd, query);
471 
472             // Notify the server, that CS handles GROUP BY, ORDER BY and HAVING clauses.
473             query->group_by = NULL;
474             query->order_by = NULL;
475             query->having = NULL;
476         }
477     }
478 
479     return handler;
480 }
481 
482 /*@brief  create_columnstore_derived_handler- Creates handler*/
483 /************************************************************
484  * DESCRIPTION:
485  * Creates a derived handler if there is no non-equi JOIN, e.g
486  * t1.c1 > t2.c2 and logical OR in the filter predicates.
487  * More details in server/sql/derived_handler.h
488  * PARAMETERS:
489  *    thd - THD pointer.
490  *    derived - TABLE_LIST* to work with.
491  * RETURN:
492  *    derived_handler if possible
493  *    NULL in other case
494  ***********************************************************/
495 derived_handler*
create_columnstore_derived_handler(THD * thd,TABLE_LIST * table_ptr)496 create_columnstore_derived_handler(THD* thd, TABLE_LIST *table_ptr)
497 {
498     ha_columnstore_derived_handler* handler = NULL;
499 
500     // MCOL-2178 Disable SP support in the derived_handler for now
501     // Check the session variable value to enable/disable use of
502     // derived_handler
503     if (!get_derived_handler(thd) || (thd->lex)->sphead)
504     {
505         return handler;
506     }
507 
508     // Disable derived handler for prepared statements
509     if (thd->stmt_arena && thd->stmt_arena->is_stmt_execute())
510         return handler;
511 
512     SELECT_LEX_UNIT *unit= table_ptr->derived;
513     SELECT_LEX *sl= unit->first_select();
514 
515     bool unsupported_feature = false;
516 
517     // Impossible HAVING or WHERE
518     if ( unsupported_feature
519        || sl->having_value == Item::COND_FALSE
520         || sl->cond_value == Item::COND_FALSE )
521     {
522         unsupported_feature = true;
523     }
524 
525     // JOIN expression from WHERE, ON expressions
526     JOIN* join= sl->join;
527     //TODO DRRTUY Make a proper tree traverse
528     //To search for CROSS JOIN-s we use tree invariant
529     //G(V,E) where [V] = [E]+1
530     List<Item> join_preds_list;
531     TABLE_LIST *tl;
532     for (tl = sl->get_table_list(); !unsupported_feature && tl; tl = tl->next_local)
533     {
534         if (tl->where)
535         {
536             Item_cond* where_icp= reinterpret_cast<Item_cond*>(tl->where);
537             where_icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX);
538             where_icp->traverse_cond(save_join_predicates, &join_preds_list, Item::POSTFIX);
539         }
540 
541         // Looking for JOIN with ON expression through
542         // TABLE_LIST in FROM until CS meets unsupported feature
543         if (tl->on_expr)
544         {
545             Item_cond* on_icp= reinterpret_cast<Item_cond*>(tl->on_expr);
546             on_icp->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX);
547             on_icp->traverse_cond(save_join_predicates, &join_preds_list, Item::POSTFIX);
548         }
549 
550         // Iterate and traverse through the item list and the JOIN cond
551         // and do not create DH if the unsupported (set_user_var)
552         // function is present.
553         if (check_user_var(tl->select_lex))
554         {
555             return handler;
556         }
557     }
558 
559     if (!unsupported_feature && !join_preds_list.elements
560           && join && join->conds)
561     {
562         Item_cond* conds= reinterpret_cast<Item_cond*>(join->conds);
563         conds->traverse_cond(check_walk, &unsupported_feature, Item::POSTFIX);
564         conds->traverse_cond(save_join_predicates, &join_preds_list, Item::POSTFIX);
565     }
566 
567     // CROSS JOIN w/o conditions isn't supported until MCOL-301
568     // is ready.
569     if (!unsupported_feature && join
570          && join->table_count >= 2 && !join_preds_list.elements)
571     {
572         unsupported_feature= true;
573     }
574 
575     // CROSS JOIN with not enough JOIN predicates
576     if(!unsupported_feature && join
577         && join_preds_list.elements < join->table_count-1)
578     {
579         unsupported_feature= true;
580     }
581 
582     if ( !unsupported_feature )
583         handler= new ha_columnstore_derived_handler(thd, table_ptr);
584 
585   return handler;
586 }
587 
588 /***********************************************************
589  * DESCRIPTION:
590  * derived_handler constructor
591  * PARAMETERS:
592  *    thd - THD pointer.
593  *    tbl - tables involved.
594  ***********************************************************/
ha_columnstore_derived_handler(THD * thd,TABLE_LIST * dt)595 ha_columnstore_derived_handler::ha_columnstore_derived_handler(THD *thd,
596                                                              TABLE_LIST *dt)
597   : derived_handler(thd, mcs_hton)
598 {
599   derived = dt;
600 }
601 
602 /***********************************************************
603  * DESCRIPTION:
604  * derived_handler destructor
605  ***********************************************************/
~ha_columnstore_derived_handler()606 ha_columnstore_derived_handler::~ha_columnstore_derived_handler()
607 {}
608 
609 /*@brief  Initiate the query for derived_handler           */
610 /***********************************************************
611  * DESCRIPTION:
612  * Execute the query and saves derived table query.
613  * PARAMETERS:
614  *
615  * RETURN:
616  *    rc as int
617  ***********************************************************/
init_scan()618 int ha_columnstore_derived_handler::init_scan()
619 {
620     DBUG_ENTER("ha_columnstore_derived_handler::init_scan");
621 
622     mcs_handler_info mhi = mcs_handler_info(reinterpret_cast<void*>(this), DERIVED);
623     // this::table is the place for the result set
624     int rc = ha_mcs_impl_pushdown_init(&mhi, table);
625 
626     DBUG_RETURN(rc);
627 }
628 
629 /*@brief  Fetch next row for derived_handler               */
630 /***********************************************************
631  * DESCRIPTION:
632  * Fetches next row and saves it in the temp table
633  * PARAMETERS:
634  *
635  * RETURN:
636  *    rc as int
637  *
638  ***********************************************************/
next_row()639 int ha_columnstore_derived_handler::next_row()
640 {
641     DBUG_ENTER("ha_columnstore_derived_handler::next_row");
642 
643     int rc = ha_mcs_impl_rnd_next(table->record[0], table);
644 
645     DBUG_RETURN(rc);
646 }
647 
648 /*@brief  Finishes the scan and clean it up               */
649 /***********************************************************
650  * DESCRIPTION:
651  * Finishes the scan for derived handler
652  * PARAMETERS:
653  *
654  * RETURN:
655  *    rc as int
656  *
657  ***********************************************************/
end_scan()658 int ha_columnstore_derived_handler::end_scan()
659 {
660     DBUG_ENTER("ha_columnstore_derived_handler::end_scan");
661 
662     int rc = ha_mcs_impl_rnd_end(table, true);
663 
664     DBUG_RETURN(rc);
665 }
666 
print_error(int,unsigned long)667 void ha_columnstore_derived_handler::print_error(int, unsigned long)
668 {
669 }
670 
671 /***********************************************************
672  * DESCRIPTION:
673  * GROUP BY handler constructor
674  * PARAMETERS:
675  *    thd - THD pointer.
676  *    query - Query describing structure
677  ***********************************************************/
ha_mcs_group_by_handler(THD * thd_arg,Query * query)678 ha_mcs_group_by_handler::ha_mcs_group_by_handler(THD* thd_arg, Query* query)
679         : group_by_handler(thd_arg, mcs_hton),
680           select(query->select),
681           table_list(query->from),
682           distinct(query->distinct),
683           where(query->where),
684           group_by(query->group_by),
685           order_by(query->order_by),
686           having(query->having)
687 {
688 }
689 
690 /***********************************************************
691  * DESCRIPTION:
692  * GROUP BY destructor
693  ***********************************************************/
~ha_mcs_group_by_handler()694 ha_mcs_group_by_handler::~ha_mcs_group_by_handler()
695 {
696 }
697 
698 /***********************************************************
699  * DESCRIPTION:
700  * Makes the plan and prepares the data
701  * RETURN:
702  *    int rc
703  ***********************************************************/
init_scan()704 int ha_mcs_group_by_handler::init_scan()
705 {
706     DBUG_ENTER("ha_mcs_group_by_handler::init_scan");
707 
708     mcs_handler_info mhi = mcs_handler_info(reinterpret_cast<void*>(this), GROUP_BY);
709     int rc = ha_mcs_impl_group_by_init(&mhi, table);
710 
711     DBUG_RETURN(rc);
712 }
713 
714 /***********************************************************
715  * DESCRIPTION:
716  * Fetches a row and saves it to a temporary table.
717  * RETURN:
718  *    int rc
719  ***********************************************************/
next_row()720 int ha_mcs_group_by_handler::next_row()
721 {
722     DBUG_ENTER("ha_mcs_group_by_handler::next_row");
723     int rc = ha_mcs_impl_group_by_next(table);
724 
725     DBUG_RETURN(rc);
726 }
727 
728 /***********************************************************
729  * DESCRIPTION:
730  * Shuts the scan down.
731  * RETURN:
732  *    int rc
733  ***********************************************************/
end_scan()734 int ha_mcs_group_by_handler::end_scan()
735 {
736     DBUG_ENTER("ha_mcs_group_by_handler::end_scan");
737     int rc = ha_mcs_impl_group_by_end(table);
738 
739     DBUG_RETURN(rc);
740 }
741 
742 /*@brief  create_columnstore_select_handler- Creates handler*/
743 /************************************************************
744  * DESCRIPTION:
745  * Creates a select handler if there is no non-equi JOIN, e.g
746  * t1.c1 > t2.c2 and logical OR in the filter predicates.
747  * More details in server/sql/select_handler.h
748  * PARAMETERS:
749  *    thd - THD pointer.
750  *    sel - SELECT_LEX* that describes the query.
751  * RETURN:
752  *    select_handler if possible
753  *    NULL in other case
754  ***********************************************************/
755 select_handler*
create_columnstore_select_handler(THD * thd,SELECT_LEX * select_lex)756 create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex)
757 {
758     ha_columnstore_select_handler* handler = NULL;
759 
760     // Check the session variable value to enable/disable use of
761     // select_handler
762     if (!get_select_handler(thd) ||
763         ((thd->lex)->sphead && !get_select_handler_in_stored_procedures(thd)))
764     {
765         return handler;
766     }
767 
768     // Flag to indicate if this is a prepared statement
769     bool isPS = thd->stmt_arena && thd->stmt_arena->is_stmt_execute();
770 
771     // Disable processing of select_result_interceptor classes
772     // which intercept and transform result set rows. E.g.:
773     // select a,b into @a1, @a2 from t1;
774     if (((thd->lex)->result &&
775         !((select_dumpvar *)(thd->lex)->result)->var_list.is_empty()) &&
776         (!isPS))
777     {
778         return handler;
779     }
780 
781     // Select_handler couldn't properly process UPSERT..SELECT
782     if ((thd->lex)->sql_command == SQLCOM_INSERT_SELECT
783             && thd->lex->duplicates == DUP_UPDATE)
784     {
785         return handler;
786     }
787 
788     // Iterate and traverse through the item list and the JOIN cond
789     // and do not create SH if the unsupported (set_user_var)
790     // function is present.
791     TABLE_LIST* table_ptr = select_lex->get_table_list();
792     for (; table_ptr; table_ptr = table_ptr->next_global)
793     {
794         if (check_user_var(table_ptr->select_lex))
795         {
796             return handler;
797         }
798     }
799 
800     // We apply dedicated rewrites from MDB here so MDB's data structures
801     // becomes dirty and CS has to raise an error in case of any problem
802     // or unsupported feature.
803     handler= new ha_columnstore_select_handler(thd, select_lex);
804     bool unsupported_feature = false;
805     JOIN *join= select_lex->join;
806     {
807         Query_arena *arena, backup;
808         arena= thd->activate_stmt_arena_if_needed(&backup);
809 
810         disable_indices_for_CEJ(thd);
811 
812         if (arena)
813             thd->restore_active_arena(arena, &backup);
814 
815         if (select_lex->handle_derived(thd->lex, DT_MERGE))
816         {
817             unsupported_feature = true;
818             handler->err_msg.assign("create_columnstore_select_handler(): \
819                 Internal error occured in SL::handle_derived()");
820         }
821 
822         COND *conds = nullptr;
823         if (!unsupported_feature)
824         {
825             SELECT_LEX *sel= select_lex;
826             // Rewrite once for PS
827 	    // Refer to JOIN::optimize_inner() in sql/sql_select.cc
828 	    // for details on the optimizations performed in this block.
829             if (sel->first_cond_optimization)
830             {
831                 create_explain_query_if_not_exists(thd->lex, thd->mem_root);
832                 arena= thd->activate_stmt_arena_if_needed(&backup);
833                 sel->first_cond_optimization= false;
834 
835                 conds= simplify_joins_mcs(join, select_lex->join_list,
836                     join->conds, true, false);
837 
838                 build_bitmap_for_nested_joins_mcs(select_lex->join_list, 0);
839                 sel->where= conds;
840 
841                 if (isPS)
842                 {
843                     sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
844 
845                     if (in_subselect_rewrite(sel))
846                     {
847                         unsupported_feature = true;
848                         handler->err_msg.assign("create_columnstore_select_handler(): \
849                             Internal error occured in in_subselect_rewrite()");
850                     }
851                 }
852 
853                 select_lex->update_used_tables();
854 
855                 if (arena)
856                     thd->restore_active_arena(arena, &backup);
857 
858                 // Unset SL::first_cond_optimization
859                 opt_flag_unset_PS(sel);
860             }
861         }
862 
863         if (!unsupported_feature && conds)
864         {
865 #ifdef DEBUG_WALK_COND
866             conds->traverse_cond(cal_impl_if::debug_walk, NULL, Item::POSTFIX);
867 #endif
868             join->conds = conds;
869         }
870 
871         // MCOL-3747 IN-TO-EXISTS rewrite inside MDB didn't add
872         // an equi-JOIN condition.
873         if (!unsupported_feature && !isPS && in_subselect_rewrite(select_lex))
874         {
875             unsupported_feature = true;
876             handler->err_msg.assign("create_columnstore_select_handler(): \
877                 Internal error occured in in_subselect_rewrite()");
878         }
879     }
880 
881     // We shouldn't raise error now so set an error to raise it later in init_SH.
882     handler->rewrite_error= unsupported_feature;
883     // Return SH even if init fails b/c CS changed SELECT_LEX structures
884     // with simplify_joins_mcs()
885     return handler;
886 }
887 
888 /***********************************************************
889  * DESCRIPTION:
890  * select_handler constructor
891  * PARAMETERS:
892  *    thd - THD pointer.
893  *    select_lex - sematic tree for the query.
894  ***********************************************************/
ha_columnstore_select_handler(THD * thd,SELECT_LEX * select_lex)895 ha_columnstore_select_handler::ha_columnstore_select_handler(THD *thd,
896                                                              SELECT_LEX* select_lex)
897   : select_handler(thd, mcs_hton)
898 {
899   select= select_lex;
900   rewrite_error= false;
901 }
902 
903 /***********************************************************
904  * DESCRIPTION:
905  * select_handler constructor
906  ***********************************************************/
~ha_columnstore_select_handler()907 ha_columnstore_select_handler::~ha_columnstore_select_handler()
908 {
909 }
910 
911 /*@brief  Initiate the query for select_handler           */
912 /***********************************************************
913  * DESCRIPTION:
914  * Execute the query and saves select table query.
915  * PARAMETERS:
916  *
917  * RETURN:
918  *    rc as int
919  ***********************************************************/
init_scan()920 int ha_columnstore_select_handler::init_scan()
921 {
922     DBUG_ENTER("ha_columnstore_select_handler::init_scan");
923 
924     int rc = 0;
925 
926     if (!rewrite_error)
927     {
928         // handler::table is the place for the result set
929         // Skip execution for EXPLAIN queries
930         if (!thd->lex->describe)
931         {
932             mcs_handler_info mhi= mcs_handler_info(
933                 reinterpret_cast<void*>(this), SELECT);
934             rc= ha_mcs_impl_pushdown_init(&mhi, this->table);
935         }
936     }
937     else
938     {
939         my_printf_error(ER_INTERNAL_ERROR, "%s", MYF(0), err_msg.c_str());
940         sql_print_error("%s", err_msg.c_str());
941         rc= ER_INTERNAL_ERROR;
942     }
943 
944     DBUG_RETURN(rc);
945 }
946 
947 /*@brief  Fetch next row for select_handler               */
948 /***********************************************************
949  * DESCRIPTION:
950  * Fetches next row and saves it in the temp table
951  * PARAMETERS:
952  *
953  * RETURN:
954  *    rc as int
955  *
956  ***********************************************************/
next_row()957 int ha_columnstore_select_handler::next_row()
958 {
959     DBUG_ENTER("ha_columnstore_select_handler::next_row");
960 
961     int rc= ha_mcs_impl_select_next(table->record[0], table);
962 
963     DBUG_RETURN(rc);
964 }
965 
966 /*@brief  Finishes the scan and clean it up               */
967 /***********************************************************
968  * DESCRIPTION:
969  * Finishes the scan for select handler
970  * PARAMETERS:
971  *
972  * RETURN:
973  *    rc as int
974  *
975  ***********************************************************/
end_scan()976 int ha_columnstore_select_handler::end_scan()
977 {
978     DBUG_ENTER("ha_columnstore_select_handler::end_scan");
979 
980     int rc = ha_mcs_impl_rnd_end(table, true);
981 
982     DBUG_RETURN(rc);
983 }
984