From cdd9bed1ae74e65be6081782825225086a5f9ebe Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Tue, 3 Jul 2018 18:22:13 +0300 Subject: [PATCH] MCOL-1510 GROUP BY supports functions with aggregation funcs as arguments in projections, e.g. sum(i)+1. --- dbcon/mysql/ha_calpont.cpp | 40 +++++++++++++++ dbcon/mysql/ha_calpont.h | 30 +++++------ dbcon/mysql/ha_calpont_execplan.cpp | 77 +++++++++++++++++++++++++---- dbcon/mysql/ha_calpont_impl.cpp | 4 +- dbcon/mysql/ha_calpont_impl_if.h | 10 ++-- 5 files changed, 129 insertions(+), 32 deletions(-) diff --git a/dbcon/mysql/ha_calpont.cpp b/dbcon/mysql/ha_calpont.cpp index 79efdb88e..8d3996fe2 100644 --- a/dbcon/mysql/ha_calpont.cpp +++ b/dbcon/mysql/ha_calpont.cpp @@ -1170,6 +1170,46 @@ create_calpont_group_by_handler(THD* thd, Query* query) return handler; } +/*********************************************************** + * DESCRIPTION: + * GROUP BY handler constructor + * PARAMETERS: + * thd - THD pointer. + * query - Query describing structure + ***********************************************************/ +ha_calpont_group_by_handler::ha_calpont_group_by_handler(THD* thd_arg, Query* query) + : group_by_handler(thd_arg, calpont_hton), + select(query->select), + table_list(query->from), + distinct(query->distinct), + where(query->where), + group_by(query->group_by), + order_by(query->order_by), + having(query->having) +{ + List_iterator_fast item_iter(*select); + Item* item; + char* str = NULL; + while((item = item_iter++)) + { + String descr; + item->print(&descr, QT_ORDINARY); + str = new char[descr.length()+1]; + strncpy(str, descr.ptr(), descr.length()); + str[descr.length()] = '\0'; + select_list_descr.push_back(str); + } +} + +/*********************************************************** + * DESCRIPTION: + * GROUP BY destructor + ***********************************************************/ +ha_calpont_group_by_handler::~ha_calpont_group_by_handler() +{ + select_list_descr.delete_elements(); +} + /*********************************************************** * DESCRIPTION: * Makes the plan and prepares the data diff --git a/dbcon/mysql/ha_calpont.h b/dbcon/mysql/ha_calpont.h index bcbcdc5da..3c6f7e49e 100644 --- a/dbcon/mysql/ha_calpont.h +++ b/dbcon/mysql/ha_calpont.h @@ -255,12 +255,16 @@ public: * One should read comments in server/sql/group_by_handler.h * Attributes: * select - attribute contains all GROUP BY, HAVING, ORDER items and calls it - * an extended SELECT list accordin to comments in - * server/sql/group_handler.cc. - * So the temporary table for - * select count(*) from b group by a having a > 3 order by a - * will have 4 columns not 1. - * However server ignores all NULLs used in GROUP BY, HAVING, ORDER. + * an extended SELECT list according to comments in + * server/sql/group_handler.cc. + * So the temporary table for + * select count(*) from b group by a having a > 3 order by a + * will have 4 columns not 1. + * However server ignores all NULLs used in + * GROUP BY, HAVING, ORDER. + * select_list_descr - contains Item description returned by Item->print() + * that is used in lookup for corresponding columns in + * extended SELECT list. * table_list - contains all tables involved. Must be CS tables only. * distinct - looks like a useless thing for now. Couldn't get it set by server. * where - where items. @@ -275,22 +279,14 @@ public: class ha_calpont_group_by_handler: public group_by_handler { public: - ha_calpont_group_by_handler(THD* thd_arg, Query* query) - : group_by_handler(thd_arg, calpont_hton), - select(query->select), - table_list(query->from), - distinct(query->distinct), - where(query->where), - group_by(query->group_by), - order_by(query->order_by), - having(query->having) - { } - ~ha_calpont_group_by_handler() { } + ha_calpont_group_by_handler(THD* thd_arg, Query* query); + ~ha_calpont_group_by_handler(); int init_scan(); int next_row(); int end_scan(); List* select; + List select_list_descr; TABLE_LIST* table_list; bool distinct; Item* where; diff --git a/dbcon/mysql/ha_calpont_execplan.cpp b/dbcon/mysql/ha_calpont_execplan.cpp index c0bf47b95..b06c197aa 100644 --- a/dbcon/mysql/ha_calpont_execplan.cpp +++ b/dbcon/mysql/ha_calpont_execplan.cpp @@ -42,6 +42,9 @@ #include #include #include + +#include + using namespace std; #include @@ -188,6 +191,24 @@ bool nonConstFunc(Item_func* ifp) return false; } +ReturnedColumn* findCorrespTempField(Item_ref* item, gp_walk_info& gwi) +{ + ReturnedColumn* result = NULL; + uint32_t i; + for (i = 0; i < gwi.returnedCols.size(); i++) + { + if (item->ref[0] && item->ref[0]->name && + gwi.returnedCols[i]->alias().c_str() && + !strcasecmp(item->ref[0]->name, gwi.returnedCols[i]->alias().c_str())) + { + result = gwi.returnedCols[i]->clone(); + break; + } + } + + return result; +} + string getViewName(TABLE_LIST* table_ptr) { string viewName = ""; @@ -2739,7 +2760,7 @@ CalpontSystemCatalog::ColType colType_MysqlToIDB (const Item* item) return ct; } -ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport) +ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand) { ReturnedColumn* rc = NULL; @@ -2864,7 +2885,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp } if (func_name == "+" || func_name == "-" || func_name == "*" || func_name == "/" ) - return buildArithmeticColumn(ifp, gwi, nonSupport); + return buildArithmeticColumn(ifp, gwi, nonSupport, pushdownHand); else return buildFunctionColumn(ifp, gwi, nonSupport); } @@ -2998,7 +3019,11 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp return rc; } -ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport) +ArithmeticColumn* buildArithmeticColumn( + Item_func* item, + gp_walk_info& gwi, + bool& nonSupport, + bool pushdownHand) { if (!(gwi.thd->infinidb_vtable.cal_conn_info)) gwi.thd->infinidb_vtable.cal_conn_info = (void*)(new cal_connection_info()); @@ -3021,7 +3046,7 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool { if (gwi.clauseType == SELECT || /*gwi.clauseType == HAVING || */gwi.clauseType == GROUP_BY || gwi.clauseType == FROM) // select list { - lhs = new ParseTree(buildReturnedColumn(sfitempp[0], gwi, nonSupport)); + lhs = new ParseTree(buildReturnedColumn(sfitempp[0], gwi, nonSupport, pushdownHand)); if (!lhs->data() && (sfitempp[0]->type() == Item::FUNC_ITEM)) { @@ -3029,8 +3054,15 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool Item_func* ifp = (Item_func*)sfitempp[0]; lhs = buildParseTree(ifp, gwi, nonSupport); } - - rhs = new ParseTree(buildReturnedColumn(sfitempp[1], gwi, nonSupport)); + else if(pushdownHand && !lhs->data() && (sfitempp[0]->type() == Item::REF_ITEM)) + { + // There must be an aggregation column in extended SELECT + // list so find the corresponding column. + ReturnedColumn* rc = findCorrespTempField(static_cast(sfitempp[0]), gwi); + if(rc) + lhs = new ParseTree(rc); + } + rhs = new ParseTree(buildReturnedColumn(sfitempp[1], gwi, nonSupport, pushdownHand)); if (!rhs->data() && (sfitempp[1]->type() == Item::FUNC_ITEM)) { @@ -3038,6 +3070,14 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool Item_func* ifp = (Item_func*)sfitempp[1]; rhs = buildParseTree(ifp, gwi, nonSupport); } + else if(pushdownHand && !rhs->data() && (sfitempp[1]->type() == Item::REF_ITEM)) + { + // There must be an aggregation column in extended SELECT + // list so find the corresponding column. + ReturnedColumn* rc = findCorrespTempField(static_cast(sfitempp[1]), gwi); + if(rc) + rhs = new ParseTree(rc); + } } else // where clause { @@ -3198,7 +3238,11 @@ ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool return ac; } -ReturnedColumn* buildFunctionColumn(Item_func* ifp, gp_walk_info& gwi, bool& nonSupport) +ReturnedColumn* buildFunctionColumn( + Item_func* ifp, + gp_walk_info& gwi, + bool& nonSupport, + bool pushdownHand) { if (!(gwi.thd->infinidb_vtable.cal_conn_info)) gwi.thd->infinidb_vtable.cal_conn_info = (void*)(new cal_connection_info()); @@ -3239,7 +3283,7 @@ ReturnedColumn* buildFunctionColumn(Item_func* ifp, gp_walk_info& gwi, bool& non // Arithmetic exp if (funcName == "+" || funcName == "-" || funcName == "*" || funcName == "/" ) { - ArithmeticColumn* ac = buildArithmeticColumn(ifp, gwi, nonSupport); + ArithmeticColumn* ac = buildArithmeticColumn(ifp, gwi, nonSupport, pushdownHand); return ac; } @@ -8087,6 +8131,7 @@ int cp_get_group_plan(THD* thd, SCSEP& csep, cal_impl_if::cal_group_info& gi) SELECT_LEX select_lex = lex->select_lex; gp_walk_info gwi; gwi.thd = thd; + gwi.groupByAuxDescr = gi.groupByAuxDescr; int status = getGroupPlan(gwi, select_lex, csep, gi); cerr << "---------------- cp_get_group_plan EXECUTION PLAN ----------------" << endl; @@ -8468,6 +8513,8 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro string sel_cols_in_create; string sel_cols_in_select; bool redo = false; + List_iterator_fast itDescr(*gi.groupByAuxDescr); + char* fieldDescr; // empty rcWorkStack and ptWorkStack. They should all be empty by now. clearStacks(gwi); @@ -8486,7 +8533,15 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro while ((item = it++)) { - string itemAlias = (item->name ? item->name : ""); + // Given the size of gi.groupByAuxDescr is equal to gi.groupByFields + fieldDescr = itDescr++; + string itemAlias; + if(item->name) + itemAlias = (item->name); + else + { + itemAlias = (fieldDescr ? fieldDescr: ""); + } // @bug 5916. Need to keep checking until getting concret item in case // of nested view. @@ -8592,6 +8647,8 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro return ER_CHECK_NOT_IMPLEMENTED; } + if(!ac->alias().length()) + ac->alias(fieldDescr); // add this agg col to returnedColumnList boost::shared_ptr spac(ac); gwi.returnedCols.push_back(spac); @@ -8651,7 +8708,7 @@ int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_gro return ER_CHECK_NOT_IMPLEMENTED; } - ReturnedColumn* rc = buildFunctionColumn(ifp, gwi, hasNonSupportItem); + ReturnedColumn* rc = buildFunctionColumn(ifp, gwi, hasNonSupportItem, true); SRCP srcp(rc); if (rc) diff --git a/dbcon/mysql/ha_calpont_impl.cpp b/dbcon/mysql/ha_calpont_impl.cpp index 3d4ee6ac3..9a018068d 100644 --- a/dbcon/mysql/ha_calpont_impl.cpp +++ b/dbcon/mysql/ha_calpont_impl.cpp @@ -5265,6 +5265,7 @@ int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE // MCOL-1052 Send Items lists down to the optimizer. gi.groupByTables = group_hand->table_list; gi.groupByFields = group_hand->select; + gi.groupByAuxDescr = &group_hand->select_list_descr; gi.groupByWhere = group_hand->where; gi.groupByGroup = group_hand->group_by; gi.groupByOrder = group_hand->order_by; @@ -5831,7 +5832,8 @@ int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* try { - sm::tpl_close(ti.tpl_ctx, &hndl, ci->stats); + if(hndl) + sm::tpl_close(ti.tpl_ctx, &hndl, ci->stats); ci->cal_conn_hndl = hndl; diff --git a/dbcon/mysql/ha_calpont_impl_if.h b/dbcon/mysql/ha_calpont_impl_if.h index cb603ca49..40e746917 100644 --- a/dbcon/mysql/ha_calpont_impl_if.h +++ b/dbcon/mysql/ha_calpont_impl_if.h @@ -142,6 +142,7 @@ struct gp_walk_info std::map derivedTbFilterMap; uint32_t derivedTbCnt; std::vector subselectList; + List* groupByAuxDescr; // Kludge for Bug 750 int32_t recursionLevel; @@ -195,6 +196,7 @@ struct cal_table_info struct cal_group_info { cal_group_info() : groupByFields(0), + groupByAuxDescr(0), groupByTables(0), groupByWhere(0), groupByGroup(0), @@ -205,6 +207,7 @@ struct cal_group_info ~cal_group_info() { } List* groupByFields; // MCOL-1052 SELECT + List* groupByAuxDescr; //MCOL-1052 Auxilary column descriptions TABLE_LIST* groupByTables; // MCOL-1052 FROM Item* groupByWhere; // MCOL-1052 WHERE ORDER* groupByGroup; // MCOL-1052 GROUP BY @@ -327,14 +330,13 @@ void setError(THD* thd, uint32_t errcode, const std::string errmsg, gp_walk_info void setError(THD* thd, uint32_t errcode, const std::string errmsg); void gp_walk(const Item* item, void* arg); void parse_item (Item* item, std::vector& field_vec, bool& hasNonSupportItem, uint16& parseInfo); -execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport); const std::string bestTableName(const Item_field* ifp); bool isInfiniDB(TABLE* table_ptr); // execution plan util functions prototypes -execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport); -execplan::ReturnedColumn* buildFunctionColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport); -execplan::ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport); +execplan::ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand = false); +execplan::ReturnedColumn* buildFunctionColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand = false); +execplan::ArithmeticColumn* buildArithmeticColumn(Item_func* item, gp_walk_info& gwi, bool& nonSupport, bool pushdownHand = false); execplan::ConstantColumn* buildDecimalColumn(Item* item, gp_walk_info& gwi); execplan::SimpleColumn* buildSimpleColumn(Item_field* item, gp_walk_info& gwi); execplan::FunctionColumn* buildCaseFunction(Item_func* item, gp_walk_info& gwi, bool& nonSupport);