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