diff --git a/dbcon/mysql/ha_calpont_execplan.cpp b/dbcon/mysql/ha_calpont_execplan.cpp index e15a5eb97..fd8ae8922 100644 --- a/dbcon/mysql/ha_calpont_execplan.cpp +++ b/dbcon/mysql/ha_calpont_execplan.cpp @@ -6912,2450 +6912,21 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i algorithm::to_lower(lower_create_query); algorithm::to_lower(lower_select_query); - // Group by list. not valid for union main query - if (gwi.thd->infinidb_vtable.vtable_state == THD::INFINIDB_CREATE_VTABLE && !unionSel) + // 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) { - gwi.clauseType = GROUP_BY; - Item* nonSupportItem = NULL; - ORDER* groupcol = reinterpret_cast(select_lex.group_list.first); - - // 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(order_list.first); - - // 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); - - // @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) - { - 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); - } - - 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)); - } - } - else if (!isUnion) - { - vector fieldVec; - bool addToSel; - - // the following order by is just for redo phase - if (!unionSel) - { - for (; ordercol; ordercol = ordercol->next) - { - Item* ord_item = *(ordercol->item); - - // @bug5993. Could be nested ref. - while (ord_item->type() == Item::REF_ITEM) - ord_item = (*((Item_ref*)ord_item)->ref); - - // @bug 1706. re-construct the order by item one by one - //Item* ord_item = *(ordercol->item); - if (ord_cols.length() != 0) - ord_cols += ", "; - - addToSel = true; - string fullname; - - if (ordercol->in_field_list && ordercol->counter_used) - { - ostringstream oss; - oss << ordercol->counter; - ord_cols += oss.str(); - - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; - - continue; - } - - else if (ord_item->type() == Item::FUNC_ITEM) - { - // @bug 2621. order by alias - if (!ord_item->is_autogenerated_name && ord_item->name) - { - ord_cols += ord_item->name; - continue; - } - - // if there's group by clause or aggregate column, check to see - // if this item or the arguments is on the GB list. - ReturnedColumn* rc = 0; - // check if this order by column is on the select list - Item_func* ifp = (Item_func*)(*(ordercol->item)); - rc = buildFunctionColumn(ifp, gwi, gwi.fatalParseError); - - if (rc) - { - 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(); - addToSel = false; - break; - } - } - } - - if (addToSel) - { - FunctionColumn* fc = dynamic_cast(rc); - - if (fc) - { - addToSel = false; - redo = true; - string ord_func = string(ifp->func_name()) + "("; - - for (uint32_t i = 0; i < fc->functionParms().size(); i++) - { - if (i != 0) - ord_func += ","; - - for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) - { - if (fc->functionParms()[i]->data()->operator==(gwi.returnedCols[j].get())) - { - ord_func += "`" + escapeBackTick(gwi.returnedCols[j]->alias().c_str()) + "`"; - continue; - } - - AggregateColumn* ac = dynamic_cast(fc->functionParms()[i]->data()); - - if (ac) - { - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - addToSel = true; - //continue; - - } - } - - ord_func += ")"; - - if (!addToSel) - ord_cols += ord_func; - } - } - } - 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 if (ord_item->type() == Item::SUM_FUNC_ITEM) - { - ReturnedColumn* ac = 0; - - Item_sum* ifp = (Item_sum*)(*(ordercol->item)); - // @bug3477. add aggregate column to the select list of the create phase. - ac = buildAggregateColumn(ifp, gwi); - - if (!ac) - { - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, - IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY), gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - // check if this order by column is on the select list - for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) - { - AggregateColumn* ret = dynamic_cast(gwi.returnedCols[i].get()); - - if (!ret) - continue; - - if (ac->operator==(gwi.returnedCols[i].get())) - { - ostringstream oss; - oss << i + 1; - ord_cols += oss.str(); - addToSel = false; - break; - } - } - - if (ac || !gwi.groupByCols.empty()) - { - if (addToSel) - { - redo = true; - // @bug 3076. do not add the argument of aggregate function to the SELECT list, - // instead, add the whole column - String str; - ord_item->print(&str, QT_INFINIDB_NO_QUOTE); - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - sel_cols_in_create += str.c_ptr(); - //gwi.selectCols.push_back(" `" + string(str.c_ptr()) + "`"); - SRCP srcp(ac); - gwi.returnedCols.push_back(srcp); - ord_cols += " `" + escapeBackTick(str.c_ptr()) + "`"; - } - - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; - - continue; - } - } - else if (ord_item->name && ord_item->type() == Item::FIELD_ITEM) - { - Item_field* field = reinterpret_cast(ord_item); - ReturnedColumn* rc = buildSimpleColumn(field, gwi); - fullname = field->full_name(); -// 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); - - for (uint32_t 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) - { - ord_cols += string(" `") + escapeBackTick(gwi.returnedCols[i]->alias().c_str()) + '`'; - addToSel = false; - break; - } - - if (sc && sc->sameColumn(rc)) - { - ostringstream oss; - oss << i + 1; - ord_cols += oss.str(); - addToSel = false; - break; - } - } - } - - if (addToSel) - { - // @bug 2719. Error out order by not on the distinct select list. - if (select_lex.options & SELECT_DISTINCT) - { - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_ORDERBY_NOT_IN_DISTINCT); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - bool hasNonSupportItem = false; - uint16_t parseInfo = 0; - parse_item(ord_item, fieldVec, hasNonSupportItem, parseInfo); - - if (hasNonSupportItem) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - String str; - ord_item->print(&str, QT_INFINIDB); - ord_cols += str.c_ptr(); - } - - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; - } - } - - redo = (redo || fieldVec.size() != 0); - - // populate string to be added to the select list for order by - for (uint32_t i = 0; i < fieldVec.size(); i++) - { - SimpleColumn* sc = buildSimpleColumn(fieldVec[i], gwi); - - if (!sc) - { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); - setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } - - String str; - fieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); - sc->alias(string(str.c_ptr())); - 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()) - { - string fullname; - - if (sel_cols_in_create.length() != 0) - sel_cols_in_create += ", "; - - fullname = str.c_ptr(); - sel_cols_in_create += fullname + " `" + escapeBackTick(fullname.c_str()) + "`"; - - gwi.returnedCols.push_back(srcp); - gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(fieldVec[i]->field_name), srcp)); - TABLE_LIST* tmp = (fieldVec[i]->cached_table ? fieldVec[i]->cached_table : 0); - gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = - make_pair(1, tmp); - } - } - } - - // 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 = select_lex.get_table_list(); - - 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_global) - { - 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 (/*join->select_options*/select_lex.options & SELECT_DISTINCT && 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(); - if (unionSel) - order_list = select_lex.master_unit()->global_parameters()->order_list; - - ordercol = reinterpret_cast(order_list.first); - 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; - } - } - - if (unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) - { - if (select_lex.master_unit()->global_parameters()->explicit_limit) - { - if (select_lex.master_unit()->global_parameters()->offset_limit) - { - Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit; - csep->limitStart(offset->val_int()); - } - - if (select_lex.master_unit()->global_parameters()->select_limit) - { - Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit; - csep->limitNum(select->val_int()); - } - - if (unionSel && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT) - { - ostringstream limit; - limit << " limit "; - limit << csep->limitStart() << ", "; - limit << csep->limitNum(); - select_query += limit.str(); - } - } - } - else if (isUnion && select_lex.explicit_limit) - { - if (select_lex.braces) - { - if (select_lex.offset_limit) - csep->limitStart(((Item_int*)select_lex.offset_limit)->val_int()); - - if (select_lex.select_limit) - csep->limitNum(((Item_int*)select_lex.select_limit)->val_int()); - } - } - else if (select_lex.explicit_limit) - { - uint32_t limitOffset = 0; - uint32_t limitNum = std::numeric_limits::max(); - - if (join) - { -#if MYSQL_VERSION_ID >= 50172 - - // @bug5729. After upgrade, join->unit sometimes is uninitialized pointer - // (not null though) and will cause seg fault. Prefer checking - // select_lex->offset_limit if not null. - if (join->select_lex && - join->select_lex->offset_limit && - join->select_lex->offset_limit->fixed && - join->select_lex->select_limit && - join->select_lex->select_limit->fixed) - { - limitOffset = join->select_lex->offset_limit->val_int(); - limitNum = join->select_lex->select_limit->val_int(); - } - - else if (join->unit) - { - limitOffset = join->unit->offset_limit_cnt; - limitNum = join->unit->select_limit_cnt - limitOffset; - } - -#else - limitOffset = (join->unit)->offset_limit_cnt; - limitNum = (join->unit)->select_limit_cnt - (join->unit)->offset_limit_cnt; -#endif - } - else - { - if (select_lex.master_unit()->global_parameters()->offset_limit) - { - Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit; - limitOffset = offset->val_int(); - } - - if (select_lex.master_unit()->global_parameters()->select_limit) - { - Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit; - limitNum = select->val_int(); - } - } - - // relate to bug4848. let mysql drive limit when limit session variable set. - // do not set in csep. @bug5096. ignore session limit setting for dml - if ((gwi.thd->variables.select_limit == (uint64_t) -1 || - (gwi.thd->variables.select_limit != (uint64_t) -1 && - gwi.thd->infinidb_vtable.vtable_state != THD::INFINIDB_CREATE_VTABLE)) && - !csep->hasOrderBy()) - { - csep->limitStart(limitOffset); - csep->limitNum(limitNum); - } - else - { - ostringstream limit; - limit << " limit " << limitOffset << ", " << limitNum; - select_query += limit.str(); - } - } - - gwi.thd->infinidb_vtable.select_vtable_query.free(); - gwi.thd->infinidb_vtable.select_vtable_query.append(select_query.c_str(), select_query.length()); - - // We don't currently support limit with correlated subquery - if (csep->limitNum() != (uint64_t) -1 && - gwi.subQuery && !gwi.correlatedTbNameVec.empty()) - { - gwi.fatalParseError = true; - gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_LIMIT_SUB); - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); - return ER_CHECK_NOT_IMPLEMENTED; - } + if ((*(ordercol->item))->type() == Item::WINDOW_FUNC_ITEM) + gwi.hasWindowFunc = true; } - if (/*join->select_options*/select_lex.options & SELECT_DISTINCT) - csep->distinct(true); + // re-visit the first of ordercol list + ordercol = reinterpret_cast(order_list.first); - // add the smallest column to count(*) parm. - // select constant in subquery case - std::vector::iterator coliter; - - if (!minSc) + // 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) { - 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; - } - - int cp_get_plan(THD * thd, SCSEP & csep) - { - LEX* lex = thd->lex; - idbassert(lex != 0); - - SELECT_LEX select_lex = lex->select_lex; - gp_walk_info gwi; - gwi.thd = thd; - int status = getSelectPlan(gwi, select_lex, csep); - - if (status > 0) - return ER_INTERNAL_ERROR; - else if (status < 0) - return status; - - // Derived table projection and filter optimization. - derivedTableOptimization(csep); - - return 0; - } - - int cp_get_table_plan(THD * thd, SCSEP & csep, cal_table_info & ti) - { - gp_walk_info* gwi = ti.condInfo; - - if (!gwi) - gwi = new gp_walk_info(); - - gwi->thd = thd; - LEX* lex = thd->lex; - idbassert(lex != 0); - uint32_t sessionID = csep->sessionID(); - gwi->sessionid = sessionID; - TABLE* table = ti.msTablePtr; - boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); - csc->identity(CalpontSystemCatalog::FE); - - // get all columns that mysql needs to fetch - MY_BITMAP* read_set = table->read_set; - Field** f_ptr, *field; - gwi->columnMap.clear(); - - for (f_ptr = table->field ; (field = *f_ptr) ; f_ptr++) - { - if (bitmap_is_set(read_set, field->field_index)) - { - SimpleColumn* sc = new SimpleColumn(table->s->db.str, table->s->table_name.str, field->field_name, sessionID); - string alias(table->alias.c_ptr()); - sc->tableAlias(lower(alias)); - assert (sc); - boost::shared_ptr spsc(sc); - gwi->returnedCols.push_back(spsc); - gwi->columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(field->field_name), spsc)); - } - } - - if (gwi->columnMap.empty()) - { - CalpontSystemCatalog::TableName tn = make_table(table->s->db.str, table->s->table_name.str); - CalpontSystemCatalog::TableAliasName tan = make_aliastable(table->s->db.str, table->s->table_name.str, table->alias.c_ptr()); - SimpleColumn* sc = getSmallestColumn(csc, tn, tan, table, *gwi); - SRCP srcp(sc); - gwi->columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); - gwi->returnedCols.push_back(srcp); - } - - // get filter - if (ti.condInfo) - { - gp_walk_info* gwi = ti.condInfo; - ParseTree* filters = 0; - ParseTree* ptp = 0; - ParseTree* rhs = 0; - - while (!gwi->ptWorkStack.empty()) - { - filters = gwi->ptWorkStack.top(); - gwi->ptWorkStack.pop(); - SimpleFilter* sf = dynamic_cast(filters->data()); - - if (sf && sf->op()->data() == "noop") - { - delete filters; - filters = 0; - - if (gwi->ptWorkStack.empty()) - break; - - continue; - } - - if (gwi->ptWorkStack.empty()) - break; - - ptp = new ParseTree(new LogicOperator("and")); - ptp->left(filters); - rhs = gwi->ptWorkStack.top(); - gwi->ptWorkStack.pop(); - ptp->right(rhs); - gwi->ptWorkStack.push(ptp); - } - - csep->filters(filters); - } - - csep->returnedCols(gwi->returnedCols); - csep->columnMap(gwi->columnMap); - CalpontSelectExecutionPlan::TableList tblist; - tblist.push_back(make_aliastable(table->s->db.str, table->s->table_name.str, table->alias.c_ptr())); - csep->tableList(tblist); - - // @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); - - 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; @@ -9382,64 +6953,11 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i 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) @@ -9448,17 +6966,6 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i 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); @@ -9475,31 +6982,370 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i gwi.orderByCols.push_back(SRCP(rc)); } + } + else if (!isUnion) + { + vector fieldVec; + bool addToSel; + // the following order by is just for redo phase + if (!unionSel) + { + for (; ordercol; ordercol = ordercol->next) + { + Item* ord_item = *(ordercol->item); - // make sure columnmap, returnedcols and count(*) arg_list are not empty - TableMap::iterator tb_iter = gwi.tableMap.begin(); + // @bug5993. Could be nested ref. + while (ord_item->type() == Item::REF_ITEM) + ord_item = (*((Item_ref*)ord_item)->ref); + + // @bug 1706. re-construct the order by item one by one + //Item* ord_item = *(ordercol->item); + if (ord_cols.length() != 0) + ord_cols += ", "; + + addToSel = true; + string fullname; + + if (ordercol->in_field_list && ordercol->counter_used) + { + ostringstream oss; + oss << ordercol->counter; + ord_cols += oss.str(); + + if (ordercol->direction != ORDER::ORDER_ASC) + ord_cols += " desc"; + + continue; + } + + else if (ord_item->type() == Item::FUNC_ITEM) + { + // @bug 2621. order by alias + if (!ord_item->is_autogenerated_name && ord_item->name) + { + ord_cols += ord_item->name; + continue; + } + + // if there's group by clause or aggregate column, check to see + // if this item or the arguments is on the GB list. + ReturnedColumn* rc = 0; + // check if this order by column is on the select list + Item_func* ifp = (Item_func*)(*(ordercol->item)); + rc = buildFunctionColumn(ifp, gwi, gwi.fatalParseError); + + if (rc) + { + 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(); + addToSel = false; + break; + } + } + } + + if (addToSel) + { + FunctionColumn* fc = dynamic_cast(rc); + + if (fc) + { + addToSel = false; + redo = true; + string ord_func = string(ifp->func_name()) + "("; + + for (uint32_t i = 0; i < fc->functionParms().size(); i++) + { + if (i != 0) + ord_func += ","; + + for (uint32_t j = 0; j < gwi.returnedCols.size(); j++) + { + if (fc->functionParms()[i]->data()->operator==(gwi.returnedCols[j].get())) + { + ord_func += "`" + escapeBackTick(gwi.returnedCols[j]->alias().c_str()) + "`"; + continue; + } + + AggregateColumn* ac = dynamic_cast(fc->functionParms()[i]->data()); + + if (ac) + { + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + addToSel = true; + //continue; + + } + } + + ord_func += ")"; + + if (!addToSel) + ord_cols += ord_func; + } + } + } + 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 if (ord_item->type() == Item::SUM_FUNC_ITEM) + { + ReturnedColumn* ac = 0; + + Item_sum* ifp = (Item_sum*)(*(ordercol->item)); + // @bug3477. add aggregate column to the select list of the create phase. + ac = buildAggregateColumn(ifp, gwi); + + if (!ac) + { + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, + IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY), gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + // check if this order by column is on the select list + for (uint32_t i = 0; i < gwi.returnedCols.size(); i++) + { + AggregateColumn* ret = dynamic_cast(gwi.returnedCols[i].get()); + + if (!ret) + continue; + + if (ac->operator==(gwi.returnedCols[i].get())) + { + ostringstream oss; + oss << i + 1; + ord_cols += oss.str(); + addToSel = false; + break; + } + } + + if (ac || !gwi.groupByCols.empty()) + { + if (addToSel) + { + redo = true; + // @bug 3076. do not add the argument of aggregate function to the SELECT list, + // instead, add the whole column + String str; + ord_item->print(&str, QT_INFINIDB_NO_QUOTE); + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + sel_cols_in_create += str.c_ptr(); + //gwi.selectCols.push_back(" `" + string(str.c_ptr()) + "`"); + SRCP srcp(ac); + gwi.returnedCols.push_back(srcp); + ord_cols += " `" + escapeBackTick(str.c_ptr()) + "`"; + } + + if (ordercol->direction != ORDER::ORDER_ASC) + ord_cols += " desc"; + + continue; + } + } + else if (ord_item->name && ord_item->type() == Item::FIELD_ITEM) + { + Item_field* field = reinterpret_cast(ord_item); + ReturnedColumn* rc = buildSimpleColumn(field, gwi); + fullname = field->full_name(); +// 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); + + for (uint32_t 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) + { + ord_cols += string(" `") + escapeBackTick(gwi.returnedCols[i]->alias().c_str()) + '`'; + addToSel = false; + break; + } + + if (sc && sc->sameColumn(rc)) + { + ostringstream oss; + oss << i + 1; + ord_cols += oss.str(); + addToSel = false; + break; + } + } + } + + if (addToSel) + { + // @bug 2719. Error out order by not on the distinct select list. + if (select_lex.options & SELECT_DISTINCT) + { + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_ORDERBY_NOT_IN_DISTINCT); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + bool hasNonSupportItem = false; + uint16_t parseInfo = 0; + parse_item(ord_item, fieldVec, hasNonSupportItem, parseInfo); + + if (hasNonSupportItem) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + String str; + ord_item->print(&str, QT_INFINIDB); + ord_cols += str.c_ptr(); + } + + if (ordercol->direction != ORDER::ORDER_ASC) + ord_cols += " desc"; + } + } + + redo = (redo || fieldVec.size() != 0); + + // populate string to be added to the select list for order by + for (uint32_t i = 0; i < fieldVec.size(); i++) + { + SimpleColumn* sc = buildSimpleColumn(fieldVec[i], gwi); + + if (!sc) + { + string emsg = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_ORDER_BY); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, emsg, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + + String str; + fieldVec[i]->print(&str, QT_INFINIDB_NO_QUOTE); + sc->alias(string(str.c_ptr())); + 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()) + { + string fullname; + + if (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; + + fullname = str.c_ptr(); + sel_cols_in_create += fullname + " `" + escapeBackTick(fullname.c_str()) + "`"; + + gwi.returnedCols.push_back(srcp); + gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(fieldVec[i]->field_name), srcp)); + TABLE_LIST* tmp = (fieldVec[i]->cached_table ? fieldVec[i]->cached_table : 0); + gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = + make_pair(1, tmp); + } + } + } + + // 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 (; tb_iter != gwi.tableMap.end(); tb_iter++) + for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter) { - if ((*tb_iter).second.first == 1) continue; + // should always not null + SimpleColumn* sc = dynamic_cast(iter->second.get()); - 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; + 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 (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); @@ -9508,412 +7354,2559 @@ int getSelectPlan(gp_walk_info& gwi, SELECT_LEX& select_lex, SCSEP& csep, bool i return ER_INTERNAL_ERROR; } - if (!gwi.count_asterisk_list.empty() || !gwi.no_parm_func_list.empty() || - gwi.returnedCols.empty()) + 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) { - // get the smallest column from colmap - CalpontSelectExecutionPlan::ColumnMap::const_iterator iter; - int minColWidth = 0; - CalpontSystemCatalog::ColType ct; - - try + // select now() from region case. returnedCols should have minSc. + if (sel_cols_in_create.length() == 0) { - for (iter = gwi.columnMap.begin(); iter != gwi.columnMap.end(); ++iter) + 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 = select_lex.get_table_list(); + + 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_global) + { + if (string(table_ptr->table_name).find("$vtable") != string::npos) + continue; + + if (table_ptr->derived) { - // should always not null - SimpleColumn* sc = dynamic_cast(iter->second.get()); + if (aliasSet.find(table_ptr->alias) != aliasSet.end()) + continue; - if (sc && !(sc->joinInfo() & JOIN_CORRELATED)) + 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) { - ct = csc->colType(sc->oid()); + if (aliasSet.find(string(table_ptr->referencing_view->alias) + "_" + + string(table_ptr->alias)) != aliasSet.end()) + continue; - if (minColWidth == 0) + 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 (/*join->select_options*/select_lex.options & SELECT_DISTINCT && 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(); + if (unionSel) + order_list = select_lex.master_unit()->global_parameters()->order_list; + + ordercol = reinterpret_cast(order_list.first); + 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())) { - minColWidth = ct.colWidth; - minSc = iter->second; + ostringstream oss; + oss << i + 1; + ord_cols += oss.str(); + break; } - else if (ct.colWidth < minColWidth) + } + + //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) { - minColWidth = ct.colWidth; - minSc = iter->second; + 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"; } - catch (...) + } + + 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; + } + } + + if (unionSel || gwi.subSelectType != CalpontSelectExecutionPlan::MAIN_SELECT) + { + if (select_lex.master_unit()->global_parameters()->explicit_limit) + { + if (select_lex.master_unit()->global_parameters()->offset_limit) { - string emsg = IDBErrorInfo::instance()->errorMsg(ERR_LOST_CONN_EXEMGR); - setError(gwi.thd, ER_INTERNAL_ERROR, emsg, gwi); + Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit; + csep->limitStart(offset->val_int()); + } + + if (select_lex.master_unit()->global_parameters()->select_limit) + { + Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit; + csep->limitNum(select->val_int()); + } + + if (unionSel && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT) + { + ostringstream limit; + limit << " limit "; + limit << csep->limitStart() << ", "; + limit << csep->limitNum(); + select_query += limit.str(); + } + } + } + else if (isUnion && select_lex.explicit_limit) + { + if (select_lex.braces) + { + if (select_lex.offset_limit) + csep->limitStart(((Item_int*)select_lex.offset_limit)->val_int()); + + if (select_lex.select_limit) + csep->limitNum(((Item_int*)select_lex.select_limit)->val_int()); + } + } + else if (select_lex.explicit_limit) + { + uint32_t limitOffset = 0; + uint32_t limitNum = std::numeric_limits::max(); + + if (join) + { +#if MYSQL_VERSION_ID >= 50172 + + // @bug5729. After upgrade, join->unit sometimes is uninitialized pointer + // (not null though) and will cause seg fault. Prefer checking + // select_lex->offset_limit if not null. + if (join->select_lex && + join->select_lex->offset_limit && + join->select_lex->offset_limit->fixed && + join->select_lex->select_limit && + join->select_lex->select_limit->fixed) + { + limitOffset = join->select_lex->offset_limit->val_int(); + limitNum = join->select_lex->select_limit->val_int(); + } + + else if (join->unit) + { + limitOffset = join->unit->offset_limit_cnt; + limitNum = join->unit->select_limit_cnt - limitOffset; + } + +#else + limitOffset = (join->unit)->offset_limit_cnt; + limitNum = (join->unit)->select_limit_cnt - (join->unit)->offset_limit_cnt; +#endif + } + else + { + if (select_lex.master_unit()->global_parameters()->offset_limit) + { + Item_int* offset = (Item_int*)select_lex.master_unit()->global_parameters()->offset_limit; + limitOffset = offset->val_int(); + } + + if (select_lex.master_unit()->global_parameters()->select_limit) + { + Item_int* select = (Item_int*)select_lex.master_unit()->global_parameters()->select_limit; + limitNum = select->val_int(); + } + } + + // relate to bug4848. let mysql drive limit when limit session variable set. + // do not set in csep. @bug5096. ignore session limit setting for dml + if ((gwi.thd->variables.select_limit == (uint64_t) -1 || + (gwi.thd->variables.select_limit != (uint64_t) -1 && + gwi.thd->infinidb_vtable.vtable_state != THD::INFINIDB_CREATE_VTABLE)) && + !csep->hasOrderBy()) + { + csep->limitStart(limitOffset); + csep->limitNum(limitNum); + } + else + { + ostringstream limit; + limit << " limit " << limitOffset << ", " << limitNum; + select_query += limit.str(); + } + } + + gwi.thd->infinidb_vtable.select_vtable_query.free(); + gwi.thd->infinidb_vtable.select_vtable_query.append(select_query.c_str(), select_query.length()); + + // We don't currently support limit with correlated subquery + if (csep->limitNum() != (uint64_t) -1 && + gwi.subQuery && !gwi.correlatedTbNameVec.empty()) + { + gwi.fatalParseError = true; + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_LIMIT_SUB); + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + return ER_CHECK_NOT_IMPLEMENTED; + } + } + + if (/*join->select_options*/select_lex.options & SELECT_DISTINCT) + 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; +} + +int cp_get_plan(THD* thd, SCSEP& csep) +{ + LEX* lex = thd->lex; + idbassert(lex != 0); + + SELECT_LEX select_lex = lex->select_lex; + gp_walk_info gwi; + gwi.thd = thd; + int status = getSelectPlan(gwi, select_lex, csep); + + if (status > 0) + return ER_INTERNAL_ERROR; + else if (status < 0) + return status; + + // Derived table projection and filter optimization. + derivedTableOptimization(csep); + + return 0; +} + +int cp_get_table_plan(THD* thd, SCSEP& csep, cal_table_info& ti) +{ + gp_walk_info* gwi = ti.condInfo; + + if (!gwi) + gwi = new gp_walk_info(); + + gwi->thd = thd; + LEX* lex = thd->lex; + idbassert(lex != 0); + uint32_t sessionID = csep->sessionID(); + gwi->sessionid = sessionID; + TABLE* table = ti.msTablePtr; + boost::shared_ptr csc = CalpontSystemCatalog::makeCalpontSystemCatalog(sessionID); + csc->identity(CalpontSystemCatalog::FE); + + // get all columns that mysql needs to fetch + MY_BITMAP* read_set = table->read_set; + Field** f_ptr, *field; + gwi->columnMap.clear(); + + for (f_ptr = table->field ; (field = *f_ptr) ; f_ptr++) + { + if (bitmap_is_set(read_set, field->field_index)) + { + SimpleColumn* sc = new SimpleColumn(table->s->db.str, table->s->table_name.str, field->field_name, sessionID); + string alias(table->alias.c_ptr()); + sc->tableAlias(lower(alias)); + assert (sc); + boost::shared_ptr spsc(sc); + gwi->returnedCols.push_back(spsc); + gwi->columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(string(field->field_name), spsc)); + } + } + + if (gwi->columnMap.empty()) + { + CalpontSystemCatalog::TableName tn = make_table(table->s->db.str, table->s->table_name.str); + CalpontSystemCatalog::TableAliasName tan = make_aliastable(table->s->db.str, table->s->table_name.str, table->alias.c_ptr()); + SimpleColumn* sc = getSmallestColumn(csc, tn, tan, table, *gwi); + SRCP srcp(sc); + gwi->columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); + gwi->returnedCols.push_back(srcp); + } + + // get filter + if (ti.condInfo) + { + gp_walk_info* gwi = ti.condInfo; + ParseTree* filters = 0; + ParseTree* ptp = 0; + ParseTree* rhs = 0; + + while (!gwi->ptWorkStack.empty()) + { + filters = gwi->ptWorkStack.top(); + gwi->ptWorkStack.pop(); + SimpleFilter* sf = dynamic_cast(filters->data()); + + if (sf && sf->op()->data() == "noop") + { + delete filters; + filters = 0; + + if (gwi->ptWorkStack.empty()) + break; + + continue; + } + + if (gwi->ptWorkStack.empty()) + break; + + ptp = new ParseTree(new LogicOperator("and")); + ptp->left(filters); + rhs = gwi->ptWorkStack.top(); + gwi->ptWorkStack.pop(); + ptp->right(rhs); + gwi->ptWorkStack.push(ptp); + } + + csep->filters(filters); + } + + csep->returnedCols(gwi->returnedCols); + csep->columnMap(gwi->columnMap); + CalpontSelectExecutionPlan::TableList tblist; + tblist.push_back(make_aliastable(table->s->db.str, table->s->table_name.str, table->alias.c_ptr())); + csep->tableList(tblist); + + // @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); + + 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; } - if (gwi.returnedCols.empty() && gwi.additionalRetCols.empty()) - gwi.returnedCols.push_back(minSc); + 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; } - if (!isUnion && !gwi.hasWindowFunc && gwi.subSelectType == CalpontSelectExecutionPlan::MAIN_SELECT) + 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: { - std::ostringstream vtb; - vtb << "infinidb_vtable.$vtable_" << gwi.thd->thread_id; + Item_field* ifp = (Item_field*)item; + SimpleColumn* sc = NULL; + ConstantColumn* constCol = NULL; - //vtb << "$vtable_" << gwi.thd->thread_id; - // re-construct the select query and redo phase 1 - if (redo) + if (ifp->field_name && string(ifp->field_name) == "*") { - // select now() from region case. returnedCols should have minSc. - if (sel_cols_in_create.length() == 0) - { - SimpleColumn* sc = dynamic_cast(gwi.returnedCols[0].get()); + collectAllCols(gwi, ifp); + break; + } - if (sc) - sel_cols_in_create = dynamic_cast(gwi.returnedCols[0].get())->columnName(); - else - sel_cols_in_create = gwi.returnedCols[0]->alias(); + 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()) + "`"; } - // 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 "; + if (ifp->is_autogenerated_name) + gwi.selectCols.push_back("`" + escapeBackTick(fullname.c_str()) + "`" + " `" + + escapeBackTick(itemAlias.empty() ? ifp->name : itemAlias.c_str()) + "`"); else - sel_query = "select "; + gwi.selectCols.push_back("`" + escapeBackTick((itemAlias.empty() ? ifp->name : itemAlias.c_str())) + "`"); - // select * from derived table... - if (gwi.selectCols.size() == 0) - sel_query += " * "; - - for (uint32_t i = 0; i < gwi.selectCols.size(); i++) + // MCOL-1052 Replace SimpleColumn with ConstantColumn, + // since it must have a single value only. + if (constCol) { - sel_query += gwi.selectCols[i]; - - if ( i + 1 != gwi.selectCols.size()) - sel_query += ", "; + 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)); } - select_query.replace(lower_select_query.find("select *"), string("select *").length(), sel_query); + 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 { - // 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"); + setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + delete sc; + return ER_INTERNAL_ERROR; + } - if (pos != string::npos) - select_query.replace(pos, lower_select_query.length() - pos, ""); + break; + } - //select_query = "select * from " + vtb.str(); - // MCOL-1052 - if (unionSel) + //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) { - ordercol = reinterpret_cast(gi.groupByOrder); - //order_list = gi.groupByOrder; + 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 - ordercol = 0; - - ord_cols = ""; - - for (; ordercol; ordercol = ordercol->next) { - Item* ord_item = *(ordercol->item); + String str(256); + ifp->print(&str, QT_INFINIDB_NO_QUOTE); - // @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 (sel_cols_in_create.length() != 0) + sel_cols_in_create += ", "; - if (ordercol->in_field_list && ordercol->counter_used) + 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) { - ostringstream oss; - oss << ordercol->counter; - ord_cols += oss.str(); + cc = new ConstantColumn("", ConstantColumn::NULLDATA); } - else if (ord_item->type() == Item::NULL_ITEM) + else if (ifp->result_type() == STRING_RESULT) { - // MCOL-793 Do nothing for an ORDER BY NULL + cc = new ConstantColumn(valStr, ConstantColumn::LITERAL); } - else if (ord_item->type() == Item::SUM_FUNC_ITEM) + else if (ifp->result_type() == DECIMAL_RESULT) { - 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; - } - } + cc = buildDecimalColumn(ifp, gwi); } else { - String str; - ord_item->print(&str, QT_INFINIDB_NO_QUOTE); - ord_cols += string(str.c_ptr()); + cc = new ConstantColumn(valStr, ConstantColumn::NUM); + cc->resultType(colType_MysqlToIDB(item)); } - if (ordercol->direction != ORDER::ORDER_ASC) - ord_cols += " desc"; + 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 = ""; } } - 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; - } + break; } - } // 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) + case Item::INT_ITEM: { - 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); - } - } + 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; - 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())) + // @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 = "No project column found for aggregate function"; - setError(gwi.thd, ER_INTERNAL_ERROR, gwi.parseErrorText, gwi); + gwi.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_FILTER_COND_EXP); + setError(gwi.thd, ER_CHECK_NOT_IMPLEMENTED, gwi.parseErrorText, gwi); return ER_CHECK_NOT_IMPLEMENTED; } - (*coliter)->functionParms(minSc); + 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; + } } - - 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; } + // @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; +} + }