execplan::ReturnedColumn* buildPseudoColumn(Item* item, gp_walk_info& gwi, bool& nonSupport, uint32_t pseudoType) { Item_func* ifp = (Item_func*)item; // idblocalpm is replaced by constant if (pseudoType == PSEUDO_LOCALPM) { int64_t localPm = idblocalpm(); ConstantColumn* cc; if (localPm) cc = new ConstantColumn(localPm); else cc = new ConstantColumn("", ConstantColumn::NULLDATA); cc->alias(ifp->name? ifp->name : ""); return cc; } // convert udf item to pseudocolumn item. // adjust result type // put arg col to column map string funcName = ifp->func_name(); if (ifp->arg_count != 1 || !(ifp->arguments()) || !(ifp->arguments()[0]) || ifp->arguments()[0]->type() != Item::FIELD_ITEM) return nullOnError(gwi, funcName); Item_field* field = (Item_field*)(ifp->arguments()[0]); // @todo rule out derive table if (!field->field || !field->db_name || strlen(field->db_name) == 0) return nullOnError(gwi, funcName); SimpleColumn *sc = buildSimpleColumn(field, gwi); if (!sc) return nullOnError(gwi, funcName); if ((pseudoType == PSEUDO_EXTENTMIN || pseudoType == PSEUDO_EXTENTMAX) && (sc->colType().colDataType == CalpontSystemCatalog::VARBINARY || (sc->colType().colDataType == CalpontSystemCatalog::VARCHAR && sc->colType().colWidth > 7) || (sc->colType().colDataType == CalpontSystemCatalog::CHAR && sc->colType().colWidth > 8))) return nullOnError(gwi, funcName); // put arg col to column map if (gwi.clauseType == SELECT || gwi.clauseType == GROUP_BY) // select clause { SRCP srcp(sc); gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp)); gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isInfiniDB())] = make_pair(1, field->cached_table); } else if (!gwi.rcWorkStack.empty()) { gwi.rcWorkStack.pop(); } if (pseudoType == PSEUDO_PARTITION) { // parms: psueducolumn dbroot, segmentdir, segment SPTP sptp; FunctionColumn *fc = new FunctionColumn(funcName); funcexp::FunctionParm parms; PseudoColumn *dbroot = new PseudoColumn(*sc, PSEUDO_DBROOT); sptp.reset(new ParseTree(dbroot)); parms.push_back(sptp); PseudoColumn *pp = new PseudoColumn(*sc, PSEUDO_SEGMENTDIR); sptp.reset(new ParseTree(pp)); parms.push_back(sptp); PseudoColumn* seg = new PseudoColumn(*sc, PSEUDO_SEGMENT); sptp.reset(new ParseTree(seg)); parms.push_back(sptp); fc->functionParms(parms); fc->expressionId(gwi.expressionId++); // string result type CalpontSystemCatalog::ColType ct; ct.colDataType = CalpontSystemCatalog::VARCHAR; ct.colWidth = 256; fc->resultType(ct); // operation type integer funcexp::Func_idbpartition* idbpartition = new funcexp::Func_idbpartition(); fc->operationType(idbpartition->operationType(parms, fc->resultType())); fc->alias(ifp->name? ifp->name : ""); return fc; } PseudoColumn *pc = new PseudoColumn(*sc, pseudoType); // @bug5892. set alias for derived table column matching. pc->alias(ifp->name? ifp->name : ""); return pc; }
ReturnedColumn* buildWindowFunctionColumn(Item* item, gp_walk_info& gwi, bool& nonSupport) { //@todo fix print for create view //String str; //item->print(&str, QT_INFINIDB_NO_QUOTE); //cout << str.c_ptr() << endl; if (!(gwi.thd->infinidb_vtable.cal_conn_info)) gwi.thd->infinidb_vtable.cal_conn_info = (void*)(new cal_connection_info()); cal_connection_info* ci = reinterpret_cast<cal_connection_info*>(gwi.thd->infinidb_vtable.cal_conn_info); gwi.hasWindowFunc = true; Item_func_window* wf = (Item_func_window*)item; string funcName = wf->func_name(); WindowFunctionColumn* ac = new WindowFunctionColumn(funcName); ac->distinct(wf->isDistinct()); Window_context *wf_ctx = wf->window_ctx(); SRCP srcp; // arguments vector<SRCP> funcParms; for (uint32_t i = 0; i < wf->arg_count; i++) { srcp.reset(buildReturnedColumn(wf->arguments()[i], gwi, nonSupport)); if (!srcp) return nullOnError(gwi); funcParms.push_back(srcp); if (gwi.clauseType == WHERE && !gwi.rcWorkStack.empty()) gwi.rcWorkStack.pop(); } ac->functionParms(funcParms); // Partition by if (wf_ctx) { vector<SRCP> partitions; for (uint32_t i = 0; i < wf_ctx->partition_count; i++) { srcp.reset(buildReturnedColumn(wf_ctx->partitions[i], gwi, nonSupport)); if (!srcp) return nullOnError(gwi); partitions.push_back(srcp); } ac->partitions(partitions); // Order by if (wf_ctx->ordering) { WF_OrderBy orderBy; // order columns if (wf_ctx->ordering->orders) { vector<SRCP> orders; ORDER* orderCol = reinterpret_cast<ORDER*>(wf_ctx->ordering->orders->first); for (; orderCol; orderCol= orderCol->next) { Item* orderItem = *(orderCol->item); srcp.reset(buildReturnedColumn(orderItem, gwi, nonSupport)); if (!srcp) return nullOnError(gwi); srcp->asc(orderCol->asc); srcp->nullsFirst(orderCol->nulls); // nulls 1-nulls first 0-nulls last orders.push_back(srcp); } orderBy.fOrders = orders; } // window frame WF_Frame frm; if (wf_ctx->ordering->frame) { frm.fIsRange = wf_ctx->ordering->frame->isRange; // start if (wf_ctx->ordering->frame->start) { frm.fStart.fFrame = frame(wf_ctx->ordering->frame->start->bound); if (wf_ctx->ordering->frame->start->item) { frm.fStart.fVal.reset(buildReturnedColumn(wf_ctx->ordering->frame->start->item, gwi, nonSupport)); if (!frm.fStart.fVal) return nullOnError(gwi); // 1. check expr is numeric type (rows) or interval (range) bool boundTypeErr = false; switch (frm.fStart.fVal->resultType().colDataType) { case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::VARCHAR: case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::CLOB: boundTypeErr = true; break; case CalpontSystemCatalog::DATE: case CalpontSystemCatalog::DATETIME: if (!frm.fIsRange) boundTypeErr = true; else if (dynamic_cast<IntervalColumn*>(frm.fStart.fVal.get()) == NULL) boundTypeErr = true; break; default: //okay break; } if (boundTypeErr) { gwi.fatalParseError = true; gwi.parseErrorText = logging::IDBErrorInfo::instance()->errorMsg(logging::ERR_WF_INVALID_BOUND_TYPE, colDataTypeToString(frm.fStart.fVal->resultType().colDataType)); return nullOnError(gwi); } } } // end if (wf_ctx->ordering->frame->end) { frm.fEnd.fFrame = frame(wf_ctx->ordering->frame->end->bound); if (wf_ctx->ordering->frame->end->item) { frm.fEnd.fVal.reset(buildReturnedColumn(wf_ctx->ordering->frame->end->item, gwi, nonSupport)); if (!frm.fEnd.fVal) return nullOnError(gwi); // check expr is numeric type (rows) or interval (range) bool boundTypeErr = false; switch (frm.fEnd.fVal->resultType().colDataType) { case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::VARCHAR: case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::CLOB: boundTypeErr = true; break; case CalpontSystemCatalog::DATE: case CalpontSystemCatalog::DATETIME: if (!frm.fIsRange) boundTypeErr = true; else if (dynamic_cast<IntervalColumn*>(frm.fEnd.fVal.get()) == NULL) boundTypeErr = true; break; default: //okay break; } if (boundTypeErr) { gwi.fatalParseError = true; gwi.parseErrorText = logging::IDBErrorInfo::instance()->errorMsg(logging::ERR_WF_INVALID_BOUND_TYPE, colDataTypeToString(frm.fStart.fVal->resultType().colDataType)); return nullOnError(gwi); } } } else // no end specified. default end to current row { frm.fEnd.fFrame = WF_CURRENT_ROW; } if (frm.fStart.fVal || frm.fEnd.fVal) { // check order by key only 1 (should be error-ed out in parser. double check here) if (frm.fIsRange && orderBy.fOrders.size() > 1) { gwi.fatalParseError = true; gwi.parseErrorText = logging::IDBErrorInfo::instance()->errorMsg(logging::ERR_WF_INVALID_ORDER_KEY); return nullOnError(gwi); } // check order by key type is numeric or date/datetime bool orderTypeErr = false; if (frm.fIsRange && orderBy.fOrders.size() == 1) { switch (orderBy.fOrders[0]->resultType().colDataType) { case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::VARCHAR: case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::CLOB: orderTypeErr = true; break; default: //okay // interval bound has to have date/datetime order key if ((dynamic_cast<IntervalColumn*>(frm.fStart.fVal.get()) != NULL || dynamic_cast<IntervalColumn*>(frm.fEnd.fVal.get()) != NULL)) { if (orderBy.fOrders[0]->resultType().colDataType != CalpontSystemCatalog::DATE && orderBy.fOrders[0]->resultType().colDataType != CalpontSystemCatalog::DATETIME) orderTypeErr = true; } else { if (orderBy.fOrders[0]->resultType().colDataType == CalpontSystemCatalog::DATETIME) orderTypeErr = true; } break; } if (orderTypeErr) { gwi.fatalParseError = true; gwi.parseErrorText = logging::IDBErrorInfo::instance()->errorMsg(logging::ERR_WF_INVALID_ORDER_TYPE, colDataTypeToString(orderBy.fOrders[0]->resultType().colDataType)); return nullOnError(gwi); } } } // construct +,- or interval function for boundary if (frm.fIsRange && frm.fStart.fVal) { frm.fStart.fBound.reset(buildBoundExp(frm.fStart, orderBy.fOrders[0], gwi)); if (!frm.fStart.fBound) return nullOnError(gwi); } if (frm.fIsRange && frm.fEnd.fVal) { frm.fEnd.fBound.reset(buildBoundExp(frm.fEnd, orderBy.fOrders[0], gwi)); if (!frm.fEnd.fVal) return nullOnError(gwi); } } else { frm.fStart.fFrame = WF_UNBOUNDED_PRECEDING; frm.fEnd.fFrame = WF_CURRENT_ROW; } orderBy.fFrame = frm; ac->orderBy(orderBy); } } if (gwi.fatalParseError || nonSupport) { if (gwi.parseErrorText.empty()) gwi.parseErrorText = logging::IDBErrorInfo::instance()->errorMsg(logging::ERR_WF_NON_SUPPORT); setError(gwi.thd, HA_ERR_UNSUPPORTED, gwi.parseErrorText); return NULL; } ac->resultType(colType_MysqlToIDB(wf)); // bug5736. Make the result type double for some window functions when // infinidb_double_for_decimal_math is set. ac->adjustResultType(); ac->expressionId(ci->expressionId++); if (item->name) ac->alias(item->name); // put ac on windowFuncList gwi.windowFuncList.push_back(ac); return ac; }