diff --git a/dbcon/joblist/jlf_subquery.cpp b/dbcon/joblist/jlf_subquery.cpp index 1e4eaeeec..add3dc533 100644 --- a/dbcon/joblist/jlf_subquery.cpp +++ b/dbcon/joblist/jlf_subquery.cpp @@ -756,8 +756,8 @@ int doFromSubquery(CalpontExecutionPlan* ep, const string& alias, const string& void addOrderByAndLimit(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo) { // make sure there is a LIMIT - if (csep->orderByCols().size() > 0 && csep->limitNum() == (uint64_t) - 1) - return; +// if (csep->orderByCols().size() > 0 csep->limitNum() == (uint64_t) - 1) +// return; jobInfo.limitStart = csep->limitStart(); jobInfo.limitCount = csep->limitNum(); diff --git a/dbcon/joblist/jlf_tuplejoblist.cpp b/dbcon/joblist/jlf_tuplejoblist.cpp index aabc81486..480b23f91 100644 --- a/dbcon/joblist/jlf_tuplejoblist.cpp +++ b/dbcon/joblist/jlf_tuplejoblist.cpp @@ -483,28 +483,28 @@ void adjustLastStep(JobStepVector& querySteps, DeliveredTableMap& deliverySteps, deliverySteps[CNX_VTABLE_ID] = ws; } - if ((jobInfo.limitCount != (uint64_t) - 1) || - (jobInfo.constantCol == CONST_COL_EXIST) || - (jobInfo.hasDistinct)) - { +// if ((jobInfo.limitCount != (uint64_t) - 1) || +// (jobInfo.constantCol == CONST_COL_EXIST) || +// (jobInfo.hasDistinct)) +// { if (jobInfo.annexStep.get() == NULL) jobInfo.annexStep.reset(new TupleAnnexStep(jobInfo)); TupleAnnexStep* tas = dynamic_cast(jobInfo.annexStep.get()); tas->setLimit(jobInfo.limitStart, jobInfo.limitCount); - if (jobInfo.limitCount != (uint64_t) - 1) - { + // if (jobInfo.limitCount != (uint64_t) - 1) +// { if (jobInfo.orderByColVec.size() > 0) tas->addOrderBy(new LimitedOrderBy()); - } +// } if (jobInfo.constantCol == CONST_COL_EXIST) tas->addConstant(new TupleConstantStep(jobInfo)); if (jobInfo.hasDistinct) tas->setDistinct(); - } +// } if (jobInfo.annexStep) { diff --git a/dbcon/joblist/joblistfactory.cpp b/dbcon/joblist/joblistfactory.cpp index 812256869..a48ecd13a 100644 --- a/dbcon/joblist/joblistfactory.cpp +++ b/dbcon/joblist/joblistfactory.cpp @@ -1622,7 +1622,7 @@ void makeVtableModeSteps(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo, JobStepVector& querySteps, JobStepVector& projectSteps, DeliveredTableMap& deliverySteps) { // @bug4848, enhance and unify limit handling. - if (csep->limitNum() != (uint64_t) - 1) +// if (csep->limitNum() != (uint64_t) - 1) { // special case for outer query order by limit -- return all if (jobInfo.subId == 0 && csep->hasOrderBy()) diff --git a/dbcon/joblist/limitedorderby.cpp b/dbcon/joblist/limitedorderby.cpp index e9bcaf95e..6701faf4b 100644 --- a/dbcon/joblist/limitedorderby.cpp +++ b/dbcon/joblist/limitedorderby.cpp @@ -76,7 +76,13 @@ void LimitedOrderBy::initialize(const RowGroup& rg, const JobInfo& jobInfo) { map::iterator j = keyToIndexMap.find(i->first); idbassert(j != keyToIndexMap.end()); - fOrderByCond.push_back(IdbSortSpec(j->second, i->second)); + // MCOL-1052 Ordering direction in CSEP differs from + // internal direction representation. + if (i->second) + fOrderByCond.push_back(IdbSortSpec(j->second, false)); + else + fOrderByCond.push_back(IdbSortSpec(j->second, true)); + //fOrderByCond.push_back(IdbSortSpec(j->second, i->second)); } // limit row count info @@ -174,7 +180,9 @@ void LimitedOrderBy::finalize() if (fRowGroup.getRowCount() > 0) fDataQueue.push(fData); - if (fStart != 0) + // MCOL-1052 The removed check effectivly disables sorting to happen, + // since fStart = 0; + if (true) { uint64_t newSize = fRowsPerRG * fRowGroup.getRowSize(); fMemSize += newSize; diff --git a/dbcon/joblist/tupleaggregatestep.cpp b/dbcon/joblist/tupleaggregatestep.cpp index 9e23ac17b..3dbd01311 100644 --- a/dbcon/joblist/tupleaggregatestep.cpp +++ b/dbcon/joblist/tupleaggregatestep.cpp @@ -1304,7 +1304,7 @@ void TupleAggregateStep::prep1PhaseAggregate( { throw logic_error("prep1PhaseAggregate: A UDAF function is called but there's no/not enough UDAFColumn/-s"); } - } + } else { funct.reset(new RowAggFunctionCol(aggOp, stats, colProj, i)); diff --git a/dbcon/mysql/ha_calpont.cpp b/dbcon/mysql/ha_calpont.cpp index 1a1b0b5ec..aed7ffafc 100644 --- a/dbcon/mysql/ha_calpont.cpp +++ b/dbcon/mysql/ha_calpont.cpp @@ -123,6 +123,9 @@ static int calpont_rollback(handlerton* hton, THD* thd, bool all); static int calpont_close_connection ( handlerton* hton, THD* thd ); handlerton* calpont_hton; +static group_by_handler * +create_calpont_group_by_handler(THD *thd, Query *query); + /* Variables for example share methods */ /* @@ -218,6 +221,7 @@ static int columnstore_init_func(void* p) calpont_hton->commit = calpont_commit; calpont_hton->rollback = calpont_rollback; calpont_hton->close_connection = calpont_close_connection; + calpont_hton->create_group_by = create_calpont_group_by_handler; DBUG_RETURN(0); } @@ -1135,6 +1139,86 @@ static MYSQL_SYSVAR_ULONG( 0); #endif +/*@brief create_calpont_group_by_handler- Creates handler*/ +/*********************************************************** + * DESCRIPTION: + * Creates a group_by pushdown handler. + * Details are in server/sql/group_by_handler.h + * PARAMETERS: + * thd - THD pointer. + * query - Query structure, that describes the pushdowned query. + * RETURN: + * group_by_handler if success + * NULL in other case + ***********************************************************/ +static group_by_handler * +create_calpont_group_by_handler(THD *thd, Query *query) +{ + ha_calpont_group_by_handler *handler = NULL; + + if ( thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE ) + { + handler = new ha_calpont_group_by_handler(thd, query); + + // Notify the server, that CS handles GROUP BY, ORDER BY and HAVING clauses. + query->group_by = NULL; + query->order_by = NULL; + query->having = NULL; + } + + return handler; +} + +/*********************************************************** + * DESCRIPTION: + * Makes the plan and prepares the data + * RETURN: + * int rc + ***********************************************************/ +int ha_calpont_group_by_handler::init_scan() +{ + DBUG_ENTER("ha_calpont_group_by_handler::init_scan"); + + // Save vtable_state to restore the after we inited. + THD::infinidb_state oldState = thd->infinidb_vtable.vtable_state; + // MCOL-1052 Should be removed after cleaning the code up. + thd->infinidb_vtable.vtable_state = THD::INFINIDB_CREATE_VTABLE; + int rc = ha_calpont_impl_group_by_init(this, table); + thd->infinidb_vtable.vtable_state = oldState; + + DBUG_RETURN(rc); +} + +/*********************************************************** + * DESCRIPTION: + * Fetches a row and saves it to a temporary table. + * RETURN: + * int rc + ***********************************************************/ +int ha_calpont_group_by_handler::next_row() +{ + DBUG_ENTER("ha_calpont_group_by_handler::next_row"); + int rc = ha_calpont_impl_group_by_next(this, table); + + DBUG_RETURN(rc); +} + +/*********************************************************** + * DESCRIPTION: + * Shuts the scan down. + * RETURN: + * int rc + ***********************************************************/ +int ha_calpont_group_by_handler::end_scan() +{ + DBUG_ENTER("ha_calpont_group_by_handler::end_scan"); + + int rc = ha_calpont_impl_group_by_end(this, table); + + DBUG_RETURN(rc); +} + + static struct st_mysql_sys_var* calpont_system_variables[] = { // MYSQL_SYSVAR(enum_var), diff --git a/dbcon/mysql/ha_calpont.h b/dbcon/mysql/ha_calpont.h index 6abaf51ed..d1e545fec 100644 --- a/dbcon/mysql/ha_calpont.h +++ b/dbcon/mysql/ha_calpont.h @@ -40,6 +40,8 @@ #include #include "idb_mysql.h" +extern handlerton* calpont_hton; + /** @brief EXAMPLE_SHARE is a structure that will be shared among all open handlers. This example implements the minimum of what you will probably need. @@ -245,5 +247,56 @@ public: } }; + +/*@brief group_by_handler class*/ +/*********************************************************** + * DESCRIPTION: + * Provides server with group_by_handler API methods. + * 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. + * 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. + * group_by - group by ORDER items. + * order_by - order by ORDER items. + * having - having Item. + * Methods: + * init_scan - get plan and send it to ExeMgr. Get the execution result. + * next_row - get a row back from sm. + * end_scan - finish and clean the things up. + ***********************************************************/ +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() { } + int init_scan(); + int next_row(); + int end_scan(); + + List *select; + TABLE_LIST *table_list; + bool distinct; + Item *where; + ORDER *group_by; + ORDER *order_by; + Item *having; +}; #endif //HA_CALPONT_H__ diff --git a/dbcon/mysql/ha_calpont_execplan.cpp b/dbcon/mysql/ha_calpont_execplan.cpp index 210da9992..02fa4d8a4 100644 --- a/dbcon/mysql/ha_calpont_execplan.cpp +++ b/dbcon/mysql/ha_calpont_execplan.cpp @@ -221,7 +221,7 @@ void debug_walk(const Item* item, void* arg) case Item::FIELD_ITEM: { Item_field* ifp = (Item_field*)item; - cout << "FIELD_ITEM: " << (ifp->db_name ? ifp->db_name : "") << '.' << bestTableName(ifp) << + cerr << "FIELD_ITEM: " << (ifp->db_name ? ifp->db_name : "") << '.' << bestTableName(ifp) << '.' << ifp->field_name << endl; break; } @@ -229,10 +229,10 @@ void debug_walk(const Item* item, void* arg) case Item::INT_ITEM: { Item_int* iip = (Item_int*)item; - cout << "INT_ITEM: "; + cerr << "INT_ITEM: "; - if (iip->name) cout << iip->name << " (from name string)" << endl; - else cout << iip->val_int() << endl; + if (iip->name) cerr << iip->name << " (from name string)" << endl; + else cerr << iip->val_int() << endl; break; } @@ -243,19 +243,19 @@ void debug_walk(const Item* item, void* arg) String val, *str = isp->val_str(&val); string valStr; valStr.assign(str->ptr(), str->length()); - cout << "STRING_ITEM: >" << valStr << '<' << endl; + cerr << "STRING_ITEM: >" << valStr << '<' << endl; break; } case Item::REAL_ITEM: { - cout << "REAL_ITEM" << endl; + cerr << "REAL_ITEM" << endl; break; } case Item::DECIMAL_ITEM: { - cout << "DECIMAL_ITEM" << endl; + cerr << "DECIMAL_ITEM" << endl; break; } @@ -263,85 +263,85 @@ void debug_walk(const Item* item, void* arg) { Item_func* ifp = (Item_func*)item; Item_func_opt_neg* inp; - cout << "FUNC_ITEM: "; + cerr << "FUNC_ITEM: "; switch (ifp->functype()) { case Item_func::UNKNOWN_FUNC: // 0 - cout << ifp->func_name() << " (" << ifp->functype() << ")" << endl; + cerr << ifp->func_name() << " (" << ifp->functype() << ")" << endl; break; case Item_func::GT_FUNC: // 7 - cout << '>' << " (" << ifp->functype() << ")" << endl; + cerr << '>' << " (" << ifp->functype() << ")" << endl; break; case Item_func::EQ_FUNC: // 1 - cout << '=' << " (" << ifp->functype() << ")" << endl; + cerr << '=' << " (" << ifp->functype() << ")" << endl; break; case Item_func::GE_FUNC: - cout << ">=" << " (" << ifp->functype() << ")" << endl; + cerr << ">=" << " (" << ifp->functype() << ")" << endl; break; case Item_func::LE_FUNC: - cout << "<=" << " (" << ifp->functype() << ")" << endl; + cerr << "<=" << " (" << ifp->functype() << ")" << endl; break; case Item_func::LT_FUNC: - cout << '<' << " (" << ifp->functype() << ")" << endl; + cerr << '<' << " (" << ifp->functype() << ")" << endl; break; case Item_func::NE_FUNC: - cout << "<>" << " (" << ifp->functype() << ")" << endl; + cerr << "<>" << " (" << ifp->functype() << ")" << endl; break; case Item_func::NEG_FUNC: // 45 - cout << "unary minus" << " (" << ifp->functype() << ")" << endl; + cerr << "unary minus" << " (" << ifp->functype() << ")" << endl; break; case Item_func::IN_FUNC: // 16 inp = (Item_func_opt_neg*)ifp; - if (inp->negated) cout << "not "; + if (inp->negated) cerr << "not "; - cout << "in" << " (" << ifp->functype() << ")" << endl; + cerr << "in" << " (" << ifp->functype() << ")" << endl; break; case Item_func::BETWEEN: inp = (Item_func_opt_neg*)ifp; - if (inp->negated) cout << "not "; + if (inp->negated) cerr << "not "; - cout << "between" << " (" << ifp->functype() << ")" << endl; + cerr << "between" << " (" << ifp->functype() << ")" << endl; break; case Item_func::ISNULL_FUNC: // 10 - cout << "is null" << " (" << ifp->functype() << ")" << endl; + cerr << "is null" << " (" << ifp->functype() << ")" << endl; break; case Item_func::ISNOTNULL_FUNC: // 11 - cout << "is not null" << " (" << ifp->functype() << ")" << endl; + cerr << "is not null" << " (" << ifp->functype() << ")" << endl; break; case Item_func::NOT_ALL_FUNC: - cout << "not_all" << " (" << ifp->functype() << ")" << endl; + cerr << "not_all" << " (" << ifp->functype() << ")" << endl; break; case Item_func::NOT_FUNC: - cout << "not_func" << " (" << ifp->functype() << ")" << endl; + cerr << "not_func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::TRIG_COND_FUNC: - cout << "trig_cond_func" << " (" << ifp->functype() << ")" << endl; + cerr << "trig_cond_func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::ISNOTNULLTEST_FUNC: - cout << "isnotnulltest_func" << " (" << ifp->functype() << ")" << endl; + cerr << "isnotnulltest_func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::MULT_EQUAL_FUNC: { - cout << "mult_equal_func:" << " (" << ifp->functype() << ")" << endl; + cerr << "mult_equal_func:" << " (" << ifp->functype() << ")" << endl; Item_equal* item_eq = (Item_equal*)ifp; Item_equal_fields_iterator it(*item_eq); Item* item; @@ -349,142 +349,142 @@ void debug_walk(const Item* item, void* arg) while ((item = it++)) { Field* equal_field = it.get_curr_field(); - cout << equal_field->field_name << endl; + cerr << equal_field->field_name << endl; } break; } case Item_func::EQUAL_FUNC: - cout << "equal func" << " (" << ifp->functype() << ")" << endl; + cerr << "equal func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::FT_FUNC: - cout << "ft func" << " (" << ifp->functype() << ")" << endl; + cerr << "ft func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::LIKE_FUNC: - cout << "like func" << " (" << ifp->functype() << ")" << endl; + cerr << "like func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::COND_AND_FUNC: - cout << "cond and func" << " (" << ifp->functype() << ")" << endl; + cerr << "cond and func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::COND_OR_FUNC: - cout << "cond or func" << " (" << ifp->functype() << ")" << endl; + cerr << "cond or func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::XOR_FUNC: - cout << "xor func" << " (" << ifp->functype() << ")" << endl; + cerr << "xor func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::INTERVAL_FUNC: - cout << "interval func" << " (" << ifp->functype() << ")" << endl; + cerr << "interval func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_EQUALS_FUNC: - cout << "sp equals func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp equals func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_DISJOINT_FUNC: - cout << "sp disjoint func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp disjoint func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_INTERSECTS_FUNC: - cout << "sp intersects func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp intersects func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_TOUCHES_FUNC: - cout << "sp touches func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp touches func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_CROSSES_FUNC: - cout << "sp crosses func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp crosses func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_WITHIN_FUNC: - cout << "sp within func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp within func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_CONTAINS_FUNC: - cout << "sp contains func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp contains func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_OVERLAPS_FUNC: - cout << "sp overlaps func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp overlaps func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_STARTPOINT: - cout << "sp startpoint func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp startpoint func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_ENDPOINT: - cout << "sp endpoint func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp endpoint func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_EXTERIORRING: - cout << "sp exteriorring func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp exteriorring func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_POINTN: - cout << "sp pointn func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp pointn func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_GEOMETRYN: - cout << "sp geometryn func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp geometryn func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_INTERIORRINGN: - cout << "sp exteriorringn func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp exteriorringn func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SP_RELATE_FUNC: - cout << "sp relate func" << " (" << ifp->functype() << ")" << endl; + cerr << "sp relate func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::NOW_FUNC: - cout << "now func" << " (" << ifp->functype() << ")" << endl; + cerr << "now func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::SUSERVAR_FUNC: - cout << "suservar func" << " (" << ifp->functype() << ")" << endl; + cerr << "suservar func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::GUSERVAR_FUNC: - cout << "guservar func" << " (" << ifp->functype() << ")" << endl; + cerr << "guservar func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::COLLATE_FUNC: - cout << "collate func" << " (" << ifp->functype() << ")" << endl; + cerr << "collate func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::EXTRACT_FUNC: - cout << "extract func" << " (" << ifp->functype() << ")" << endl; + cerr << "extract func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::CHAR_TYPECAST_FUNC: - cout << "char typecast func" << " (" << ifp->functype() << ")" << endl; + cerr << "char typecast func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::FUNC_SP: - cout << "func sp func" << " (" << ifp->functype() << ")" << endl; + cerr << "func sp func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::UDF_FUNC: - cout << "udf func" << " (" << ifp->functype() << ")" << endl; + cerr << "udf func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::GSYSVAR_FUNC: - cout << "gsysvar func" << " (" << ifp->functype() << ")" << endl; + cerr << "gsysvar func" << " (" << ifp->functype() << ")" << endl; break; case Item_func::DYNCOL_FUNC: - cout << "dyncol func" << " (" << ifp->functype() << ")" << endl; + cerr << "dyncol func" << " (" << ifp->functype() << ")" << endl; break; default: - cout << "type=" << ifp->functype() << endl; + cerr << "type=" << ifp->functype() << endl; break; } @@ -494,7 +494,7 @@ void debug_walk(const Item* item, void* arg) case Item::COND_ITEM: { Item_cond* icp = (Item_cond*)item; - cout << "COND_ITEM: " << icp->func_name() << endl; + cerr << "COND_ITEM: " << icp->func_name() << endl; break; } @@ -503,7 +503,17 @@ void debug_walk(const Item* item, void* arg) Item_sum* isp = (Item_sum*)item; char* item_name = item->name; - if (!item_name) + // MCOL-1052 This is an extended SELECT list item + if (!item_name && isp->get_arg_count() && isp->get_arg(0)->name) + { + item_name = isp->get_arg(0)->name; + } + else if (!item_name && isp->get_arg_count() + && isp->get_arg(0)->type() == Item::INT_ITEM) + { + item_name = (char*)"INT||*"; + } + else if (!item_name) { item_name = (char*)""; } @@ -511,39 +521,39 @@ void debug_walk(const Item* item, void* arg) switch (isp->sum_func()) { case Item_sum::SUM_FUNC: - cout << "SUM_FUNC: " << item_name << endl; + cerr << "SUM_FUNC: " << item_name << endl; break; case Item_sum::SUM_DISTINCT_FUNC: - cout << "SUM_DISTINCT_FUNC: " << item_name << endl; + cerr << "SUM_DISTINCT_FUNC: " << item_name << endl; break; case Item_sum::AVG_FUNC: - cout << "AVG_FUNC: " << item_name << endl; + cerr << "AVG_FUNC: " << item_name << endl; break; case Item_sum::COUNT_FUNC: - cout << "COUNT_FUNC: " << item_name << endl; + cerr << "COUNT_FUNC: " << item_name << endl; break; case Item_sum::COUNT_DISTINCT_FUNC: - cout << "COUNT_DISTINCT_FUNC: " << item_name << endl; + cerr << "COUNT_DISTINCT_FUNC: " << item_name << endl; break; case Item_sum::MIN_FUNC: - cout << "MIN_FUNC: " << item_name << endl; + cerr << "MIN_FUNC: " << item_name << endl; break; case Item_sum::MAX_FUNC: - cout << "MAX_FUNC: " << item_name << endl; + cerr << "MAX_FUNC: " << item_name << endl; break; case Item_sum::UDF_SUM_FUNC: - cout << "UDAF_FUNC: " << item_name << endl; + cerr << "UDAF_FUNC: " << item_name << endl; break; default: - cout << "SUM_FUNC_ITEM type=" << isp->sum_func() << endl; + cerr << "SUM_FUNC_ITEM type=" << isp->sum_func() << endl; break; } @@ -553,24 +563,24 @@ void debug_walk(const Item* item, void* arg) case Item::SUBSELECT_ITEM: { Item_subselect* sub = (Item_subselect*)item; - cout << "SUBSELECT Item: "; + cerr << "SUBSELECT Item: "; switch (sub->substype()) { case Item_subselect::EXISTS_SUBS: - cout << "EXISTS"; + cerr << "EXISTS"; break; case Item_subselect::IN_SUBS: - cout << "IN"; + cerr << "IN"; break; default: - cout << sub->substype(); + cerr << sub->substype(); break; } - cout << endl; + cerr << endl; JOIN* join = sub->get_select_lex()->join; if (join) @@ -581,7 +591,7 @@ void debug_walk(const Item* item, void* arg) cond->traverse_cond(debug_walk, arg, Item::POSTFIX); } - cout << "Finish subselect item traversing" << endl; + cerr << "Finish subselect item traversing" << endl; break; } @@ -599,14 +609,14 @@ void debug_walk(const Item* item, void* arg) //ifp->cached_table->select_lex->select_number gives the select level. // could be used on alias. // could also be used to tell correlated join (equal level). - cout << "CACHED REF FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << + cerr << "CACHED REF FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << '.' << ifp->field_name << endl; break; } else if (field->type() == Item::FUNC_ITEM) { Item_func* ifp = (Item_func*)field; - cout << "CACHED REF FUNC_ITEM " << ifp->func_name() << endl; + cerr << "CACHED REF FUNC_ITEM " << ifp->func_name() << endl; } else if (field->type() == Item::REF_ITEM) { @@ -686,34 +696,43 @@ void debug_walk(const Item* item, void* arg) } } - cout << "CACHED REF_ITEM: ref type " << refType.c_str() << " real type " << realType.c_str() << endl; + cerr << "CACHED REF_ITEM: ref type " << refType.c_str() << " real type " << realType.c_str() << endl; break; } else { - cout << "REF_ITEM with CACHE_ITEM type unknown " << field->type() << endl; + cerr << "REF_ITEM with CACHE_ITEM type unknown " << field->type() << endl; } } else if (ref->real_item()->type() == Item::FIELD_ITEM) { Item_field* ifp = (Item_field*)ref->real_item(); - cout << "REF FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << '.' << - ifp->field_name << endl; + // MCOL-1052 The field referenced presumable came from + // extended SELECT list. + if ( !ifp->field_name ) + { + cerr << "REF extra FIELD_ITEM: " << ifp->name << endl; + } + else + { + cerr << "REF FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << '.' << + ifp->field_name << endl; + } break; } else if (ref->real_item()->type() == Item::FUNC_ITEM) { Item_func* ifp = (Item_func*)ref->real_item(); - cout << "REF FUNC_ITEM " << ifp->func_name() << endl; + cerr << "REF FUNC_ITEM " << ifp->func_name() << endl; } else if (ref->real_item()->type() == Item::WINDOW_FUNC_ITEM) { Item_window_func* ifp = (Item_window_func*)ref->real_item(); - cout << "REF WINDOW_FUNC_ITEM " << ifp->window_func()->func_name() << endl; + cerr << "REF WINDOW_FUNC_ITEM " << ifp->window_func()->func_name() << endl; } else { - cout << "UNKNOWN REF ITEM type " << ref->real_item()->type() << endl; + cerr << "UNKNOWN REF ITEM type " << ref->real_item()->type() << endl; } break; @@ -722,7 +741,7 @@ void debug_walk(const Item* item, void* arg) case Item::ROW_ITEM: { Item_row* row = (Item_row*)item; - cout << "ROW_ITEM: " << endl; + cerr << "ROW_ITEM: " << endl; for (uint32_t i = 0; i < row->cols(); i++) debug_walk(row->element_index(i), 0); @@ -732,7 +751,7 @@ void debug_walk(const Item* item, void* arg) case Item::EXPR_CACHE_ITEM: { - cout << "Expr Cache Item" << endl; + cerr << "Expr Cache Item" << endl; ((Item_cache_wrapper*)item)->get_orig_item()->traverse_cond(debug_walk, arg, Item::POSTFIX); break; } @@ -747,27 +766,27 @@ void debug_walk(const Item* item, void* arg) switch (item->result_type()) { case STRING_RESULT: - cout << "CACHE_STRING_ITEM" << endl; + cerr << "CACHE_STRING_ITEM" << endl; break; case REAL_RESULT: - cout << "CACHE_REAL_ITEM " << isp->val_real() << endl; + cerr << "CACHE_REAL_ITEM " << isp->val_real() << endl; break; case INT_RESULT: - cout << "CACHE_INT_ITEM " << isp->val_int() << endl; + cerr << "CACHE_INT_ITEM " << isp->val_int() << endl; break; case ROW_RESULT: - cout << "CACHE_ROW_ITEM" << endl; + cerr << "CACHE_ROW_ITEM" << endl; break; case DECIMAL_RESULT: - cout << "CACHE_DECIMAL_ITEM " << isp->val_decimal() << endl; + cerr << "CACHE_DECIMAL_ITEM " << isp->val_decimal() << endl; break; default: - cout << "CACHE_UNKNOWN_ITEM" << endl; + cerr << "CACHE_UNKNOWN_ITEM" << endl; break; } @@ -780,7 +799,7 @@ void debug_walk(const Item* item, void* arg) //ifp->cached_table->select_lex->select_number gives the select level. // could be used on alias. // could also be used to tell correlated join (equal level). - cout << "CACHED FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << + cerr << "CACHED FIELD_ITEM: " << ifp->db_name << '.' << bestTableName(ifp) << '.' << ifp->field_name << endl; break; } @@ -862,18 +881,18 @@ void debug_walk(const Item* item, void* arg) } } - cout << "CACHE_ITEM ref type " << refType.c_str() << " real type " << realType.c_str() << endl; + cerr << "CACHE_ITEM ref type " << refType.c_str() << " real type " << realType.c_str() << endl; break; } else if (field->type() == Item::FUNC_ITEM) { Item_func* ifp = (Item_func*)field; - cout << "CACHE_ITEM FUNC_ITEM " << ifp->func_name() << endl; + cerr << "CACHE_ITEM FUNC_ITEM " << ifp->func_name() << endl; break; } else { - cout << "CACHE_ITEM type unknown " << field->type() << endl; + cerr << "CACHE_ITEM type unknown " << field->type() << endl; } break; @@ -884,12 +903,12 @@ void debug_walk(const Item* item, void* arg) String val, *str = NULL; Item_temporal_literal* itp = (Item_temporal_literal*)item; str = itp->val_str(&val); - cout << "DATE ITEM: "; + cerr << "DATE ITEM: "; if (str) - cout << ": (" << str->ptr() << ')' << endl; + cerr << ": (" << str->ptr() << ')' << endl; else - cout << ": " << endl; + cerr << ": " << endl; break; } @@ -897,13 +916,18 @@ void debug_walk(const Item* item, void* arg) case Item::WINDOW_FUNC_ITEM: { Item_window_func* ifp = (Item_window_func*)item; - cout << "Window Function Item " << ifp->window_func()->func_name() << endl; + cerr << "Window Function Item " << ifp->window_func()->func_name() << endl; + break; + } + + case Item::NULL_ITEM: + { + cerr << "NULL item" << endl; break; } - default: { - cout << "UNKNOWN_ITEM type " << item->type() << endl; + cerr << "UNKNOWN_ITEM type " << item->type() << endl; break; } } @@ -1015,11 +1039,11 @@ uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex) #ifdef DEBUG_WALK_COND if (table_ptr->alias) - cout << table_ptr->alias ; + cerr << table_ptr->alias ; else if (table_ptr->alias) - cout << table_ptr->alias; + cerr << table_ptr->alias; - cout << " outer table expression: " << endl; + cerr << " outer table expression: " << endl; expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX); #endif expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX); @@ -1053,13 +1077,13 @@ uint32_t buildOuterJoin(gp_walk_info& gwi, SELECT_LEX& select_lex) Item_cond* expr = reinterpret_cast(table_ptr->embedding->on_expr); #ifdef DEBUG_WALK_COND - cout << "inner tables: " << endl; + cerr << "inner tables: " << endl; set::const_iterator it; for (it = gwi_outer.innerTables.begin(); it != gwi_outer.innerTables.end(); ++it) - cout << (*it) << " "; + cerr << (*it) << " "; - cout << endl; + cerr << endl; expr->traverse_cond(debug_walk, &gwi_outer, Item::POSTFIX); #endif expr->traverse_cond(gp_walk, &gwi_outer, Item::POSTFIX); @@ -1485,7 +1509,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) // @bug5811. This filter string is for cross engine to use. // Use real table name. ifp->print(&str, QT_INFINIDB_DERIVED); - IDEBUG(cout << str.ptr() << endl); + IDEBUG(cerr << str.ptr() << endl); if (str.ptr()) cf->data(str.c_ptr()); @@ -1811,7 +1835,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) (current_thd->lex->sql_command == SQLCOM_DELETE) || (current_thd->lex->sql_command == SQLCOM_DELETE_MULTI))) { - IDEBUG( cout << "deleted func with 2 const columns" << endl ); + IDEBUG( cerr << "deleted func with 2 const columns" << endl ); delete rhs; delete lhs; return false; @@ -1865,7 +1889,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) if (notInner) { lhs->returnAll(true); - IDEBUG( cout << "setting returnAll on " << tan_lhs << endl); + IDEBUG( cerr << "setting returnAll on " << tan_lhs << endl); } } @@ -1882,7 +1906,7 @@ bool buildPredicateItem(Item_func* ifp, gp_walk_info* gwip) if (notInner) { rhs->returnAll(true); - IDEBUG( cout << "setting returnAll on " << tan_rhs << endl ); + IDEBUG( cerr << "setting returnAll on " << tan_rhs << endl ); } } @@ -2591,7 +2615,7 @@ CalpontSystemCatalog::ColType fieldType_MysqlToIDB (const Field* field) break; default: - IDEBUG( cout << "fieldType_MysqlToIDB:: Unknown result type of MySQL " + IDEBUG( cerr << "fieldType_MysqlToIDB:: Unknown result type of MySQL " << field->result_type() << endl ); break; } @@ -2704,7 +2728,7 @@ CalpontSystemCatalog::ColType colType_MysqlToIDB (const Item* item) break; default: - IDEBUG( cout << "colType_MysqlToIDB:: Unknown result type of MySQL " + IDEBUG( cerr << "colType_MysqlToIDB:: Unknown result type of MySQL " << item->result_type() << endl ); break; } @@ -2718,7 +2742,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp if ( gwi.thd) { - if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI )) + //if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI )) { if ( !item->fixed) { @@ -2908,7 +2932,7 @@ ReturnedColumn* buildReturnedColumn(Item* item, gp_walk_info& gwi, bool& nonSupp { // TODO: item is a Item_cache_wrapper printf("EXPR_CACHE_ITEM in buildReturnedColumn\n"); - cout << "EXPR_CACHE_ITEM in buildReturnedColumn" << endl; + cerr << "EXPR_CACHE_ITEM in buildReturnedColumn" << endl; break; } @@ -3982,7 +4006,7 @@ ParseTree* buildParseTree(Item_func* item, gp_walk_info& gwi, bool& nonSupport) Item_cond* icp = (Item_cond*)item; #ifdef DEBUG_WALK_COND // debug - cout << "Build Parsetree: " << endl; + cerr << "Build Parsetree: " << endl; icp->traverse_cond(debug_walk, &gwi, Item::POSTFIX); #endif //@bug5044. PPSTFIX walking should always be treated as WHERE clause filter @@ -4443,7 +4467,7 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) } else if (ac->constCol()) { - gwi.count_asterisk_list.push_back(ac); + gwi.count_asterisk_list.push_back(ac); } // For UDAF, populate the context and call the UDAF init() function. @@ -4829,7 +4853,7 @@ void gp_walk(const Item* item, void* arg) gwip->rcWorkStack.push(cc); if (str) - IDEBUG( cout << "Const F&E " << item->full_name() << " evaluate: " << valStr << endl ); + IDEBUG( cerr << "Const F&E " << item->full_name() << " evaluate: " << valStr << endl ); break; } @@ -5032,7 +5056,11 @@ void gp_walk(const Item* item, void* arg) gwip->clauseType = SELECT; if (col->type() != Item::COND_ITEM) + { rc = buildReturnedColumn(col, *gwip, gwip->fatalParseError); + if ( col->type() == Item::FIELD_ITEM ) + gwip->fatalParseError = false; + } SimpleColumn* sc = dynamic_cast(rc); @@ -5104,6 +5132,26 @@ void gp_walk(const Item* item, void* arg) Item_func* ifp = (Item_func*)col; gwip->ptWorkStack.push(buildParseTree(ifp, *gwip, gwip->fatalParseError)); } + else if (col->type() == Item::FIELD_ITEM && gwip->clauseType == HAVING) + { + Item_field* ifip = static_cast(col); + std::vector::iterator iter = gwip->havingAggColsItems.begin(); + Item_func_or_sum *isfp = NULL; + for( ;iter != gwip->havingAggColsItems.end(); iter++ ) + { + Item *temp_isfp = *iter; + isfp = reinterpret_cast(temp_isfp); + if ( isfp->type() == Item::SUM_FUNC_ITEM && + isfp->result_field == ifip->field ) + { + ReturnedColumn* rc = buildAggregateColumn(isfp, *gwip); + if (rc) + gwip->rcWorkStack.push(rc); + break; + } + } + break; + } else cando = false; @@ -5389,7 +5437,7 @@ void parse_item (Item* item, vector& field_vec, bool& hasNonSupport } else { - cout << "UNKNOWN REF Item" << endl; + cerr << "UNKNOWN REF Item" << endl; break; } } @@ -5461,7 +5509,7 @@ bool isInfiniDB(TABLE* table_ptr) int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool isUnion) { #ifdef DEBUG_WALK_COND - cout << "getSelectPlan()" << endl; + cerr << "getSelectPlan()" << endl; #endif // by pass the derived table resolve phase of mysql @@ -5548,7 +5596,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i while ((sj_nest = sj_list_it++)) { - cout << sj_nest->db << "." << sj_nest->table_name << endl; + cerr << sj_nest->db << "." << sj_nest->table_name << endl; } #endif @@ -5632,7 +5680,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i CalpontSystemCatalog::TableAliasName tan = make_aliastable(table_ptr->db, table_name, table_ptr->alias, infiniDB); gwi.tableMap[tan] = make_pair(0, table_ptr); #ifdef DEBUG_WALK_COND - cout << tn << endl; + cerr << tn << endl; #endif } } @@ -5712,15 +5760,15 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i distUnionNum = unionVec.size(); /*#ifdef DEBUG_WALK_COND - IDEBUG( cout << ">>>> UNION DEBUG" << endl ); + IDEBUG( cerr << ">>>> UNION DEBUG" << endl ); JOIN* join = sl->join; Item_cond* icp = 0; if (join != 0) icp = reinterpret_cast(join->conds); if (icp) icp->traverse_cond(debug_walk, &gwi, Item::POSTFIX); - IDEBUG ( cout << *plan << endl ); - IDEBUG ( cout << "<<<traverse_cond(debug_walk, &gwi, Item::POSTFIX); - cout << "------------------------------------------------\n" << endl; + cerr << "------------------------------------------------\n" << endl; #endif icp->traverse_cond(gp_walk, &gwi, Item::POSTFIX); @@ -5797,16 +5845,16 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i TABLE_LIST* curr = *tbl; if (curr->table_name) - cout << curr->table_name << " "; + cerr << curr->table_name << " "; else - cout << curr->alias << endl; + cerr << curr->alias << endl; if (curr->outer_join) - cout << " is inner table" << endl; + cerr << " is inner table" << endl; else if (curr->straight) - cout << "straight_join" << endl; + cerr << "straight_join" << endl; else - cout << "join" << endl; + cerr << "join" << endl; if (curr->nested_join) { @@ -5822,7 +5870,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i for (TABLE_LIST** tb = inner; tb < end1; tb++) { TABLE_LIST* curr1 = *tb; - cout << curr1->alias << endl; + cerr << curr1->alias << endl; if (curr1->sj_on_expr) { @@ -5897,7 +5945,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.clauseType = SELECT; #ifdef DEBUG_WALK_COND { - cout << "------------------- SELECT --------------------" << endl; + cerr << "------------------- SELECT --------------------" << endl; List_iterator_fast it(select_lex.item_list); Item* item; @@ -5906,7 +5954,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i debug_walk(item, 0); } - cout << "-----------------------------------------------\n" << endl; + cerr << "-----------------------------------------------\n" << endl; } #endif @@ -6364,7 +6412,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i } #ifdef DEBUG_WALK_COND - cout << "SELECT clause SUBSELECT Item: " << sub->substype() << endl; + cerr << "SELECT clause SUBSELECT Item: " << sub->substype() << endl; JOIN* join = sub->get_select_lex()->join; if (join) @@ -6375,7 +6423,7 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i cond->traverse_cond(debug_walk, &gwi, Item::POSTFIX); } - cout << "Finish SELECT clause subselect item traversing" << endl; + cerr << "Finish SELECT clause subselect item traversing" << endl; #endif SelectSubQuery* selectSub = new SelectSubQuery(gwi, sub); //selectSub->gwip(&gwi); @@ -6494,9 +6542,9 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i { Item_cond* having = reinterpret_cast(select_lex.having); #ifdef DEBUG_WALK_COND - cout << "------------------- HAVING ---------------------" << endl; + cerr << "------------------- HAVING ---------------------" << endl; having->traverse_cond(debug_walk, &gwi, Item::POSTFIX); - cout << "------------------------------------------------\n" << endl; + cerr << "------------------------------------------------\n" << endl; #endif having->traverse_cond(gp_walk, &gwi, Item::POSTFIX); @@ -7836,6 +7884,10 @@ int cp_get_plan(THD* thd, SCSEP& csep) else if (status < 0) return status; + cerr << "---------------- cp_get_plan EXECUTION PLAN ----------------" << endl; + cerr << *csep << endl ; + cerr << "-------------- EXECUTION PLAN END --------------\n" << endl; + // Derived table projection and filter optimization. derivedTableOptimization(csep); @@ -7937,4 +7989,1949 @@ int cp_get_table_plan(THD* thd, SCSEP& csep, cal_table_info& ti) return 0; } + +int cp_get_group_plan(THD* thd, SCSEP& csep, cal_impl_if::cal_group_info& gi) +{ + LEX* lex = thd->lex; + idbassert(lex != 0); + + SELECT_LEX select_lex = lex->select_lex; + gp_walk_info gwi; + gwi.thd = thd; + int status = getGroupPlan(gwi, select_lex, csep, gi); + + if (status > 0) + return ER_INTERNAL_ERROR; + else if (status < 0) + return status; + + return 0; +} + +/*@brief buildConstColFromFilter- change SimpleColumn into ConstColumn*/ +/*********************************************************** + * DESCRIPTION: + * Server could optimize out fields from GROUP BY list, when certain + * filter predicate is used, e.g. + * field = 'AIR', field IN ('AIR'). This utility function tries to + * replace such fields with ConstantColumns using cond_pushed filters. + * PARAMETERS: + * originalSC SimpleColumn* removed field + * gwi main strucutre + * gi auxilary group_by handler structure + * RETURNS + * ConstantColumn* if originalSC equals with cond_pushed columns. + * NULL otherwise + ***********************************************************/ +ConstantColumn* buildConstColFromFilter(SimpleColumn* originalSC, +gp_walk_info& gwi, cal_group_info& gi) +{ + execplan::SimpleColumn* simpleCol; + execplan::ConstantColumn* constCol; + execplan::SOP op; + execplan::SimpleFilter* simpFilter; + execplan::ConstantColumn* result = NULL; + std::vector::iterator ptIt = gi.pushedPts.begin(); + for(; ptIt != gi.pushedPts.end(); ptIt++) + { + simpFilter = dynamic_cast((*ptIt)->data()); + if (simpFilter == NULL) + continue; + simpleCol = dynamic_cast(simpFilter->lhs()); + constCol = dynamic_cast(simpFilter->rhs()); + if(simpleCol == NULL || constCol == NULL) + continue; + op = simpFilter->op(); + if ( originalSC->sameColumn(dynamic_cast(simpleCol)) + && op.get()->op() == OP_EQ && constCol) + { +#ifdef DEBUG_WALK_COND + cerr << "buildConstColFromFilter() replaced " << endl; + cerr << simpleCol->toString() << endl; + cerr << " with " << endl; + cerr << constCol << endl; +#endif + result = constCol; + } + } + return result; +} + +int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, cal_group_info& gi, bool isUnion) +{ +#ifdef DEBUG_WALK_COND + cerr << "getGroupPlan()" << endl; +#endif + + // rollup is currently not supported + if (select_lex.olap == ROLLUP_TYPE) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_ROLLUP_NOT_SUPPORT); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + gwi.internalDecimalScale = (gwi.thd->variables.infinidb_use_decimal_scale ? gwi.thd->variables.infinidb_decimal_scale : -1); + gwi.subSelectType = csep->subType(); + + JOIN* join = select_lex.join; + Item_cond* icp = 0; + + if ( gi.groupByWhere ) + icp = reinterpret_cast(gi.groupByWhere); + + uint32_t sessionID = csep->sessionID(); + gwi.sessionid = sessionID; + boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); + csc->identity(CalpontSystemCatalog::FE); + gwi.csc = csc; + + // @bug 2123. Override large table estimate if infinidb_ordered hint was used. + // @bug 2404. Always override if the infinidb_ordered_only variable is turned on. + if (gwi.thd->infinidb_vtable.override_largeside_estimate || gwi.thd->variables.infinidb_ordered_only) + csep->overrideLargeSideEstimate(true); + + // @bug 5741. Set a flag when in Local PM only query mode + csep->localQuery(gwi.thd->variables.infinidb_local_query); + + // @bug 3321. Set max number of blocks in a dictionary file to be scanned for filtering + csep->stringScanThreshold(gwi.thd->variables.infinidb_string_scan_threshold); + + csep->stringTableThreshold(gwi.thd->variables.infinidb_stringtable_threshold); + + csep->djsSmallSideLimit(gwi.thd->variables.infinidb_diskjoin_smallsidelimit * 1024ULL * 1024); + csep->djsLargeSideLimit(gwi.thd->variables.infinidb_diskjoin_largesidelimit * 1024ULL * 1024); + csep->djsPartitionSize(gwi.thd->variables.infinidb_diskjoin_bucketsize * 1024ULL * 1024); + + if (gwi.thd->variables.infinidb_um_mem_limit == 0) + csep->umMemLimit(numeric_limits::max()); + else + csep->umMemLimit(gwi.thd->variables.infinidb_um_mem_limit * 1024ULL * 1024); + + // populate table map and trigger syscolumn cache for all the tables (@bug 1637). + // all tables on FROM list must have at least one col in colmap + TABLE_LIST* table_ptr = gi.groupByTables; + CalpontSelectExecutionPlan::SelectList derivedTbList; + +// DEBUG +#ifdef DEBUG_WALK_COND + List_iterator sj_list_it(select_lex.sj_nests); + TABLE_LIST* sj_nest; + + while ((sj_nest = sj_list_it++)) + { + cerr << sj_nest->db << "." << sj_nest->table_name << endl; + } + +#endif + + // @bug 1796. Remember table order on the FROM list. + gwi.clauseType = FROM; + + try + { + for (; table_ptr; table_ptr = table_ptr->next_local) + { + // mysql put vtable here for from sub. we ignore it + //if (string(table_ptr->table_name).find("$vtable") != string::npos) + // continue; + + // Until we handle recursive cte: + // Checking here ensures we catch all with clauses in the query. + if (table_ptr->is_recursive_with_table()) + { + gwi.fatalParseError = true; + gwi.parseErrorText = "Recursive CTE"; + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + string viewName = getViewName(table_ptr); + + // @todo process from subquery + if (table_ptr->derived) + { + String str; + (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_INFINIDB_DERIVED); + + SELECT_LEX* select_cursor = table_ptr->derived->first_select(); + FromSubQuery fromSub(gwi, select_cursor); + string alias(table_ptr->alias); + fromSub.alias(lower(alias)); + + CalpontSystemCatalog::TableAliasName tn = make_aliasview("", "", alias, viewName); + // @bug 3852. check return execplan + SCSEP plan = fromSub.transform(); + + if (!plan) + { + setError(gwi.thd, ER_INTERNAL_ERROR, fromSub.gwip().parseErrorText, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + gwi.derivedTbList.push_back(plan); + gwi.tbList.push_back(tn); + CalpontSystemCatalog::TableAliasName tan = make_aliastable("", alias, alias); + gwi.tableMap[tan] = make_pair(0, table_ptr); +// gwi.thd->infinidb_vtable.isUnion = true; //by-pass the 2nd pass of rnd_init + } + else if (table_ptr->view) + { + View* view = new View(table_ptr->view->select_lex, &gwi); + CalpontSystemCatalog::TableAliasName tn = make_aliastable(table_ptr->db, table_ptr->table_name, table_ptr->alias); + view->viewName(tn); + gwi.viewList.push_back(view); + view->transform(); + } + else + { + // check foreign engine tables + bool infiniDB = (table_ptr->table ? isInfiniDB(table_ptr->table) : true); + + // trigger system catalog cache + if (infiniDB) + csc->columnRIDs(make_table(table_ptr->db, table_ptr->table_name), true); + + string table_name = table_ptr->table_name; + + // @bug5523 + if (table_ptr->db && strcmp(table_ptr->db, "information_schema") == 0) + table_name = (table_ptr->schema_table_name ? table_ptr->schema_table_name : table_ptr->alias); + + CalpontSystemCatalog::TableAliasName tn = make_aliasview(table_ptr->db, table_name, table_ptr->alias, viewName, infiniDB); + gwi.tbList.push_back(tn); + CalpontSystemCatalog::TableAliasName tan = make_aliastable(table_ptr->db, table_name, table_ptr->alias, infiniDB); + gwi.tableMap[tan] = make_pair(0, table_ptr); +#ifdef DEBUG_WALK_COND + cerr << tn << endl; +#endif + } + } + + if (gwi.fatalParseError) + { + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_INTERNAL_ERROR; + } + } + catch (IDBExcept& ie) + { + setError(gwi.thd, ER_INTERNAL_ERROR, ie.what(), gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + // @bug 3852. set error status for gwi. + gwi.fatalParseError = true; + gwi.parseErrorText = ie.what(); + return ER_INTERNAL_ERROR; + } + catch (...) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); + // @bug3852 set error status for gwi. + gwi.fatalParseError = true; + gwi.parseErrorText = emsg; + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + csep->tableList(gwi.tbList); + + bool unionSel = false; + + gwi.clauseType = WHERE; + + + if (icp) + { + // MCOL-1052 The condition could be useless. + // MariaDB bug 624 - without the fix_fields call, delete with join may error with "No query step". + //#if MYSQL_VERSION_ID < 50172 + //@bug 3039. fix fields for constants + if (!icp->fixed) + { + icp->fix_fields(gwi.thd, (Item**)&icp); + } + +//#endif + gwi.fatalParseError = false; +#ifdef DEBUG_WALK_COND + cerr << "------------------ WHERE -----------------------" << endl; + icp->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + cerr << "------------------------------------------------\n" << endl; +#endif + + icp->traverse_cond(gp_walk, &gwi, Item::POSTFIX); + + if (gwi.fatalParseError) + { + // if this is dervied table process phase, mysql may have not developed the plan + // completely. Do not error and eventually mysql will call JOIN::exec() again. + // related to bug 2922. Need to find a way to skip calling rnd_init for derived table + // processing. + if (gwi.thd->derived_tables_processing) + { + gwi.thd->infinidb_vtable.isUnion = false; + gwi.thd->infinidb_vtable.isUpdateWithDerive = true; + return -1; + } + + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_INTERNAL_ERROR; + } + } + else if (join && join->zero_result_cause) + { + gwi.rcWorkStack.push(new ConstantColumn((int64_t)0, ConstantColumn::NUM)); + } + + uint32_t failed = buildOuterJoin(gwi, select_lex); + + if (failed) return failed; + + // @bug5764. build outer join for view, make sure outerjoin filter is appended + // to the end of the filter list. + for (uint i = 0; i < gwi.viewList.size(); i++) + { + failed = gwi.viewList[i]->processOuterJoin(gwi); + + if (failed) + break; + } + + if (failed != 0) + return failed; + + ParseTree* filters = NULL; + ParseTree* ptp = NULL; + ParseTree* lhs = NULL; + + // @bug 2932. for "select * from region where r_name" case. if icp not null and + // ptWorkStack empty, the item is in rcWorkStack. + // MySQL 5.6 (MariaDB?). when icp is null and zero_result_cause is set, a constant 0 + // is pushed to rcWorkStack. + if (/*icp && */gwi.ptWorkStack.empty() && !gwi.rcWorkStack.empty()) + { + filters = new ParseTree(gwi.rcWorkStack.top()); + gwi.rcWorkStack.pop(); + } + + while (!gwi.ptWorkStack.empty()) + { + filters = gwi.ptWorkStack.top(); + gwi.ptWorkStack.pop(); + + if (gwi.ptWorkStack.empty()) + break; + + ptp = new ParseTree(new LogicOperator("and")); + //ptp->left(filters); + ptp->right(filters); + lhs = gwi.ptWorkStack.top(); + gwi.ptWorkStack.pop(); + //ptp->right(rhs); + ptp->left(lhs); + gwi.ptWorkStack.push(ptp); + } + + if (filters) + { + csep->filters(filters); +#ifdef DEBUG_WALK_COND + filters->drawTree("/tmp/filter1.dot"); +#endif + } + + gwi.clauseType = SELECT; +#ifdef DEBUG_WALK_COND + { + cerr << "------------------- SELECT --------------------" << endl; + List_iterator_fast it(*gi.groupByFields); + Item* item; + + while ((item = it++)) + { + debug_walk(item, 0); + } + + cerr << "-----------------------------------------------\n" << endl; + } +#endif + + // populate returnedcolumnlist and columnmap + List_iterator_fast it(*gi.groupByFields); + Item* item; + vector funcFieldVec; + string sel_cols_in_create; + string sel_cols_in_select; + bool redo = false; + + // empty rcWorkStack and ptWorkStack. They should all be empty by now. + clearStacks(gwi); + + // indicate the starting pos of scalar returned column, because some join column + // has been inserted to the returned column list. + if (gwi.subQuery) + { + ScalarSub* scalar = dynamic_cast(gwi.subQuery); + + if (scalar) + scalar->returnedColPos(gwi.additionalRetCols.size()); + } + + CalpontSelectExecutionPlan::SelectList selectSubList; + + while ((item = it++)) + { + string itemAlias = (item->name ? item->name : ""); + + // @bug 5916. Need to keep checking until getting concret item in case + // of nested view. + while (item->type() == Item::REF_ITEM) + { + Item_ref* ref = (Item_ref*)item; + item = (*(ref->ref)); + } + + Item::Type itype = item->type(); + + switch (itype) + { + case Item::FIELD_ITEM: + { + Item_field* ifp = (Item_field*)item; + SimpleColumn* sc = NULL; + ConstantColumn* constCol = NULL; + + if (ifp->field_name && string(ifp->field_name) == "*") + { + collectAllCols(gwi, ifp); + break; + } + + sc = buildSimpleColumn(ifp, gwi); + + if (sc) + { + constCol = buildConstColFromFilter(sc, gwi, gi); + boost::shared_ptr spcc(constCol); + boost::shared_ptr spsc(sc); + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + string fullname; + String str; + ifp->print(&str, QT_INFINIDB_NO_QUOTE); + fullname = str.c_ptr(); + + //sel_cols_in_create += fullname; + if (ifp->is_autogenerated_name) // no alias + { + sel_cols_in_create += fullname + " `" + escapeBackTick(str.c_ptr()) + "`"; + sc->alias(fullname); + } + else // alias + { + if (!itemAlias.empty()) + sc->alias(itemAlias); + + sel_cols_in_create += fullname + " `" + escapeBackTick(sc->alias().c_str()) + "`"; + } + + if (ifp->is_autogenerated_name) + gwi.selectCols.push_back("`" + escapeBackTick(fullname.c_str()) + "`" + " `" + + escapeBackTick(itemAlias.empty() ? ifp->name : itemAlias.c_str()) + "`"); + else + gwi.selectCols.push_back("`" + escapeBackTick((itemAlias.empty() ? ifp->name : itemAlias.c_str())) + "`"); + + // MCOL-1052 Replace SimpleColumn with ConstantColumn, + // since it must have a single value only. + if(constCol) + { + gwi.returnedCols.push_back(spcc); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), spcc)); + } + else + { + gwi.returnedCols.push_back(spsc); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), spsc)); + } + TABLE_LIST* tmp = 0; + + if (ifp->cached_table) + tmp = ifp->cached_table; + + gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = + make_pair(1, tmp); + } + else + { + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + delete sc; + return ER_INTERNAL_ERROR; + } + + break; + } + + //aggregate column + case Item::SUM_FUNC_ITEM: + { + ReturnedColumn* ac = buildAggregateColumn(item, gwi); + + if (gwi.fatalParseError) + { + // e.g., non-support ref column + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + delete ac; + return ER_CHECK_NOT_IMPLEMENTED; + } + + // add this agg col to returnedColumnList + boost::shared_ptr spac(ac); + gwi.returnedCols.push_back(spac); + // This item will be used in HAVING later. + Item_func_or_sum* isfp = reinterpret_cast(item); + if ( ! isfp->name_length ) + { + gwi.havingAggColsItems.push_back(item); + } + + gwi.selectCols.push_back('`' + escapeBackTick(spac->alias().c_str()) + '`'); + String str(256); + item->print(&str, QT_INFINIDB_NO_QUOTE); + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + sel_cols_in_create += string(str.c_ptr()) + " `" + escapeBackTick(spac->alias().c_str()) + "`"; + break; + } + + case Item::FUNC_ITEM: + { + Item_func* ifp = reinterpret_cast(item); + + // @bug4383. error out non-support stored function + if (ifp->functype() == Item_func::FUNC_SP) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_SP_FUNCTION_NOT_SUPPORT); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + if (string(ifp->func_name()) == "xor") + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + uint16_t parseInfo = 0; + vector tmpVec; + bool hasNonSupportItem = false; + parse_item(ifp, tmpVec, hasNonSupportItem, parseInfo); + + if (ifp->has_subquery() || + string(ifp->func_name()) == string("") || + ifp->functype() == Item_func::NOT_ALL_FUNC || + parseInfo & SUB_BIT) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SELECT_SUB); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + ReturnedColumn* rc = buildFunctionColumn(ifp, gwi, hasNonSupportItem); + SRCP srcp(rc); + + if (rc) + { + if (!hasNonSupportItem && !nonConstFunc(ifp) && !(parseInfo & AF_BIT) && tmpVec.size() == 0) + { + if (isUnion || unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT || + parseInfo & SUB_BIT ) //|| select_lex.group_list.elements != 0) + { + srcp.reset(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (ifp->name) + srcp->alias(ifp->name); + + continue; + } + + if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || + ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || + ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || + ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) ) + { } + else + { + redo = true; + String str; + ifp->print(&str, QT_INFINIDB_NO_QUOTE); + gwi.selectCols.push_back(string(str.c_ptr()) + " " + "`" + escapeBackTick(item->name) + "`"); + } + + break; + } + + //SRCP srcp(rc); + gwi.returnedCols.push_back(srcp); + + if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI )) + { } + else + { + String str(256); + ifp->print(&str, QT_INFINIDB_NO_QUOTE); + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + sel_cols_in_create += string(str.c_ptr()) + " `" + ifp->name + "`"; + gwi.selectCols.push_back("`" + escapeBackTick(ifp->name) + "`"); + } + } + else // InfiniDB Non support functions still go through post process for now + { + hasNonSupportItem = false; + uint32_t before_size = funcFieldVec.size(); + parse_item(ifp, funcFieldVec, hasNonSupportItem, parseInfo); + uint32_t after_size = funcFieldVec.size(); + + // group by func and func in subquery can not be post processed + // @bug3881. set_user_var can not be treated as constant function + // @bug5716. Try to avoid post process function for union query. + if ((gwi.subQuery /*|| select_lex.group_list.elements != 0 */ || + !csep->unionVec().empty() || isUnion) && + !hasNonSupportItem && (after_size - before_size) == 0 && + !(parseInfo & AGG_BIT) && !(parseInfo & SUB_BIT) && + string(ifp->func_name()) != "set_user_var") + { + String val, *str = ifp->val_str(&val); + string valStr; + + if (str) + valStr.assign(str->ptr(), str->length()); + + ConstantColumn* cc = NULL; + + if (!str) + { + cc = new ConstantColumn("", ConstantColumn::NULLDATA); + } + else if (ifp->result_type() == STRING_RESULT) + { + cc = new ConstantColumn(valStr, ConstantColumn::LITERAL); + } + else if (ifp->result_type() == DECIMAL_RESULT) + { + cc = buildDecimalColumn(ifp, gwi); + } + else + { + cc = new ConstantColumn(valStr, ConstantColumn::NUM); + cc->resultType(colType_MysqlToIDB(item)); + } + + SRCP srcp(cc); + + if (ifp->name) + cc->alias(ifp->name); + + gwi.returnedCols.push_back(srcp); + + // clear the error set by buildFunctionColumn + gwi.fatalParseError = false; + gwi.parseErrorText = ""; + break; + } + else if (hasNonSupportItem || parseInfo & AGG_BIT || parseInfo & SUB_BIT || + (gwi.fatalParseError && gwi.subQuery)) + { + if (gwi.parseErrorText.empty()) + { + Message::Args args; + args.add(ifp->func_name()); + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORTED_FUNCTION, args); + } + + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + else if ( gwi.subQuery && (isPredicateFunction(ifp, &gwi) || ifp->type() == Item::COND_ITEM )) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + //@Bug 3030 Add error check for dml statement + if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) ) + { + if ( after_size - before_size != 0 ) + { + gwi.parseErrorText = ifp->func_name(); + return -1; + } + } + + //@Bug 3021. Bypass postprocess for update and delete. + //if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI )) + //{} + else + { + // @bug 3881. Here is the real redo part. + redo = true; + // @bug 1706 + String funcStr; + ifp->print(&funcStr, QT_INFINIDB); + gwi.selectCols.push_back(string(funcStr.c_ptr()) + " `" + escapeBackTick(ifp->name) + "`"); + // clear the error set by buildFunctionColumn + gwi.fatalParseError = false; + gwi.parseErrorText = ""; + } + } + + break; + } + + case Item::INT_ITEM: + { + if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI )) + { } + else + { + // do not push the dummy column (mysql added) to returnedCol + if (item->name && string(item->name) == "Not_used") + continue; + + // @bug3509. Constant column is sent to ExeMgr now. + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + + if (item->name) + srcp->alias(item->name); + + gwi.returnedCols.push_back(srcp); + + Item_int* isp = reinterpret_cast(item); + ostringstream oss; + oss << isp->value << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + sel_cols_in_create += oss.str(); + gwi.selectCols.push_back(oss.str()); + } + + break; + } + + case Item::STRING_ITEM: + { + if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI )) + { } + else + { + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (item->name) + srcp->alias(item->name); + + Item_string* isp = reinterpret_cast(item); + String val, *str = isp->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + string name = "'" + valStr + "'" + " " + "`" + escapeBackTick(srcp->alias().c_str()) + "`"; + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + sel_cols_in_create += name; + gwi.selectCols.push_back(name); + } + + break; + } + + case Item::DECIMAL_ITEM: + { + if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI )) + { } + else + { + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (item->name) + srcp->alias(item->name); + + Item_decimal* isp = reinterpret_cast(item); + String val, *str = isp->val_str(&val); + string valStr; + valStr.assign(str->ptr(), str->length()); + ostringstream oss; + oss << valStr.c_str() << " `" << escapeBackTick(srcp->alias().c_str()) << "`"; + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + sel_cols_in_create += oss.str(); + gwi.selectCols.push_back(oss.str()); + } + + break; + } + + case Item::NULL_ITEM: + { + /*if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ) || ((gwi.thd->lex)->sql_command == SQLCOM_DELETE_MULTI ) ) + { } + else + { + SRCP srcp(buildReturnedColumn(item, gwi, gwi.fatalParseError)); + gwi.returnedCols.push_back(srcp); + + if (item->name) + srcp->alias(item->name); + + string name = string("null `") + escapeBackTick(srcp->alias().c_str()) + string("`") ; + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + sel_cols_in_create += name; + gwi.selectCols.push_back("null"); + }*/ + + break; + } + + case Item::SUBSELECT_ITEM: + { + Item_subselect* sub = (Item_subselect*)item; + + if (sub->substype() != Item_subselect::SINGLEROW_SUBS) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SELECT_SUB); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + +#ifdef DEBUG_WALK_COND + cerr << "SELECT clause SUBSELECT Item: " << sub->substype() << endl; + JOIN* join = sub->get_select_lex()->join; + + if (join) + { + Item_cond* cond = reinterpret_cast(join->conds); + + if (cond) + cond->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + } + + cerr << "Finish SELECT clause subselect item traversing" << endl; +#endif + SelectSubQuery* selectSub = new SelectSubQuery(gwi, sub); + //selectSub->gwip(&gwi); + SCSEP ssub = selectSub->transform(); + + if (!ssub || gwi.fatalParseError) + { + if (gwi.parseErrorText.empty()) + gwi.parseErrorText = "Unsupported Item in SELECT subquery."; + + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + selectSubList.push_back(ssub); + SimpleColumn* rc = new SimpleColumn(); + rc->colSource(rc->colSource() | SELECT_SUB); + + if (sub->get_select_lex()->get_table_list()) + rc->viewName(lower(getViewName(sub->get_select_lex()->get_table_list()))); + + if (sub->name) + rc->alias(sub->name); + + gwi.returnedCols.push_back(SRCP(rc)); + String str; + sub->get_select_lex()->print(gwi.thd, &str, QT_INFINIDB_NO_QUOTE); + sel_cols_in_create += "(" + string(str.c_ptr()) + ")"; + + if (sub->name) + { + sel_cols_in_create += "`" + escapeBackTick(sub->name) + "`"; + gwi.selectCols.push_back(sub->name); + } + else + { + sel_cols_in_create += "`" + escapeBackTick(str.c_ptr()) + "`"; + gwi.selectCols.push_back("`" + escapeBackTick(str.c_ptr()) + "`"); + } + + break; + } + + case Item::COND_ITEM: + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + case Item::EXPR_CACHE_ITEM: + { + printf("EXPR_CACHE_ITEM in getSelectPlan\n"); + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_UNKNOWN_COL); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + case Item::WINDOW_FUNC_ITEM: + { + SRCP srcp(buildWindowFunctionColumn(item, gwi, gwi.fatalParseError)); + + if (!srcp || gwi.fatalParseError) + { + if (gwi.parseErrorText.empty()) + gwi.parseErrorText = "Unsupported Item in SELECT subquery."; + + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + gwi.returnedCols.push_back(srcp); + break; + } + + default: + { + break; + } + } + } + + // @bug4388 normalize the project coltypes for union main select list + if (!csep->unionVec().empty()) + { + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) + { + vector coltypes; + + for (uint32_t j = 0; j < csep->unionVec().size(); j++) + { + coltypes.push_back( + dynamic_cast(csep->unionVec()[j].get())->returnedCols()[i]->resultType()); + + // @bug5976. set hasAggregate true for the main column if + // one corresponding union column has aggregate + if (dynamic_cast(csep->unionVec()[j].get())->returnedCols()[i]->hasAggregate()) + gwi.returnedCols[i]->hasAggregate(true); + } + + gwi.returnedCols[i]->resultType(dataconvert::DataConvert::convertUnionColType(coltypes)); + } + } + + // Having clause handling + gwi.clauseType = HAVING; + clearStacks(gwi); + ParseTree* havingFilter = 0; + // clear fatalParseError that may be left from post process functions + gwi.fatalParseError = false; + gwi.parseErrorText = ""; + + if (gi.groupByHaving != 0) + { + Item_cond* having = reinterpret_cast(gi.groupByHaving); +#ifdef DEBUG_WALK_COND + cerr << "------------------- HAVING ---------------------" << endl; + having->traverse_cond(debug_walk, &gwi, Item::POSTFIX); + cerr << "------------------------------------------------\n" << endl; +#endif + having->traverse_cond(gp_walk, &gwi, Item::POSTFIX); + + if (gwi.fatalParseError) + { + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_INTERNAL_ERROR; + } + + ParseTree* ptp = 0; + ParseTree* rhs = 0; + + // @bug 4215. some function filter will be in the rcWorkStack. + if (gwi.ptWorkStack.empty() && !gwi.rcWorkStack.empty()) + { + havingFilter = new ParseTree(gwi.rcWorkStack.top()); + gwi.rcWorkStack.pop(); + } + + while (!gwi.ptWorkStack.empty()) + { + havingFilter = gwi.ptWorkStack.top(); + gwi.ptWorkStack.pop(); + + if (gwi.ptWorkStack.empty()) + break; + + ptp = new ParseTree(new LogicOperator("and")); + ptp->left(havingFilter); + rhs = gwi.ptWorkStack.top(); + gwi.ptWorkStack.pop(); + ptp->right(rhs); + gwi.ptWorkStack.push(ptp); + } + } + + // for post process expressions on the select list + // error out post process for union and sub select unit + if (isUnion || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) + { + if (funcFieldVec.size() != 0 && !gwi.fatalParseError) + { + string emsg("Fatal parse error in vtable mode: Unsupported Items in union or sub select unit"); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg); + return ER_CHECK_NOT_IMPLEMENTED; + } + } + + for (uint32_t i = 0; i < funcFieldVec.size(); i++) + { + SimpleColumn* sc = buildSimpleColumn(funcFieldVec[i], gwi); + + if (!sc || gwi.fatalParseError) + { + string emsg; + + if (gwi.parseErrorText.empty()) + { + emsg = "un-recognized column"; + + if (funcFieldVec[i]->name) + emsg += string(funcFieldVec[i]->name); + } + else + { + emsg = gwi.parseErrorText; + } + + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + return ER_INTERNAL_ERROR; + } + + String str; + funcFieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); + sc->alias(string(str.c_ptr())); + //sc->tableAlias(funcFieldVec[i]->table_name); + sc->tableAlias(sc->tableAlias()); + SRCP srcp(sc); + uint32_t j = 0; + + for (; j < gwi.returnedCols.size(); j++) + { + if (sc->sameColumn(gwi.returnedCols[j].get())) + { + SimpleColumn* field = dynamic_cast(gwi.returnedCols[j].get()); + + if (field && field->alias() == sc->alias()) + break; + } + } + + if (j == gwi.returnedCols.size()) + { + gwi.returnedCols.push_back(srcp); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(funcFieldVec[i]->field_name), srcp)); + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + string fullname; + fullname = str.c_ptr(); + sel_cols_in_create += fullname + " `" + escapeBackTick(fullname.c_str()) + "`"; + TABLE_LIST* tmp = (funcFieldVec[i]->cached_table ? funcFieldVec[i]->cached_table : 0); + gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = + make_pair(1, tmp); + } + } + + // post-process Order by list and expressions on select by redo phase1. only for vtable + // ignore ORDER BY clause for union select unit + string ord_cols = ""; // for normal select phase + SRCP minSc; // min width projected column. for count(*) use + + // Group by list. not valid for union main query + if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE && !unionSel) + { + gwi.clauseType = GROUP_BY; + Item* nonSupportItem = NULL; + ORDER* groupcol = reinterpret_cast(gi.groupByGroup); + + // check if window functions are in order by. InfiniDB process order by list if + // window functions are involved, either in order by or projection. + bool hasWindowFunc = gwi.hasWindowFunc; + gwi.hasWindowFunc = false; + + for (; groupcol; groupcol = groupcol->next) + { + if ((*(groupcol->item))->type() == Item::WINDOW_FUNC_ITEM) + gwi.hasWindowFunc = true; + } + + if (gwi.hasWindowFunc) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_WF_NOT_ALLOWED, "GROUP BY clause"); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + gwi.hasWindowFunc = hasWindowFunc; + groupcol = reinterpret_cast(gi.groupByGroup); + + for (; groupcol; groupcol = groupcol->next) + { + Item* groupItem = *(groupcol->item); + + // @bug5993. Could be nested ref. + while (groupItem->type() == Item::REF_ITEM) + groupItem = (*((Item_ref*)groupItem)->ref); + + if (groupItem->type() == Item::FUNC_ITEM) + { + Item_func* ifp = (Item_func*)groupItem; + + // call buildFunctionColumn here mostly for finding out + // non-support column on GB list. Should be simplified. + ReturnedColumn* fc = buildFunctionColumn(ifp, gwi, gwi.fatalParseError); + + if (!fc || gwi.fatalParseError) + { + nonSupportItem = ifp; + break; + } + + if (groupcol->in_field_list && groupcol->counter_used) + { + delete fc; + fc = gwi.returnedCols[groupcol->counter - 1].get(); + SRCP srcp(fc->clone()); + + // check if no column parm + for (uint32_t i = 0; i < gwi.no_parm_func_list.size(); i++) + { + if (gwi.no_parm_func_list[i]->expressionId() == fc->expressionId()) + { + gwi.no_parm_func_list.push_back(dynamic_cast(srcp.get())); + break; + } + } + + srcp->orderPos(groupcol->counter - 1); + gwi.groupByCols.push_back(srcp); + continue; + } + else if (!groupItem->is_autogenerated_name) // alias + { + uint32_t i = 0; + + for (; i < gwi.returnedCols.size(); i++) + { + if (string(groupItem->name) == gwi.returnedCols[i]->alias()) + { + ReturnedColumn* rc = gwi.returnedCols[i]->clone(); + rc->orderPos(i); + gwi.groupByCols.push_back(SRCP(rc)); + delete fc; + break; + } + } + + if (i == gwi.returnedCols.size()) + { + nonSupportItem = groupItem; + break; + } + } + else + { + uint32_t i = 0; + + for (; i < gwi.returnedCols.size(); i++) + { + if (fc->operator==(gwi.returnedCols[i].get())) + { + ReturnedColumn* rc = gwi.returnedCols[i]->clone(); + rc->orderPos(i); + gwi.groupByCols.push_back(SRCP(rc)); + delete fc; + break; + } + } + + if (i == gwi.returnedCols.size()) + { + gwi.groupByCols.push_back(SRCP(fc)); + break; + } + } + } + else if (groupItem->type() == Item::FIELD_ITEM) + { + Item_field* ifp = (Item_field*)groupItem; + // this GB col could be an alias of F&E on the SELECT clause, not necessarily a field. + ReturnedColumn* rc = buildSimpleColumn(ifp, gwi); + SimpleColumn* sc = dynamic_cast(rc); + + for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) + { + if (sc) + { + if (sc->sameColumn(gwi.returnedCols[j].get())) + { + sc->orderPos(j); + break; + } + else if (strcasecmp(sc->alias().c_str(), gwi.returnedCols[j]->alias().c_str()) == 0) + { + rc = gwi.returnedCols[j].get()->clone(); + rc->orderPos(j); + break; + } + } + else + { + if (ifp->name && string(ifp->name) == gwi.returnedCols[j].get()->alias()) + { + rc = gwi.returnedCols[j].get()->clone(); + rc->orderPos(j); + break; + } + } + } + + if (!rc) + { + nonSupportItem = ifp; + break; + } + + SRCP srcp(rc); + + // bug 3151 + AggregateColumn* ac = dynamic_cast(rc); + + if (ac) + { + nonSupportItem = ifp; + break; + } + + gwi.groupByCols.push_back(srcp); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(ifp->field_name), srcp)); + } + // @bug5638. The group by column is constant but not counter, alias has to match a column + // on the select list + else if (!groupcol->counter_used && + (groupItem->type() == Item::INT_ITEM || + groupItem->type() == Item::STRING_ITEM || + groupItem->type() == Item::REAL_ITEM || + groupItem->type() == Item::DECIMAL_ITEM)) + { + ReturnedColumn* rc = 0; + + for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) + { + if (groupItem->name && string(groupItem->name) == gwi.returnedCols[j].get()->alias()) + { + rc = gwi.returnedCols[j].get()->clone(); + rc->orderPos(j); + break; + } + } + + if (!rc) + { + nonSupportItem = groupItem; + break; + } + + gwi.groupByCols.push_back(SRCP(rc)); + } + else if ((*(groupcol->item))->type() == Item::SUBSELECT_ITEM) + { + if (!groupcol->in_field_list || !groupItem->name) + { + nonSupportItem = groupItem; + } + else + { + uint32_t i = 0; + + for (; i < gwi.returnedCols.size(); i++) + { + if (string(groupItem->name) == gwi.returnedCols[i]->alias()) + { + ReturnedColumn* rc = gwi.returnedCols[i]->clone(); + rc->orderPos(i); + gwi.groupByCols.push_back(SRCP(rc)); + break; + } + } + + if (i == gwi.returnedCols.size()) + { + nonSupportItem = groupItem; + } + } + } + // @bug 3761. + else if (groupcol->counter_used) + { + if (gwi.returnedCols.size() <= (uint32_t)(groupcol->counter - 1)) + { + nonSupportItem = groupItem; + } + else + { + gwi.groupByCols.push_back(SRCP(gwi.returnedCols[groupcol->counter - 1]->clone())); + } + } + else + { + nonSupportItem = groupItem; + } + + } + + // @bug 4756. Add internal groupby column for correlated join to the groupby list + if (gwi.aggOnSelect && !gwi.subGroupByCols.empty()) + gwi.groupByCols.insert(gwi.groupByCols.end(), gwi.subGroupByCols.begin(), gwi.subGroupByCols.end()); + + // this is window func on SELECT becuase ORDER BY has not been processed + if (!gwi.windowFuncList.empty() && !gwi.subGroupByCols.empty()) + { + for (uint32_t i = 0; i < gwi.windowFuncList.size(); i++) + { + if (gwi.windowFuncList[i]->hasWindowFunc()) + { + vector windowFunctions = gwi.windowFuncList[i]->windowfunctionColumnList(); + + for (uint32_t j = 0; j < windowFunctions.size(); j++) + windowFunctions[j]->addToPartition(gwi.subGroupByCols); + } + } + } + + if (nonSupportItem) + { + Message::Args args; + + if (nonSupportItem->name) + args.add("'" + string(nonSupportItem->name) + "'"); + else + args.add(""); + + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_GROUP_BY, args); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + } // GROUP processing ends here + + + if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) + { + ORDER* ordercol = reinterpret_cast(gi.groupByOrder); + string create_query(gwi.thd->infinidb_vtable.create_vtable_query.c_ptr()); + string select_query(gwi.thd->infinidb_vtable.select_vtable_query.c_ptr()); + string lower_create_query(gwi.thd->infinidb_vtable.create_vtable_query.c_ptr()); + string lower_select_query(gwi.thd->infinidb_vtable.select_vtable_query.c_ptr()); + algorithm::to_lower(lower_create_query); + algorithm::to_lower(lower_select_query); + + + // check if window functions are in order by. InfiniDB process order by list if + // window functions are involved, either in order by or projection. + for (; ordercol; ordercol = ordercol->next) + { + if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM) + gwi.hasWindowFunc = true; + } + + // re-visit the first of ordercol list + ordercol = reinterpret_cast(gi.groupByOrder); + + // for subquery, order+limit by will be supported in infinidb. build order by columns + // @todo union order by and limit support + //if (gwi.hasWindowFunc || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) + + for (; ordercol; ordercol = ordercol->next) + { + ReturnedColumn* rc = NULL; + + if (ordercol->in_field_list && ordercol->counter_used) + { + rc = gwi.returnedCols[ordercol->counter - 1]->clone(); + rc->orderPos(ordercol->counter - 1); + // can not be optimized off if used in order by with counter. + // set with self derived table alias if it's derived table + gwi.returnedCols[ordercol->counter - 1]->incRefCount(); + } + else + { + Item* ord_item = *(ordercol->item); + + // ignore not_used column on order by. + if (ord_item->type() == Item::INT_ITEM && ord_item->full_name() && string(ord_item->full_name()) == "Not_used") + continue; + else if (ord_item->type() == Item::INT_ITEM) + rc = gwi.returnedCols[((Item_int*)ord_item)->val_int() - 1]->clone(); + else if (ord_item->type() == Item::SUBSELECT_ITEM) + gwi.fatalParseError = true; + else + rc = buildReturnedColumn(ord_item, gwi, gwi.fatalParseError); + + // Looking for a match for this item in GROUP BY list. + if ( rc && ord_item->type() == Item::FIELD_ITEM ) + { + execplan::CalpontSelectExecutionPlan::ReturnedColumnList::iterator iter = gwi.groupByCols.begin(); + for( ; iter != gwi.groupByCols.end(); iter++ ) + { + if( rc->sameColumn((*iter).get()) ) + break; + } + + // MCOL-1052 Find and remove the optimized field + // from ORDER using cond_pushed filters. + if(buildConstColFromFilter( + dynamic_cast(rc),gwi, gi)) + { + break; + } + // MCOL-1052 GROUP BY items list doesn't contain + // this ORDER BY item. + if ( iter == gwi.groupByCols.end() ) + { + Item_ident *iip = reinterpret_cast(ord_item); + std::ostringstream ostream; + ostream << "'"; + if (iip->db_name) + ostream << iip->db_name << '.'; + else + ostream << "unknown db" << '.'; + if (iip->table_name) + ostream << iip->table_name << '.'; + else + ostream << "unknown table" << '.'; + if (iip->field_name) + ostream << iip->field_name; + else + ostream << "unknown field"; + ostream << "'"; + Message::Args args; + args.add(ostream.str()); + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NOT_GROUPBY_EXPRESSION, args); + gwi.parseErrorText = emsg; + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + return ERR_NOT_GROUPBY_EXPRESSION; + } + } + + // @bug5501 try item_ptr if item can not be fixed. For some + // weird dml statement state, item can not be fixed but the + // infomation is available in item_ptr. + if (!rc || gwi.fatalParseError) + { + gwi.fatalParseError = false; + Item* item_ptr = ordercol->item_ptr; + + while (item_ptr->type() == Item::REF_ITEM) + item_ptr = *(((Item_ref*)item_ptr)->ref); + + rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError); + } + + // This ORDER BY item must be an agg function - + // the ordercol->item_ptr and exteded SELECT list + // must contain the corresponding item. + if (!rc) + { + Item* item_ptr = ordercol->item_ptr; + if (item_ptr) + rc = buildReturnedColumn(item_ptr, gwi, gwi.fatalParseError); + } + + if (!rc) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + gwi.parseErrorText = emsg; + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + } + + if (ordercol->direction == ORDER::ORDER_ASC) + rc->asc(true); + else + rc->asc(false); + + gwi.orderByCols.push_back(SRCP(rc)); + } + + + // make sure columnmap, returnedcols and count(*) arg_list are not empty + TableMap::iterator tb_iter = gwi.tableMap.begin(); + + try + { + for (; tb_iter != gwi.tableMap.end(); tb_iter++) + { + if ((*tb_iter).second.first == 1) continue; + + CalpontSystemCatalog::TableAliasName tan = (*tb_iter).first; + CalpontSystemCatalog::TableName tn = make_table((*tb_iter).first.schema, (*tb_iter).first.table); + SimpleColumn* sc = getSmallestColumn(csc, tn, tan, (*tb_iter).second.second->table, gwi); + SRCP srcp(sc); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); + (*tb_iter).second.first = 1; + } + } + catch (runtime_error& e) + { + setError(gwi.thd, ER_INTERNAL_ERROR, e.what(), gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + catch (...) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + if (!gwi.count_asterisk_list.empty() || !gwi.no_parm_func_list.empty() || + gwi.returnedCols.empty()) + { + // get the smallest column from colmap + CalpontSelectExecutionPlan::ColumnMap::const_iterator iter; + int minColWidth = 0; + CalpontSystemCatalog::ColType ct; + + try + { + for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter) + { + // should always not null + SimpleColumn* sc = dynamic_cast(iter->second.get()); + + if (sc && !(sc->joinInfo() & JOIN_CORRELATED)) + { + ct = csc->colType(sc->oid()); + + if (minColWidth == 0) + { + minColWidth = ct.colWidth; + minSc = iter->second; + } + else if (ct.colWidth < minColWidth) + { + minColWidth = ct.colWidth; + minSc = iter->second; + } + } + } + } + catch (...) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); + setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + return ER_INTERNAL_ERROR; + } + + if (gwi.returnedCols.empty() && gwi.additionalRetCols.empty()) + gwi.returnedCols.push_back(minSc); + } + + if (!isUnion && !gwi.hasWindowFunc && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT) + { + std::ostringstream vtb; + vtb << "infinidb_vtable.$vtable_" << gwi.thd->thread_id; + + //vtb << "$vtable_" << gwi.thd->thread_id; + // re-construct the select query and redo phase 1 + if (redo) + { + // select now() from region case. returnedCols should have minSc. + if (sel_cols_in_create.length() == 0) + { + SimpleColumn* sc = dynamic_cast(gwi.returnedCols[0].get()); + + if (sc) + sel_cols_in_create = dynamic_cast(gwi.returnedCols[0].get())->columnName(); + else + sel_cols_in_create = gwi.returnedCols[0]->alias(); + } + + // select * from derived table case + if (gwi.selectCols.empty()) + sel_cols_in_create = " * "; + + create_query = "create temporary table " + vtb.str() + " engine = aria as select " + sel_cols_in_create + " from "; + TABLE_LIST* table_ptr = gi.groupByTables; + + bool firstTb = true; + + // put all tables, derived tables and views on the list + //TABLE_LIST* table_ptr = select_lex.get_table_list(); + set aliasSet; // to avoid duplicate table alias + + for (; table_ptr; table_ptr = table_ptr->next_local) + { + if (string(table_ptr->table_name).find("$vtable") != string::npos) + continue; + + if (table_ptr->derived) + { + if (aliasSet.find(table_ptr->alias) != aliasSet.end()) + continue; + + String str; + (table_ptr->derived->first_select())->print(gwi.thd, &str, QT_INFINIDB_DERIVED); + + if (!firstTb) + create_query += ", "; + + create_query += "(" + string(str.c_ptr()) + ") " + string(table_ptr->alias); + firstTb = false; + aliasSet.insert(table_ptr->alias); + } + else if (table_ptr->view) + { + if (aliasSet.find(table_ptr->alias) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + + string(" `") + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(table_ptr->alias); + firstTb = false; + } + else + { + // table referenced by view is represented by viewAlias_tableAlias. + // consistent with item.cc field print. + if (table_ptr->referencing_view) + { + if (aliasSet.find(string(table_ptr->referencing_view->alias) + "_" + + string(table_ptr->alias)) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); + create_query += string(" `") + + escapeBackTick(table_ptr->referencing_view->alias) + "_" + + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(string(table_ptr->referencing_view->alias) + "_" + + string(table_ptr->alias)); + } + else + { + if (aliasSet.find(table_ptr->alias) != aliasSet.end()) + continue; + + if (!firstTb) + create_query += ", "; + + create_query += string(table_ptr->db) + "." + string(table_ptr->table_name) + string(" "); + create_query += string("`") + escapeBackTick(table_ptr->alias) + string("`"); + aliasSet.insert(table_ptr->alias); + } + + firstTb = false; + } + } + + + gwi.thd->infinidb_vtable.create_vtable_query.free(); + gwi.thd->infinidb_vtable.create_vtable_query.append(create_query.c_str(), create_query.length()); + gwi.thd->infinidb_vtable.vtable_state = THD::INFINIDB_REDO_PHASE1; // redo phase 1 + + // turn off select distinct from post process unless there're post process functions + // on the select list. + string sel_query = "select "; + + if (gi.groupByDistinct && redo) + sel_query = "select distinct "; + else + sel_query = "select "; + + // select * from derived table... + if (gwi.selectCols.size() == 0) + sel_query += " * "; + + for (uint32_t i = 0; i < gwi.selectCols.size(); i++) + { + sel_query += gwi.selectCols[i]; + + if ( i + 1 != gwi.selectCols.size()) + sel_query += ", "; + } + + select_query.replace(lower_select_query.find("select *"), string("select *").length(), sel_query); + } + else + { + // remove order by clause in case this phase has been executed before. + // need a better fix later, like skip all the other non-optimized phase. + size_t pos = lower_select_query.find("order by"); + + if (pos != string::npos) + select_query.replace(pos, lower_select_query.length() - pos, ""); + + //select_query = "select * from " + vtb.str(); + // MCOL-1052 + if (unionSel) + { + ordercol = reinterpret_cast(gi.groupByOrder); + //order_list = gi.groupByOrder; + } + else + ordercol = 0; + + ord_cols = ""; + + for (; ordercol; ordercol = ordercol->next) + { + Item* ord_item = *(ordercol->item); + + // @bug 1706. re-construct the order by item one by one, because the ord_cols constucted so far + // is for REDO phase. + if (ord_cols.length() != 0) + ord_cols += ", "; + + if (ordercol->in_field_list && ordercol->counter_used) + { + ostringstream oss; + oss << ordercol->counter; + ord_cols += oss.str(); + } + else if (ord_item->type() == Item::NULL_ITEM) + { + // MCOL-793 Do nothing for an ORDER BY NULL + } + else if (ord_item->type() == Item::SUM_FUNC_ITEM) + { + Item_sum* ifp = (Item_sum*)(*(ordercol->item)); + ReturnedColumn* fc = buildAggregateColumn(ifp, gwi); + + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) + { + if (fc->operator==(gwi.returnedCols[i].get())) + { + ostringstream oss; + oss << i + 1; + ord_cols += oss.str(); + break; + } + } + + //continue; + } + // @bug 3518. if order by clause = selected column, use position. + else if (ord_item->name && ord_item->type() == Item::FIELD_ITEM) + { + Item_field* field = reinterpret_cast(ord_item); + string fullname; + + if (field->db_name) + fullname += string(field->db_name) + "."; + + if (field->table_name) + fullname += string(field->table_name) + "."; + + if (field->field_name) + fullname += string(field->field_name); + + uint32_t i = 0; + + for (i = 0; i < gwi.returnedCols.size(); i++) + { + SimpleColumn* sc = dynamic_cast(gwi.returnedCols[i].get()); + + if (sc && ((Item_field*)ord_item)->cached_table && + (strcasecmp(getViewName(((Item_field*)ord_item)->cached_table).c_str(), sc->viewName().c_str()) != 0)) + continue; + + if (strcasecmp(fullname.c_str(), gwi.returnedCols[i]->alias().c_str()) == 0 || + strcasecmp(ord_item->name, gwi.returnedCols[i]->alias().c_str()) == 0) + { + ostringstream oss; + oss << i + 1; + ord_cols += oss.str(); + break; + } + } + + if (i == gwi.returnedCols.size()) + ord_cols += string(" `") + escapeBackTick(ord_item->name) + '`'; + } + + else if (ord_item->name) + { + // for union order by 1 case. For unknown reason, it doesn't show in_field_list + if (ord_item->type() == Item::INT_ITEM) + { + ord_cols += ord_item->name; + } + else if (ord_item->type() == Item::SUBSELECT_ITEM) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + else + { + ord_cols += string(" `") + escapeBackTick(ord_item->name) + '`'; + } + } + else if (ord_item->type() == Item::FUNC_ITEM) + { + // @bug5636. check if this order by column is on the select list + ReturnedColumn* rc = buildFunctionColumn((Item_func*)(ord_item), gwi, gwi.fatalParseError); + + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) + { + if (rc && rc->operator==(gwi.returnedCols[i].get())) + { + ostringstream oss; + oss << i + 1; + ord_cols += oss.str(); + break; + } + } + } + else + { + String str; + ord_item->print(&str, QT_INFINIDB_NO_QUOTE); + ord_cols += string(str.c_ptr()); + } + + if (ordercol->direction != ORDER::ORDER_ASC) + ord_cols += " desc"; + } + } + + if (ord_cols.length() > 0) // has order by + { + gwi.thd->infinidb_vtable.has_order_by = true; + csep->hasOrderBy(true); + ord_cols = " order by " + ord_cols; + select_query += ord_cols; + } + } + } // ORDER BY processing ends here + + if ( gi.groupByDistinct ) + csep->distinct(true); + + // add the smallest column to count(*) parm. + // select constant in subquery case + std::vector::iterator coliter; + + if (!minSc) + { + if (!gwi.returnedCols.empty()) + minSc = gwi.returnedCols[0]; + else if (!gwi.additionalRetCols.empty()) + minSc = gwi.additionalRetCols[0]; + } + + // @bug3523, count(*) on subquery always pick column[0]. + SimpleColumn* sc = dynamic_cast(minSc.get()); + + if (sc && sc->schemaName().empty()) + { + if (gwi.derivedTbList.size() >= 1) + { + SimpleColumn* sc1 = new SimpleColumn(); + sc1->columnName(sc->columnName()); + sc1->tableName(sc->tableName()); + sc1->tableAlias(sc->tableAlias()); + sc1->viewName(lower(sc->viewName())); + sc1->colPosition(0); + minSc.reset(sc1); + } + } + + for (coliter = gwi.count_asterisk_list.begin(); coliter != gwi.count_asterisk_list.end(); ++coliter) + { + // @bug5977 @note should never throw this, but checking just in case. + // When ExeMgr fix is ready, this should not error out... + if (dynamic_cast(minSc.get())) + { + gwi.fatalParseError = true; + gwi.parseErrorText = "No project column found for aggregate function"; + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + (*coliter)->functionParms(minSc); + } + + std::vector::iterator funciter; + + SPTP sptp(new ParseTree(minSc.get()->clone())); + + for (funciter = gwi.no_parm_func_list.begin(); funciter != gwi.no_parm_func_list.end(); ++funciter) + { + FunctionParm funcParms = (*funciter)->functionParms(); + funcParms.push_back(sptp); + (*funciter)->functionParms(funcParms); + } + + // set sequence# for subquery localCols + for (uint32_t i = 0; i < gwi.localCols.size(); i++) + gwi.localCols[i]->sequence(i); + + // append additionalRetCols to returnedCols + gwi.returnedCols.insert(gwi.returnedCols.begin(), gwi.additionalRetCols.begin(), + gwi.additionalRetCols.end()); + + csep->groupByCols(gwi.groupByCols); + csep->orderByCols(gwi.orderByCols); + csep->returnedCols(gwi.returnedCols); + csep->columnMap(gwi.columnMap); + csep->having(havingFilter); + csep->derivedTableList(gwi.derivedTbList); + csep->selectSubList(selectSubList); + csep->subSelectList(gwi.subselectList); + gwi.thd->infinidb_vtable.duplicate_field_name = false; + clearStacks(gwi); + return 0; +} + + } diff --git a/dbcon/mysql/ha_calpont_impl.cpp b/dbcon/mysql/ha_calpont_impl.cpp index e59f7c7d5..12fa74fa5 100644 --- a/dbcon/mysql/ha_calpont_impl.cpp +++ b/dbcon/mysql/ha_calpont_impl.cpp @@ -171,6 +171,7 @@ const unsigned NONSUPPORTED_ERR_THRESH = 2000; vector rmParms; ResourceManager* rm = ResourceManager::instance(); bool useHdfs = rm->useHdfs(); + //convenience fcn inline uint32_t tid2sid(const uint32_t tid) { @@ -275,6 +276,104 @@ void storeNumericField(Field** f, int64_t value, CalpontSystemCatalog::ColType& } } +void storeNumericFieldGroupBy(Field** f, int64_t value, CalpontSystemCatalog::ColType& ct) +{ + // unset null bit first + if ((*f)->null_ptr) + *(*f)->null_ptr &= ~(*f)->null_bit; + + // For unsigned, use the ColType returned in the row rather than the + // unsigned_flag set by mysql. This is because mysql gets it wrong for SUM() + // Hopefully, in all other cases we get it right. + switch ((*f)->type()) + { + case MYSQL_TYPE_NEWDECIMAL: + { + Field_new_decimal* f2 = (Field_new_decimal*)*f; + + // @bug4388 stick to InfiniDB's scale in case mysql gives wrong scale due + // to create vtable limitation. + if (f2->dec < ct.scale) + f2->dec = ct.scale; + + char buf[256]; + dataconvert::DataConvert::decimalToString(value, (unsigned)ct.scale, buf, 256, ct.colDataType); + f2->store(buf, strlen(buf), f2->charset()); + break; + } + + case MYSQL_TYPE_TINY: //TINYINT type + { + Field_tiny* f2 = (Field_tiny*)*f; + longlong int_val = (longlong)value; + f2->store(int_val, f2->unsigned_flag); + break; + } + + case MYSQL_TYPE_SHORT: //SMALLINT type + { + Field_short* f2 = (Field_short*)*f; + longlong int_val = (longlong)value; + f2->store(int_val, f2->unsigned_flag); + break; + } + + case MYSQL_TYPE_LONG: //INT type + { + Field_long* f2 = (Field_long*)*f; + longlong int_val = (longlong)value; + f2->store(int_val, f2->unsigned_flag); + break; + } + + case MYSQL_TYPE_LONGLONG: //BIGINT type + { + Field_longlong* f2 = (Field_longlong*)*f; + longlong int_val = (longlong)value; + f2->store(int_val, f2->unsigned_flag); + break; + } + + case MYSQL_TYPE_FLOAT: // FLOAT type + { + Field_float* f2 = (Field_float*)*f; + float float_val = *(float*)(&value); + f2->store(float_val); + break; + } + + case MYSQL_TYPE_DOUBLE: // DOUBLE type + { + Field_double* f2 = (Field_double*)*f; + double double_val = *(double*)(&value); + f2->store(double_val); + break; + } + + case MYSQL_TYPE_VARCHAR: + { + Field_varstring* f2 = (Field_varstring*)*f; + char tmp[25]; + + if (ct.colDataType == CalpontSystemCatalog::DECIMAL) + dataconvert::DataConvert::decimalToString(value, (unsigned)ct.scale, tmp, 25, ct.colDataType); + else + snprintf(tmp, 25, "%ld", value); + + f2->store(tmp, strlen(tmp), f2->charset()); + break; + } + + default: + { + Field_longlong* f2 = (Field_longlong*)*f; + longlong int_val = (longlong)value; + f2->store(int_val, f2->unsigned_flag); + break; + } + } +} + // // @bug 2244. Log exception related to lost connection to ExeMgr. // Log exception error from calls to sm::tpl_scan_fetch in fetchNextRow() @@ -328,7 +427,7 @@ int vbin2hex(const uint8_t* p, const unsigned l, char* o) return 0; } -int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci) +int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool handler_flag=false) { int rc = HA_ERR_END_OF_FILE; int num_attr = ti.msTablePtr->s->fields; @@ -371,7 +470,12 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci) Field** f; f = ti.msTablePtr->field; //set all fields to null in null col bitmap - memset(buf, -1, ti.msTablePtr->s->null_bytes); + if (!handler_flag) + memset(buf, -1, ti.msTablePtr->s->null_bytes); + else + { + memset(ti.msTablePtr->null_flags, -1, ti.msTablePtr->s->null_bytes); + } std::vector& colTypes = ti.tpl_scan_ctx->ctp; int64_t intColVal = 0; uint64_t uintColVal = 0; @@ -4970,5 +5074,801 @@ int ha_calpont_impl_rnd_pos(uchar* buf, uchar* pos) return ER_INTERNAL_ERROR; } -// vim:sw=4 ts=4: +/*@brief ha_calpont_impl_group_by_init - Get data for MariaDB group_by + pushdown handler */ +/*********************************************************** + * DESCRIPTION: + * Prepares data for group_by_handler::next_row() calls. + * PARAMETERS: + * group_hand - group by handler, that preserves initial table and items lists. . + * table - TABLE pointer The table to save the result set into. + * RETURN: + * 0 if success + * others if something went wrong whilst getting the result set + ***********************************************************/ +int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE* table) +{ + string tableName = group_hand->table_list->table->s->table_name.str; + IDEBUG( cout << "group_by_init for table " << tableName << endl ); + THD* thd = current_thd; + //check whether the system is ready to process statement. +#ifndef _MSC_VER + static DBRM dbrm(true); + bool bSystemQueryReady = dbrm.getSystemQueryReady(); + + if (bSystemQueryReady == 0) + { + // Still not ready + setError(thd, ER_INTERNAL_ERROR, "The system is not yet ready to accept queries"); + thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; + return ER_INTERNAL_ERROR; + } + else if (bSystemQueryReady < 0) + { + // Still not ready + setError(thd, ER_INTERNAL_ERROR, "DBRM is not responding. Cannot accept queries"); + thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; + return ER_INTERNAL_ERROR; + } + +#endif + // prevent "create table as select" from running on slave + thd->infinidb_vtable.hasInfiniDBTable = true; + + // return error if error status has been already set + if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ERROR) + return ER_INTERNAL_ERROR; + + // MCOL-1052 + // by pass the extra union trips. return 0 + //if (thd->infinidb_vtable.isUnion && thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE) + // return 0; + + // @bug 2232. Basic SP support. Error out non support sp cases. + // @bug 3939. Only error out for sp with select. Let pass for alter table in sp. + if (thd->infinidb_vtable.call_sp && (thd->lex)->sql_command != SQLCOM_ALTER_TABLE) + { + setError(thd, ER_CHECK_NOT_IMPLEMENTED, "This stored procedure syntax is not supported by Columnstore in this version"); + thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; + return ER_INTERNAL_ERROR; + } + + uint32_t sessionID = tid2sid(thd->thread_id); + boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); + csc->identity(CalpontSystemCatalog::FE); + + if (!thd->infinidb_vtable.cal_conn_info) + thd->infinidb_vtable.cal_conn_info = (void*)(new cal_connection_info()); + + cal_connection_info* ci = reinterpret_cast(thd->infinidb_vtable.cal_conn_info); + + idbassert(ci != 0); + + + // MySQL sometimes calls rnd_init multiple times, plan should only be + // generated and sent once. + if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE && + !thd->infinidb_vtable.isNewQuery) + return 0; + + if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD) + { + if (ci->cal_conn_hndl) + { + // send ExeMgr a signal before closing the connection + ByteStream msg; + ByteStream::quadbyte qb = 0; + msg << qb; + + try + { + ci->cal_conn_hndl->exeMgr->write(msg); + } + catch (...) + { + // canceling query. ignore connection failure. + } + + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + return 0; + } + + sm::tableid_t tableid = 0; + cal_table_info ti; + cal_group_info gi; + sm::cpsm_conhdl_t* hndl; + SCSEP csep; + + bool localQuery = (thd->variables.infinidb_local_query > 0 ? true : false); + + { + ci->stats.reset(); // reset query stats + ci->stats.setStartTime(); + ci->stats.fUser = thd->main_security_ctx.user; + + if (thd->main_security_ctx.host) + ci->stats.fHost = thd->main_security_ctx.host; + else if (thd->main_security_ctx.host_or_ip) + ci->stats.fHost = thd->main_security_ctx.host_or_ip; + else + ci->stats.fHost = "unknown"; + + try + { + ci->stats.userPriority(ci->stats.fHost, ci->stats.fUser); + } + catch (std::exception& e) + { + string msg = string("Columnstore User Priority - ") + e.what(); + ci->warningMsg = msg; + } + + // if the previous query has error, re-establish the connection + if (ci->queryState != 0) + { + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + sm::sm_init(sessionID, &ci->cal_conn_hndl, localQuery); + idbassert(ci->cal_conn_hndl != 0); + ci->cal_conn_hndl->csc = csc; + idbassert(ci->cal_conn_hndl->exeMgr != 0); + + try + { + ci->cal_conn_hndl->connect(); + } + catch (...) + { + setError(thd, ER_INTERNAL_ERROR, IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR)); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto error; + } + + hndl = ci->cal_conn_hndl; + + if (!csep) + csep.reset(new CalpontSelectExecutionPlan()); + + SessionManager sm; + BRM::TxnID txnID; + txnID = sm.getTxnID(sessionID); + + if (!txnID.valid) + { + txnID.id = 0; + txnID.valid = true; + } + + QueryContext verID; + verID = sm.verID(); + + csep->txnID(txnID.id); + csep->verID(verID); + csep->sessionID(sessionID); + + if (group_hand->table_list->db_length) + csep->schemaName(group_hand->table_list->db); + + csep->traceFlags(ci->traceFlags); + + // MCOL-1052 Send Items lists down to the optimizer. + gi.groupByTables = group_hand->table_list; + gi.groupByFields = group_hand->select; + gi.groupByWhere = group_hand->where; + gi.groupByGroup = group_hand->group_by; + gi.groupByOrder = group_hand->order_by; + gi.groupByHaving = group_hand->having; + gi.groupByDistinct = group_hand->distinct; + + // MCOL-1052 Send pushed conditions here, since server could omit GROUP BY + // items in case of = or IN functions used on GROUP BY columns. + { + CalTableMap::iterator mapiter; + execplan::CalpontSelectExecutionPlan::ColumnMap::iterator colMapIter; + execplan::CalpontSelectExecutionPlan::ColumnMap::iterator condColMapIter; + execplan::ParseTree* ptIt; + execplan::ReturnedColumn* rcIt; + for(TABLE_LIST* tl = gi.groupByTables; tl; tl=tl->next_local) + { + mapiter = ci->tableMap.find(tl->table); + if(mapiter != ci->tableMap.end() && mapiter->second.condInfo != NULL + && mapiter->second.condInfo->condPush) + { + while(!mapiter->second.condInfo->ptWorkStack.empty()) + { + ptIt=mapiter->second.condInfo->ptWorkStack.top(); + mapiter->second.condInfo->ptWorkStack.pop(); + gi.pushedPts.push_back(ptIt); + } + } + } + } + // send plan whenever group_init is called + int status = cp_get_group_plan(thd, csep, gi); + + if (status > 0) + goto internal_error; + else if (status < 0) + return 0; + + // @bug 2547. don't need to send the plan if it's impossible where for all unions. + if (thd->infinidb_vtable.impossibleWhereOnUnion) + return 0; + + string query; + query.assign(thd->infinidb_vtable.original_query.ptr(), + thd->infinidb_vtable.original_query.length()); + csep->data(query); + + try + { + csep->priority( ci->stats.userPriority(ci->stats.fHost, ci->stats.fUser)); + } + catch (std::exception& e) + { + string msg = string("Columnstore User Priority - ") + e.what(); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, msg.c_str()); + } + + #ifdef PLAN_HEX_FILE + // plan serialization + ifstream ifs("/tmp/li1-plan.hex"); + ByteStream bs1; + ifs >> bs1; + ifs.close(); + csep->unserialize(bs1); + #endif + + if (ci->traceFlags & 1) + { + cerr << "---------------- EXECUTION PLAN ----------------" << endl; + cerr << *csep << endl ; + cerr << "-------------- EXECUTION PLAN END --------------\n" << endl; + } + else + { + IDEBUG( cout << "---------------- EXECUTION PLAN ----------------" << endl ); + IDEBUG( cerr << *csep << endl ); + IDEBUG( cout << "-------------- EXECUTION PLAN END --------------\n" << endl ); + } + }// end of execution plan generation + + { + ByteStream msg; + ByteStream emsgBs; + + while (true) + { + try + { + ByteStream::quadbyte qb = 4; + msg << qb; + hndl->exeMgr->write(msg); + msg.restart(); + csep->rmParms(rmParms); + + //send plan + csep->serialize(msg); + hndl->exeMgr->write(msg); + + //get ExeMgr status back to indicate a vtable joblist success or not + msg.restart(); + emsgBs.restart(); + msg = hndl->exeMgr->read(); + emsgBs = hndl->exeMgr->read(); + string emsg; + + if (msg.length() == 0 || emsgBs.length() == 0) + { + emsg = "Lost connection to ExeMgr. Please contact your administrator"; + setError(thd, ER_INTERNAL_ERROR, emsg); + return ER_INTERNAL_ERROR; + } + + string emsgStr; + emsgBs >> emsgStr; + bool err = false; + + if (msg.length() == 4) + { + msg >> qb; + + if (qb != 0) + { + err = true; + // for makejoblist error, stats contains only error code and insert from here + // because table fetch is not started + ci->stats.setEndTime(); + ci->stats.fQuery = csep->data(); + ci->stats.fQueryType = csep->queryType(); + ci->stats.fErrorNo = qb; + + try + { + ci->stats.insert(); + } + catch (std::exception& e) + { + string msg = string("Columnstore Query Stats - ") + e.what(); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, msg.c_str()); + } + } + } + else + { + err = true; + } + + if (err) + { + setError(thd, ER_INTERNAL_ERROR, emsgStr); + return ER_INTERNAL_ERROR; + } + + rmParms.clear(); + + if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) + { + ci->tableMap[table] = ti; + } + else + { + ci->queryState = 1; + } + + break; + } + catch (...) + { + sm::sm_cleanup(hndl); + hndl = 0; + + sm::sm_init(sessionID, &hndl, localQuery); + idbassert(hndl != 0); + hndl->csc = csc; + + if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) + ti.conn_hndl = hndl; + else + ci->cal_conn_hndl = hndl; + + try + { + hndl->connect(); + } + catch (...) + { + setError(thd, ER_INTERNAL_ERROR, IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR)); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto error; + } + + msg.restart(); + } + } + } + + // set query state to be in_process. Sometimes mysql calls rnd_init multiple + // times, this makes sure plan only being generated and sent once. It will be + // reset when query finishes in sm::end_query + thd->infinidb_vtable.isNewQuery = false; + + // common path for both vtable select phase and table mode -- open scan handle + ti = ci->tableMap[table]; + ti.msTablePtr = table; + + // MCOL-1052 + thd->infinidb_vtable.vtable_state = THD::INFINIDB_SELECT_VTABLE; + + if ((thd->infinidb_vtable.vtable_state == THD::INFINIDB_SELECT_VTABLE) || + (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) || + (thd->infinidb_vtable.vtable_state == THD::INFINIDB_REDO_QUERY)) + { + if (ti.tpl_ctx == 0) + { + ti.tpl_ctx = new sm::cpsm_tplh_t(); + ti.tpl_scan_ctx = sm::sp_cpsm_tplsch_t(new sm::cpsm_tplsch_t()); + } + + // make sure rowgroup is null so the new meta data can be taken. This is for some case mysql + // call rnd_init for a table more than once. + ti.tpl_scan_ctx->rowGroup = NULL; + + try + { + tableid = execplan::IDB_VTABLE_ID; + } + catch (...) + { + string emsg = "No table ID found for table " + string(table->s->table_name.str); + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + + try + { + sm::tpl_open(tableid, ti.tpl_ctx, hndl); + sm::tpl_scan_open(tableid, ti.tpl_scan_ctx, hndl); + } + catch (std::exception& e) + { + string emsg = "table can not be opened: " + string(e.what()); + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + catch (...) + { + string emsg = "table can not be opened"; + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + + ti.tpl_scan_ctx->traceFlags = ci->traceFlags; + + if ((ti.tpl_scan_ctx->ctp).size() == 0) + { + uint32_t num_attr = table->s->fields; + + for (uint32_t i = 0; i < num_attr; i++) + { + CalpontSystemCatalog::ColType ctype; + ti.tpl_scan_ctx->ctp.push_back(ctype); + } + + // populate coltypes here for table mode because tableband gives treeoid for dictionary column + if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_DISABLE_VTABLE) + { + CalpontSystemCatalog::RIDList oidlist = csc->columnRIDs(make_table(table->s->db.str, table->s->table_name.str), true); + + if (oidlist.size() != num_attr) + { + string emsg = "Size mismatch probably caused by front end out of sync"; + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(sessionID); + goto internal_error; + } + + for (unsigned int j = 0; j < oidlist.size(); j++) + { + CalpontSystemCatalog::ColType ctype = csc->colType(oidlist[j].objnum); + ti.tpl_scan_ctx->ctp[ctype.colPosition] = ctype; + ti.tpl_scan_ctx->ctp[ctype.colPosition].colPosition = -1; + } + } + } + } + + ci->tableMap[table] = ti; + return 0; + +error: + + if (ci->cal_conn_hndl) + { + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + // do we need to close all connection handle of the table map? + return ER_INTERNAL_ERROR; + +internal_error: + + if (ci->cal_conn_hndl) + { + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + return ER_INTERNAL_ERROR; +} + +/*@brief ha_calpont_impl_group_by_next - Return result set for MariaDB group_by + pushdown handler +*/ +/*********************************************************** + * DESCRIPTION: + * Return a result record for each group_by_handler::next_row() call. + * PARAMETERS: + * group_hand - group by handler, that preserves initial table and items lists. . + * table - TABLE pointer The table to save the result set in. + * RETURN: + * 0 if success + * HA_ERR_END_OF_FILE if the record set has come to an end + * others if something went wrong whilst getting the result set + ***********************************************************/ +int ha_calpont_impl_group_by_next(ha_calpont_group_by_handler* group_hand, TABLE* table) +{ + THD* thd = current_thd; + + /* If this node is the slave, ignore DML to IDB tables */ + if (thd->slave_thread && ( + thd->lex->sql_command == SQLCOM_INSERT || + thd->lex->sql_command == SQLCOM_INSERT_SELECT || + thd->lex->sql_command == SQLCOM_UPDATE || + thd->lex->sql_command == SQLCOM_UPDATE_MULTI || + thd->lex->sql_command == SQLCOM_DELETE || + thd->lex->sql_command == SQLCOM_DELETE_MULTI || + thd->lex->sql_command == SQLCOM_TRUNCATE || + thd->lex->sql_command == SQLCOM_LOAD)) + return 0; + + + if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ERROR) + return ER_INTERNAL_ERROR; + + if (((thd->lex)->sql_command == SQLCOM_UPDATE) || ((thd->lex)->sql_command == SQLCOM_DELETE) || + ((thd->lex)->sql_command == SQLCOM_DELETE_MULTI) || ((thd->lex)->sql_command == SQLCOM_UPDATE_MULTI)) + return HA_ERR_END_OF_FILE; + + // @bug 2547 + if (thd->infinidb_vtable.impossibleWhereOnUnion) + return HA_ERR_END_OF_FILE; + + // @bug 2232. Basic SP support + // @bug 3939. Only error out for sp with select. Let pass for alter table in sp. + /*if (thd->infinidb_vtable.call_sp && (thd->lex)->sql_command != SQLCOM_ALTER_TABLE) + { + setError(thd, ER_CHECK_NOT_IMPLEMENTED, "This stored procedure syntax is not supported by Columnstore in this version"); + thd->infinidb_vtable.vtable_state = THD::INFINIDB_ERROR; + return ER_INTERNAL_ERROR; + } + */ + if (!thd->infinidb_vtable.cal_conn_info) + thd->infinidb_vtable.cal_conn_info = (void*)(new cal_connection_info()); + + cal_connection_info* ci = reinterpret_cast(thd->infinidb_vtable.cal_conn_info); + + // @bug 3078 + if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD) + { + if (ci->cal_conn_hndl) + { + // send ExeMgr a signal before cloing the connection + ByteStream msg; + ByteStream::quadbyte qb = 0; + msg << qb; + + try + { + ci->cal_conn_hndl->exeMgr->write(msg); + } + catch (...) + { + // cancel query. ignore connection failure. + } + + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + } + + return 0; + } + + if (ci->alterTableState > 0) return HA_ERR_END_OF_FILE; + + cal_table_info ti; + ti = ci->tableMap[table]; + int rc = HA_ERR_END_OF_FILE; + + if (!ti.tpl_ctx || !ti.tpl_scan_ctx) + { + CalpontSystemCatalog::removeCalpontSystemCatalog(tid2sid(thd->thread_id)); + return ER_INTERNAL_ERROR; + } + + idbassert(ti.msTablePtr == table); + + try + { + // fetchNextRow interface forces to use buf. + unsigned char buf; + rc = fetchNextRow(&buf, ti, ci, true); + } + catch (std::exception& e) + { + string emsg = string("Error while fetching from ExeMgr: ") + e.what(); + setError(thd, ER_INTERNAL_ERROR, emsg); + CalpontSystemCatalog::removeCalpontSystemCatalog(tid2sid(thd->thread_id)); + return ER_INTERNAL_ERROR; + } + + ci->tableMap[table] = ti; + + if (rc != 0 && rc != HA_ERR_END_OF_FILE) + { + string emsg; + + // remove this check when all error handling migrated to the new framework. + if (rc >= 1000) + emsg = ti.tpl_scan_ctx->errMsg; + else + { + logging::ErrorCodes errorcodes; + emsg = errorcodes.errorString(rc); + } + + setError(thd, ER_INTERNAL_ERROR, emsg); + ci->stats.fErrorNo = rc; + CalpontSystemCatalog::removeCalpontSystemCatalog(tid2sid(thd->thread_id)); + rc = ER_INTERNAL_ERROR; + } + + return rc; +} + +int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* table) +{ + int rc = 0; + THD* thd = current_thd; + cal_connection_info* ci = NULL; + + + if (thd->slave_thread && ( + thd->lex->sql_command == SQLCOM_INSERT || + thd->lex->sql_command == SQLCOM_INSERT_SELECT || + thd->lex->sql_command == SQLCOM_UPDATE || + thd->lex->sql_command == SQLCOM_UPDATE_MULTI || + thd->lex->sql_command == SQLCOM_DELETE || + thd->lex->sql_command == SQLCOM_DELETE_MULTI || + thd->lex->sql_command == SQLCOM_TRUNCATE || + thd->lex->sql_command == SQLCOM_LOAD)) + return 0; + + thd->infinidb_vtable.isNewQuery = true; + thd->infinidb_vtable.isUnion = false; + + if (thd->infinidb_vtable.cal_conn_info) + ci = reinterpret_cast(thd->infinidb_vtable.cal_conn_info); + + // MCOL-1052 + //if (thd->infinidb_vtable.vtable_state == THD::INFINIDB_ORDER_BY ) + //{ + // thd->infinidb_vtable.vtable_state = THD::INFINIDB_SELECT_VTABLE;// flip back to normal state + // return rc; + //} + + if (((thd->lex)->sql_command == SQLCOM_INSERT) || + ((thd->lex)->sql_command == SQLCOM_INSERT_SELECT) ) + { + // @bug 4022. error handling for select part of dml + if (ci->cal_conn_hndl && ci->rc) + { + // send ExeMgr a signal before closing the connection + ByteStream msg; + ByteStream::quadbyte qb = 0; + msg << qb; + + try + { + ci->cal_conn_hndl->exeMgr->write(msg); + } + catch (...) + { + // this is error handling, so ignore connection failure. + } + + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + return rc; + } + } + + if (!ci) + { + thd->infinidb_vtable.cal_conn_info = (void*)(new cal_connection_info()); + ci = reinterpret_cast(thd->infinidb_vtable.cal_conn_info); + } + + // @bug 3078. Also session limit variable works the same as ctrl+c + if (thd->killed == KILL_QUERY || thd->killed == KILL_QUERY_HARD || + ((thd->lex)->sql_command != SQLCOM_INSERT && + (thd->lex)->sql_command != SQLCOM_INSERT_SELECT && + thd->variables.select_limit != (uint64_t) - 1)) + { + if (ci->cal_conn_hndl) + { + // send ExeMgr a signal before closing the connection + ByteStream msg; + ByteStream::quadbyte qb = 0; + msg << qb; + + try + { + ci->cal_conn_hndl->exeMgr->write(msg); + } + catch (...) + { + // this is the end of query. Ignore the exception if exemgr connection failed + // for whatever reason. + } + + sm::sm_cleanup(ci->cal_conn_hndl); + ci->cal_conn_hndl = 0; + // clear querystats because no query stats available for cancelled query + ci->queryStats = ""; + } + + return 0; + } + + IDEBUG( cerr << "group_by_end for table " << table->s->table_name.str << endl ); + + cal_table_info ti = ci->tableMap[table]; + sm::cpsm_conhdl_t* hndl; + + hndl = ci->cal_conn_hndl; + + if (ti.tpl_ctx) + { + if (ti.tpl_scan_ctx.get()) + { + try + { + sm::tpl_scan_close(ti.tpl_scan_ctx); + } + catch (...) + { + rc = ER_INTERNAL_ERROR; + } + } + + ti.tpl_scan_ctx.reset(); + + try + { + sm::tpl_close(ti.tpl_ctx, &hndl, ci->stats); + + ci->cal_conn_hndl = hndl; + + ti.tpl_ctx = 0; + } + catch (IDBExcept& e) + { + if (e.errorCode() == ERR_CROSS_ENGINE_CONNECT || e.errorCode() == ERR_CROSS_ENGINE_CONFIG) + { + string msg = string("Columnstore Query Stats - ") + e.what(); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, msg.c_str()); + } + else + { + setError(thd, ER_INTERNAL_ERROR, e.what()); + rc = ER_INTERNAL_ERROR; + } + } + catch (std::exception& e) + { + setError(thd, ER_INTERNAL_ERROR, e.what()); + rc = ER_INTERNAL_ERROR; + } + catch (...) + { + setError(thd, ER_INTERNAL_ERROR, "Internal error throwed in group_by_end"); + rc = ER_INTERNAL_ERROR; + } + } + + ti.tpl_ctx = 0; + + ci->tableMap[table] = ti; + + // push warnings from CREATE phase + if (!ci->warningMsg.empty()) + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, ci->warningMsg.c_str()); + + ci->warningMsg.clear(); + // reset expressionId just in case + ci->expressionId = 0; + return rc; +} + +// vim:sw=4 ts=4: diff --git a/dbcon/mysql/ha_calpont_impl.h b/dbcon/mysql/ha_calpont_impl.h index 1e7f7d5df..7f7c43aae 100644 --- a/dbcon/mysql/ha_calpont_impl.h +++ b/dbcon/mysql/ha_calpont_impl.h @@ -48,11 +48,16 @@ extern int ha_calpont_impl_external_lock(THD* thd, TABLE* table, int lock_type); extern int ha_calpont_impl_update_row(); extern int ha_calpont_impl_delete_row(); extern int ha_calpont_impl_rnd_pos(uchar* buf, uchar* pos); +extern int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE* table); +extern int ha_calpont_impl_group_by_next(ha_calpont_group_by_handler* group_hand, TABLE* table); +extern int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* table); + #endif #ifdef NEED_CALPONT_INTERFACE #include "ha_calpont_impl_if.h" #include "calpontsystemcatalog.h" +#include "ha_calpont.h" extern int ha_calpont_impl_rename_table_(const char* from, const char* to, cal_impl_if::cal_connection_info& ci); extern int ha_calpont_impl_write_row_(uchar* buf, TABLE* table, cal_impl_if::cal_connection_info& ci, ha_rows& rowsInserted); extern int ha_calpont_impl_write_batch_row_(uchar* buf, TABLE* table, cal_impl_if::cal_connection_info& ci); @@ -69,6 +74,9 @@ extern std::string ha_calpont_impl_droppartition_ (execplan::CalpontSystemCatal extern std::string ha_calpont_impl_viewtablelock( cal_impl_if::cal_connection_info& ci, execplan::CalpontSystemCatalog::TableName& tablename); extern std::string ha_calpont_impl_cleartablelock( cal_impl_if::cal_connection_info& ci, uint64_t tableLockID); +extern int ha_calpont_impl_group_by_init(ha_calpont_group_by_handler* group_hand, TABLE* table); +extern int ha_calpont_impl_group_by_next(ha_calpont_group_by_handler* group_hand, TABLE* table); +extern int ha_calpont_impl_group_by_end(ha_calpont_group_by_handler* group_hand, TABLE* table); #endif #endif diff --git a/dbcon/mysql/ha_calpont_impl_if.h b/dbcon/mysql/ha_calpont_impl_if.h index 709e1b051..b1e5ec443 100644 --- a/dbcon/mysql/ha_calpont_impl_if.h +++ b/dbcon/mysql/ha_calpont_impl_if.h @@ -99,6 +99,7 @@ struct gp_walk_info execplan::CalpontSelectExecutionPlan::ReturnedColumnList groupByCols; execplan::CalpontSelectExecutionPlan::ReturnedColumnList subGroupByCols; execplan::CalpontSelectExecutionPlan::ReturnedColumnList orderByCols; + std::vector havingAggColsItems; execplan::CalpontSelectExecutionPlan::ColumnMap columnMap; // This vector temporarily hold the projection columns to be added // to the returnedCols vector for subquery processing. It will be appended @@ -191,6 +192,28 @@ struct cal_table_info bool moreRows; //are there more rows to consume (b/c of limit) }; +struct cal_group_info +{ + cal_group_info() : groupByFields(0), + groupByTables(0), + groupByWhere(0), + groupByGroup(0), + groupByOrder(0), + groupByHaving(0), + groupByDistinct(false) + { } + ~cal_group_info() { } + + List* groupByFields; // MCOL-1052 SELECT + TABLE_LIST* groupByTables; // MCOL-1052 FROM + Item* groupByWhere; // MCOL-1052 WHERE + ORDER* groupByGroup; // MCOL-1052 GROUP BY + ORDER* groupByOrder; // MCOL-1052 ORDER BY + Item* groupByHaving; // MCOL-1052 HAVING + bool groupByDistinct; //MCOL-1052 DISTINCT + std::vector pushedPts; +}; + typedef std::tr1::unordered_map CalTableMap; typedef std::vector ColValuesList; typedef std::vector ColNameList; @@ -297,7 +320,9 @@ const std::string infinidb_err_msg = "\nThe query includes syntax that is not su int cp_get_plan(THD* thd, execplan::SCSEP& csep); int cp_get_table_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_table_info& ti); +int cp_get_group_plan(THD* thd, execplan::SCSEP& csep, cal_impl_if::cal_group_info& gi); int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, bool isUnion = false); +int getGroupPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, execplan::SCSEP& csep, cal_group_info& gi, bool isUnion = false); void setError(THD* thd, uint32_t errcode, const std::string errmsg, gp_walk_info* gwi); void setError(THD* thd, uint32_t errcode, const std::string errmsg); void gp_walk(const Item* item, void* arg); diff --git a/dbcon/mysql/ha_window_function.cpp b/dbcon/mysql/ha_window_function.cpp index 5724b231c..1635c815a 100644 --- a/dbcon/mysql/ha_window_function.cpp +++ b/dbcon/mysql/ha_window_function.cpp @@ -512,6 +512,18 @@ ReturnedColumn* buildWindowFunctionColumn(Item* item, gp_walk_info& gwi, bool& n { Item* orderItem = *(orderCol->item); srcp.reset(buildReturnedColumn(orderItem, gwi, nonSupport)); + + // MCOL-1052 GROUP BY handler has all of query's agg Items + // as field and correlates them with its extended SELECT Items. + if (!srcp) + { + orderItem = orderCol->item_ptr; + if (orderItem) + { + gwi.fatalParseError = false; + srcp.reset(buildReturnedColumn(orderItem, gwi, nonSupport)); + } + } if (!srcp) return nullOnError(gwi); diff --git a/dbcon/mysql/sm.cpp b/dbcon/mysql/sm.cpp index 569fee6a5..fe1a23e76 100644 --- a/dbcon/mysql/sm.cpp +++ b/dbcon/mysql/sm.cpp @@ -145,7 +145,7 @@ status_t tpl_scan_fetch_getband(cpsm_conhdl_t* hndl, sp_cpsm_tplsch_t& ntplsch, if (ntplsch->bs.length() != 0) { ntplsch->deserializeTable(ntplsch->bs); - + if (ntplsch->rowGroup && ntplsch->rowGroup->getRGData() == NULL) { ntplsch->bs.restart();