Пример #1
0
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;
}
Пример #2
0
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;
	
}