示例#1
0
/**
 * This is invoked when a NOT function is got. It's usually the case NOT<IN optimizer>
 * This function will simple turn the semi join to anti join
 *
 */
void InSub::handleNot()
{
	ParseTree *pt = fGwip.ptWorkStack.top();
	ExistsFilter *subFilter = dynamic_cast<ExistsFilter*>(pt->data());
	idbassert(subFilter);
	subFilter->notExists(true);
	SCSEP csep = subFilter->sub();
	const ParseTree* ptsub = csep->filters();
	if (ptsub)
		ptsub->walk(makeAntiJoin);
	ptsub = csep->having();
	if (ptsub)
		ptsub->walk(makeAntiJoin);
}
/** MySQL transform (NOT) IN subquery to (NOT) EXIST
 *
 */
execplan::ParseTree* InSub::transform()
{
    if (!fFunc)
        return NULL;

    // @todo need to handle scalar IN and BETWEEN specially
    // this blocks handles only one subselect scalar
    // arg[0]: column | arg[1]: subselect
    //assert (fFunc->argument_count() == 2 && fGwip.rcWorkStack.size() >= 2);
    if (fFunc->argument_count() != 2 || fGwip.rcWorkStack.size() < 2)
    {
        fGwip.fatalParseError = true;
        fGwip.parseErrorText = "Unsupported item in IN subquery";
        return NULL;
    }

    ReturnedColumn* rhs = fGwip.rcWorkStack.top();
    fGwip.rcWorkStack.pop();
    delete rhs;
    ReturnedColumn* lhs = fGwip.rcWorkStack.top();
    fGwip.rcWorkStack.pop();
    delete lhs;

    fSub = (Item_subselect*)(fFunc->arguments()[1]);
    idbassert(fSub && fFunc);

    SCSEP csep (new CalpontSelectExecutionPlan());
    csep->sessionID(fGwip.sessionid);
    csep->location(CalpontSelectExecutionPlan::WHERE);
    csep->subType (CalpontSelectExecutionPlan::IN_SUBS);

    // gwi for the sub query
    gp_walk_info gwi;
    gwi.thd = fGwip.thd;
    gwi.subQuery = this;

    // @4827 merge table list to gwi in case there is FROM sub to be referenced
    // in the FROM sub
    gwi.derivedTbCnt = fGwip.derivedTbList.size();
    uint32_t tbCnt = fGwip.tbList.size();

    gwi.tbList.insert(gwi.tbList.begin(), fGwip.tbList.begin(), fGwip.tbList.end());
    gwi.derivedTbList.insert(gwi.derivedTbList.begin(), fGwip.derivedTbList.begin(), fGwip.derivedTbList.end());

    if (getSelectPlan(gwi, *(fSub->get_select_lex()), csep) != 0)
    {
        fGwip.fatalParseError = true;

        if (gwi.fatalParseError && !gwi.parseErrorText.empty())
            fGwip.parseErrorText = gwi.parseErrorText;
        else
            fGwip.parseErrorText = "Error occured in InSub::transform()";

        return NULL;
    }

    // remove outer query tables
    CalpontSelectExecutionPlan::TableList tblist;

    if (csep->tableList().size() >= tbCnt)
        tblist.insert(tblist.begin(), csep->tableList().begin() + tbCnt, csep->tableList().end());

    CalpontSelectExecutionPlan::SelectList derivedTbList;

    if (csep->derivedTableList().size() >= gwi.derivedTbCnt)
        derivedTbList.insert(derivedTbList.begin(),
                             csep->derivedTableList().begin() + gwi.derivedTbCnt,
                             csep->derivedTableList().end());

    csep->tableList(tblist);
    csep->derivedTableList(derivedTbList);

    ExistsFilter* subFilter = new ExistsFilter();
    subFilter->sub(csep);

    if (gwi.subQuery->correlated())
        subFilter->correlated(true);
    else
        subFilter->correlated(false);

    if (fGwip.clauseType == HAVING && subFilter->correlated())
    {
        fGwip.fatalParseError = true;
        fGwip.parseErrorText = logging::IDBErrorInfo::instance()->errorMsg(logging::ERR_NON_SUPPORT_HAVING);
    }

    fGwip.subselectList.push_back(csep);
    return new ParseTree(subFilter);
}
示例#3
0
void derivedTableOptimization(SCSEP& csep)
{
	// @bug5634. replace the unused column with ConstantColumn from derived table column list,
	// ExeMgr will not project ConstantColumn. Only count for local derived column.
	// subquery may carry main query derived table list for column reference, those
	// derived tables are not checked for optimization in this scope.
	erydbSelectExecutionPlan::SelectList derivedTbList = csep->derivedTableList();

	// @bug6156. Skip horizontal optimization for no table union.
	bool horizontalOptimization = true;
	for (uint i = 0; i < derivedTbList.size(); i++)
	{
		erydbSelectExecutionPlan *plan = dynamic_cast<erydbSelectExecutionPlan*>(derivedTbList[i].get());
		erydbSelectExecutionPlan::ReturnedColumnList cols = plan->returnedCols();
		vector<erydbSelectExecutionPlan::ReturnedColumnList> unionColVec;

		// only do vertical optimization for union all
		// @bug6134. Also skip the vertical optimization for select distinct
		// because all columns need to be projected to check the distinctness.
		bool verticalOptimization = false;
		if (plan->distinctUnionNum() == 0 && !plan->distinct())
		{
			verticalOptimization = true;
			for (uint j = 0; j < plan->unionVec().size(); j++)
			{
				unionColVec.push_back(
				 dynamic_cast<erydbSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols());
			}
		}

		if (plan->tableList().empty())
			horizontalOptimization = false;
		for (uint j = 0; j < plan->unionVec().size(); j++)
		{
			if (dynamic_cast<erydbSelectExecutionPlan*>(plan->unionVec()[j].get())->tableList().empty())
			{
				horizontalOptimization = false;
				break;
			}
		}

		if (verticalOptimization)
		{
			int64_t val = 1;
			for (uint i = 0; i < cols.size(); i++)
			{
				//if (cols[i]->derivedTable().empty())
				if (cols[i]->refCount() == 0)
				{
					if (cols[i]->derivedRefCol())
						cols[i]->derivedRefCol()->decRefCount();
					cols[i].reset(new ConstantColumn(val));
					for (uint j = 0; j < unionColVec.size(); j++)
						unionColVec[j][i].reset(new ConstantColumn(val));
				}
			}

			// set back
			plan->returnedCols(cols);
			for (uint j = 0; j < unionColVec.size(); j++)
				dynamic_cast<erydbSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols(unionColVec[j]);
		}
	}

	/*
	 * @bug5635. Move filters that only belongs to a derived table to inside the derived table.
	 * 1. parse tree walk to populate derivedTableFilterMap and set null candidate on the tree.
	 * 2. remove the null filters
	 * 3. and the filters of derivedTableFilterMap and append to the WHERE filter of the derived table
	 *
	 * Note:
	 * 1. Subquery filters is ignored because derived table can not be in subquery
	 * 2. While walking tree, whenever a single derive simplefilter is encountered,
	 * this filter is pushed to the corresponding stack
	 * 2. Whenever an OR operator is encountered, all the filter stack of
	 * that OR involving derived table are emptied and null candidate of each
	 * stacked filter needs to be reset (not null)
	 */
	ParseTree* pt = csep->filters();
	map<string, ParseTree*> derivedTbFilterMap;
	if (horizontalOptimization && pt)
	{
		pt->walk(setDerivedTable);
		setDerivedFilter(pt, derivedTbFilterMap, derivedTbList);
		csep->filters(pt);
	}

	// AND the filters of individual stack to the derived table filter tree
	// @todo union filters.
	// @todo outer join complication
	map<string, ParseTree*>::iterator mapIt;
	for (uint i = 0; i < derivedTbList.size(); i++)
	{
		erydbSelectExecutionPlan *plan = dynamic_cast<erydbSelectExecutionPlan*>(derivedTbList[i].get());
		erydbSelectExecutionPlan::ReturnedColumnList derivedColList = plan->returnedCols();
		mapIt = derivedTbFilterMap.find(plan->derivedTbAlias());

		if (mapIt != derivedTbFilterMap.end())
		{
			// replace all derived column of this filter with real column from
			// derived table projection list.
			ParseTree *mainFilter = new ParseTree();
			mainFilter->copyTree(*(mapIt->second));
			replaceRefCol(mainFilter, derivedColList);
			ParseTree* derivedFilter = plan->filters();
			if (derivedFilter)
			{
				LogicOperator *op = new LogicOperator("and");
				ParseTree *filter = new ParseTree(op);
				filter->left(derivedFilter);
				filter->right(mainFilter);
				plan->filters(filter);
			}
			else
			{
				plan->filters(mainFilter);
			}

			// union filter handling
			for (uint j = 0; j < plan->unionVec().size(); j++)
			{
				erydbSelectExecutionPlan *unionPlan =
				  dynamic_cast<erydbSelectExecutionPlan*>(plan->unionVec()[j].get());
				erydbSelectExecutionPlan::ReturnedColumnList unionColList = unionPlan->returnedCols();
				ParseTree* mainFilterForUnion = new ParseTree();
				mainFilterForUnion->copyTree(*(mapIt->second));
				replaceRefCol(mainFilterForUnion, unionColList);
				ParseTree *unionFilter = unionPlan->filters();
				if (unionFilter)
				{
					LogicOperator *op = new LogicOperator("and");
					ParseTree *filter = new ParseTree(op);
					filter->left(unionFilter);
					filter->right(mainFilterForUnion);
					unionPlan->filters(filter);
				}
				else
				{
					unionPlan->filters(mainFilterForUnion);
				}
			}
		}
	}

	// clean derivedTbFilterMap because all the filters are copied
	for( mapIt = derivedTbFilterMap.begin(); mapIt != derivedTbFilterMap.end(); ++mapIt )
		delete (*mapIt).second;

	// recursively process the nested derived table
	for (uint i = 0; i < csep->subSelectList().size(); i++)
	{
		SCSEP subselect(boost::dynamic_pointer_cast<erydbSelectExecutionPlan>(csep->subSelectList()[i]));
		derivedTableOptimization(subselect);
	}
}