Ejemplo n.º 1
0
ParseTree* ExpressionParser::reduce(TreeNode* op, ParseTree* lhs, ParseTree* rhs)
{
    ParseTree* root = new ParseTree(op);
    root->left(lhs);
    root->right(rhs);
    return root;
}
Ejemplo n.º 2
0
/**
* Build an expression tree with the tokens
*/
ParseTree* ExpressionParser::reduce(TreeNode* op, ParseTree* value)
{
    char c = op->data().at(0);
    switch (c) {
    case 'M':
    case 'm':
    {
        ParseTree *root = new ParseTree(op);
        ParseTree *lhs = new ParseTree(new ConstantColumn("0", ConstantColumn::NUM));
        root->left(lhs);
        root->right(value);
        return root;
    }
    case 'I':
    case 'i':
        delete op;
        return value;
    default:
        idbassert(0);
    }
    
    ostringstream oss;
    oss << "ExpressionParser::reduce(TreeNode*,ParseTree*): invalid input token: >" << op->data() << '<';
    throw std::runtime_error(oss.str());
    return 0;
}
Ejemplo n.º 3
0
ParseTree* setDerivedFilter(ParseTree*& n, map<string, ParseTree*>& filterMap, 
                            erydbSelectExecutionPlan::SelectList& derivedTbList)
{
	if (!(n->derivedTable().empty()))
	{
		// @todo replace virtual column of n to real column
		// all simple columns should belong to the same derived table
		erydbSelectExecutionPlan *csep = NULL;
		for (uint i = 0; i < derivedTbList.size(); i++)
		{
			erydbSelectExecutionPlan *plan = dynamic_cast<erydbSelectExecutionPlan*>(derivedTbList[i].get());
			if (plan->derivedTbAlias() == n->derivedTable())
			{
				csep = plan;
				break;
			}
		}
		// should never be null; if null then give up optimization.
		if (!csep)
			return n;

		// 2. push the filter to the derived table filter stack, or 'and' with
		// the filters in the stack
		map<string, ParseTree*>::iterator mapIter = filterMap.find(n->derivedTable());
		if ( mapIter == filterMap.end())
		{
			filterMap.insert(pair<string, ParseTree*>(n->derivedTable(), n));
		}
		else
		{
			ParseTree* pt = new ParseTree(new LogicOperator("and"));
			pt->left(mapIter->second);
			pt->right(n);
			mapIter->second = pt;
		}
		int64_t val = 1;
		n = new ParseTree(new ConstantColumn(val));
	}
	else
	{
		Operator *op = dynamic_cast<Operator*>(n->data());
		if (op && (op->op() == OP_OR || op->op() == OP_XOR))
		{
			return n;
		}
		else
		{
			ParseTree *lhs = n->left();
			ParseTree *rhs = n->right();
			if (lhs)
				n->left(setDerivedFilter(lhs, filterMap, derivedTbList));
			if (rhs)
				n->right(setDerivedFilter(rhs, filterMap, derivedTbList));
		}
	}
	return n;
}
Ejemplo n.º 4
0
bool operator==(const ParseTree& t1,
				const ParseTree& t2)
{
	if (t1.data() != NULL && t2.data() != NULL) {
		if (*t1.data() != t2.data())
			return false;
	}
	else if (t1.data() != NULL || t2.data() != NULL)
		return false;

	if (t1.left() != NULL && t2.left() != NULL) {
		if (*t1.left() != *t2.left())
			return false;
	}
	else if (t1.left() != NULL || t2.left() != NULL)
		return false;
	
	if (t1.right() != NULL && t2.right() != NULL) {
		if (*t1.right() != *t2.right())
			return false;
	}
	else if (t1.right() != NULL || t2.right() != NULL)
		return false;
	
	return true;
}
Ejemplo n.º 5
0
ParseTree* ObjectReader::createParseTree(messageqcpp::ByteStream& b)
{
	CLASSID id = ZERO;
	ParseTree* ret;
	
	b >> (id_t&) id;
	if (id == NULL_CLASS)
		return NULL;
	if (id != PARSETREE)
		throw UnserializeException("Not a ParseTree");
	
	ret = new ParseTree();
	ret->left(createParseTree(b));
	ret->right(createParseTree(b));
	ret->data(createTreeNode(b));
	return ret;
}	
Ejemplo n.º 6
0
void appendSimpleFilter
				(
				ParseTree*& ptree,
				SimpleFilter* filter
				)
{
	if( ptree->data() == 0 )
	{
		// degenerate case, this filter goes at this node
		ptree->data( filter );
	}
	else if( ptree->right() == 0 && ptree->left() == 0 )
	{
		// this will be the case when there is a single node in the tree
		// that contains a filter.  Here we want to make the root node an
		// 'and' operator, push the existing down to the lhs and make a
		// new node for the new filter
		ParseTree* newLhs = new ParseTree( ptree->data() );
		ParseTree* newRhs = new ParseTree( filter );

		Operator* op = new Operator();
		op->data("and");

		ptree->data( op );
		ptree->left( newLhs );
		ptree->right( newRhs );
	}
	else
	{
		// this will be the case once we have a tree with an 'and' at the
		// root node, a filter in the lhs, and an arbitrary height tree
		// with the same properties on the rhs.  Because all operators
		// are guaranteed to be and for now we simply insert a new rhs
		// node and "push down" the existing tree
		Operator* op = new Operator();
		op->data("and");

		ParseTree* newRhs = new ParseTree( op );
		newRhs->left( new ParseTree( filter ) );
		newRhs->right( ptree->right() );
		ptree->right( newRhs );
	}
}
Ejemplo n.º 7
0
void SubAdapterStep::addExpression(const JobStepVector& exps, JobInfo& jobInfo)
{
	// maps key to the index in the RG
	map<uint32_t, uint32_t> keyToIndexMap;
	const vector<uint32_t>& keys = fRowGroupIn.getKeys();
	for (size_t i = 0; i < keys.size(); i++)
		keyToIndexMap[keys[i]] = i;

	// combine the expression to one parse tree
	ParseTree* filter = NULL;
	for (JobStepVector::const_iterator it = exps.begin(); it != exps.end(); it++)
	{
		ExpressionStep* e = dynamic_cast<ExpressionStep*>(it->get());
		idbassert(e);

		e->updateInputIndex(keyToIndexMap, jobInfo);
		if (filter != NULL)
		{
			ParseTree* left = filter;
			ParseTree* right = new ParseTree();
			right->copyTree(*(e->expressionFilter()));
			filter = new ParseTree(new LogicOperator("and"));
			filter->left(left);
			filter->right(right);
		}
		else
		{
			filter = new ParseTree();
			filter->copyTree(*(e->expressionFilter()));
		}
	}

	// add to the expression wrapper
	if (fExpression.get() == NULL)
		fExpression.reset(new funcexp::FuncExpWrapper());
	fExpression->addFilter(boost::shared_ptr<execplan::ParseTree>(filter));
}
execplan::ParseTree* ScalarSub::transform_between()
{
    //idbassert(fGwip.rcWorkStack.size() >= 3);
    if (fGwip.rcWorkStack.size() < 3)
    {
        fGwip.fatalParseError = true;
        fGwip.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SCALAR);
        return NULL;
    }

    ReturnedColumn* op3 = fGwip.rcWorkStack.top();
    fGwip.rcWorkStack.pop();
    ReturnedColumn* op2 = fGwip.rcWorkStack.top();
    fGwip.rcWorkStack.pop();
    ReturnedColumn* op1 = fGwip.rcWorkStack.top();
    fGwip.rcWorkStack.pop();
    fColumn.reset(op1);

    ParseTree* lhs = NULL;
    ParseTree* rhs = NULL;
    PredicateOperator* op_LE = new PredicateOperator("<=");
    PredicateOperator* op_GE = new PredicateOperator(">=");

    SubSelect* sub2 = dynamic_cast<SubSelect*>(op3);
    fSub = (Item_subselect*)(fFunc->arguments()[2]);

    if (sub2)
    {
        rhs = buildParseTree(op_LE);
        delete sub2;
    }
    else
    {
        SOP sop;
        sop.reset(op_LE);
        rhs = new ParseTree(new SimpleFilter(sop, fColumn.get(), op3));
    }

    SubSelect* sub1 = dynamic_cast<SubSelect*>(op2);
    fSub = (Item_subselect*)(fFunc->arguments()[1]);

    if (sub1)
    {
        lhs = buildParseTree(op_GE);
        delete sub1;
    }
    else
    {
        SOP sop;
        sop.reset(op_GE);
        lhs = new ParseTree(new SimpleFilter(sop, fColumn.get(), op2));
    }

    if (!rhs || !lhs)
    {
        fGwip.fatalParseError = true;
        fGwip.parseErrorText = "non-supported scalar subquery";
        fGwip.parseErrorText = IDBErrorInfo::instance()->errorMsg(ERR_NON_SUPPORT_SCALAR);
        return NULL;
    }

    ParseTree* pt = new ParseTree (new LogicOperator("and"));
    pt->left(lhs);
    pt->right(rhs);
    return pt;
}
/**
 * Handle MySQL's plugin functions
 * This is mostly for handling the null related functions that MySQL adds to the execution plan
 */
void InSub::handleFunc(gp_walk_info* gwip, Item_func* func)
{
    if (func->functype() == Item_func::TRIG_COND_FUNC || func->functype() == Item_func::COND_OR_FUNC)
    {
        // purpose: remove the isnull() function from the parsetree in ptWorkStack.
        // IDB handles the null semantics in the join operation
        // trigcond(or_cond) is the only form we recognize for now
        if (func->argument_count() > 2)
        {
            fGwip.fatalParseError = true;
            fGwip.parseErrorText = "Unsupported item in IN subquery";
            return;
        }

        Item_cond* cond;

        if (func->functype() == Item_func::TRIG_COND_FUNC)
        {
            Item* item;

            if (func->arguments()[0]->type() == Item::REF_ITEM)
                item = (Item_ref*)(func->arguments()[0])->real_item();
            else
                item = func->arguments()[0];

            cond = (Item_cond*)(item);
        }
        else
        {
            cond = (Item_cond*)(func);
        }

        if (cond->functype() == Item_func::COND_OR_FUNC)
        {
            // (cache=item) case. do nothing. ignore trigcond()?
            if (cond->argument_list()->elements == 1)
                return;

            // (cache=item or isnull(item)) case. remove "or isnull()"
            if (cond->argument_list()->elements == 2)
            {
                // don't know how to deal with this. don't think it's a fatal error either.
                if (gwip->ptWorkStack.empty())
                    return;

                ParseTree* pt = gwip->ptWorkStack.top();

                if (!pt->left() || !pt->right())
                    return;

                SimpleFilter* sf = dynamic_cast<SimpleFilter*>(pt->left()->data());

                //assert (sf && sf->op()->op() == execplan::OP_ISNULL);
                if (!sf || sf->op()->op() != execplan::OP_ISNULL)
                    return;

                delete sf;
                sf = dynamic_cast<SimpleFilter*>(pt->right()->data());

                //idbassert(sf && sf->op()->op() == execplan::OP_EQ);
                if (!sf || sf->op()->op() != execplan::OP_EQ)
                    return;

                // set NULLMATCH for both operand. It's really a setting for the join.
                // should only set NULLMATCH when the subtype is NOT_IN. for some IN subquery
                // with aggregation column, MySQL inefficiently convert to:
                // (cache=item or item is null) and item is not null, which is equivalent to
                // cache = item. Do not set NULLMATCH for this case.
                // Because we don't know IN or NOTIN yet, set candidate bit and switch to NULLMATCH
                // later in handleNot function.
                if (sf->lhs()->joinInfo() & JOIN_CORRELATED)
                    sf->lhs()->joinInfo(sf->lhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE);

                if (sf->rhs()->joinInfo() & JOIN_CORRELATED)
                    sf->rhs()->joinInfo(sf->rhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE);

                pt = pt->right();
                gwip->ptWorkStack.pop();
                gwip->ptWorkStack.push(pt);
            }
        }
        else if (cond->functype() == Item_func::EQ_FUNC)
        {
            // not in (select const ...)
            if (gwip->ptWorkStack.empty())
                return;

            ParseTree* pt = gwip->ptWorkStack.top();
            SimpleFilter* sf = dynamic_cast<SimpleFilter*>(pt->data());

            if (!sf || sf->op()->op() != execplan::OP_EQ)
                return;

            if (sf->lhs()->joinInfo() & JOIN_CORRELATED)
                sf->lhs()->joinInfo(sf->lhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE);

            if (sf->rhs()->joinInfo() & JOIN_CORRELATED)
                sf->rhs()->joinInfo(sf->rhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE);
        }
    }
}
Ejemplo n.º 10
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);
	}
}
Ejemplo n.º 11
0
ReturnedColumn* buildBoundExp(WF_Boundary& bound, SRCP& order, gp_walk_info& gwi)
{
	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);

	bool addOp = true;
	ReturnedColumn* rc = NULL;
	if (bound.fFrame == execplan::WF_PRECEDING)
	{
		if (order->asc())
			addOp = false;
	}
	else if (!order->asc()) // must be WF_FOLLOWING
		addOp = false;

	funcexp::FunctionParm funcParms;
	SPTP sptp;
	IntervalColumn* intervalCol = dynamic_cast<IntervalColumn*>(bound.fVal.get());
	// @todo error out non constant. only support literal interval for now.
	if (!intervalCol && order->resultType().colDataType == CalpontSystemCatalog::DATE)
	{
		intervalCol = new IntervalColumn(bound.fVal, (int)IntervalColumn::INTERVAL_DAY);
		bound.fVal.reset(intervalCol);
	}

	if (intervalCol)
	{
		// date_add
		rc = new FunctionColumn();
		string funcName = "date_add_interval";
		
		// @bug6061 . YEAR, QUARTER, MONTH, WEEK, DAY type
		CalpontSystemCatalog::ColType ct;
		if (order->resultType().colDataType == CalpontSystemCatalog::DATE &&
		    intervalCol->intervalType() <= IntervalColumn::INTERVAL_DAY)
		{
			ct.colDataType = CalpontSystemCatalog::DATE;
			ct.colWidth = 4;
		}
		else
		{
			ct.colDataType = CalpontSystemCatalog::DATETIME;
			ct.colWidth = 8;
		}
		// put interval val column to bound
		(dynamic_cast<FunctionColumn*>(rc))->functionName(funcName);
		sptp.reset(new ParseTree(order->clone()));
		funcParms.push_back(sptp);
		sptp.reset(new ParseTree(intervalCol->val()->clone()));
		funcParms.push_back(sptp);
		funcParms.push_back(getIntervalType(intervalCol->intervalType()));
		SRCP srcp(intervalCol->val());
		bound.fVal = srcp;
		if (addOp)
		{
			sptp.reset(new ParseTree(new ConstantColumn("ADD")));
			funcParms.push_back(sptp);
		}
		else
		{
			sptp.reset(new ParseTree(new ConstantColumn("SUB")));
			funcParms.push_back(sptp);
		}
		(dynamic_cast<FunctionColumn*>(rc))->functionParms(funcParms);

		rc->resultType(ct);
		// @bug6061. Use result type as operation type for WF bound expression
		rc->operationType(ct);
		rc->expressionId(ci->expressionId++);
		return rc;
	}

	// arithmetic
	rc = new ArithmeticColumn();
	ArithmeticOperator* aop;
	if (addOp)
		aop = new ArithmeticOperator("+");
	else
		aop = new ArithmeticOperator("-");
	ParseTree *pt = new ParseTree(aop);
	ParseTree *lhs = 0, *rhs = 0;
	lhs = new ParseTree(order->clone());
	rhs = new ParseTree(bound.fVal->clone());
	pt->left(lhs);
	pt->right(rhs);
	aop->resultType(order->resultType());
	aop->operationType(aop->resultType());
	(dynamic_cast<ArithmeticColumn*>(rc))->expression(pt);
	rc->resultType(aop->resultType());
	rc->operationType(aop->operationType());
	rc->expressionId(ci->expressionId++);
	return rc;
}