1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-04-18 21:44:02 +03:00
2022-01-21 16:43:49 +00:00

417 lines
8.9 KiB
C++

/* Copyright (C) 2014 InfiniDB, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 of
the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA. */
/***********************************************************************
* $Id: expressionparser.cpp 9210 2013-01-21 14:10:42Z rdempsey $
*
*
***********************************************************************/
#include <string>
#include <stack>
#include <sstream>
using namespace std;
#include "expressionparser.h"
#include "aggregatecolumn.h"
#include "functioncolumn.h"
#include "constantcolumn.h"
#include "operator.h"
#include "treenode.h"
#include <boost/algorithm/string/case_conv.hpp>
namespace execplan
{
/**
* Constructor / Destructor
*/
ExpressionParser::ExpressionParser()
{
}
ExpressionParser::~ExpressionParser()
{
}
void ExpressionParser::invalid_operator_position(TreeNode* oper)
{
std::string str = oper->data();
delete oper;
throw std::runtime_error("Invalid operator position: " + str + "\n");
}
void ExpressionParser::invalid_operator_position(const Token& oper)
{
throw std::runtime_error("Invalid operator position: " + oper.value->data() + "\n");
}
void ExpressionParser::invalid_operand_position(ParseTree* operand)
{
delete operand;
throw std::runtime_error("Invalid operand position\n");
}
void ExpressionParser::unbalanced_confix(TreeNode* oper)
{
delete oper;
throw std::runtime_error("Unbalanced confix operator\n");
}
void ExpressionParser::missing_operand(const Token& oper)
{
delete oper.value;
throw std::runtime_error("Imissing operand\n");
}
int ExpressionParser::positions(Token t)
{
string oper = t.value->data();
char c = oper.at(0);
switch (c)
{
case '+':
case '-': return expression::infix | expression::prefix;
case '*':
case '/':
case '^':
case '|': // concat ||
return expression::infix;
case '(': return expression::open | expression::function_open;
case ')': return expression::close | expression::function_close;
default:
boost::algorithm::to_lower(oper);
if (oper.compare("and") == 0 || oper.compare("or") == 0)
return expression::infix;
}
ostringstream oss;
oss << "ExpressionParser::positions(Token): invalid input token: >" << oper << '<';
throw std::runtime_error(oss.str());
return 0;
}
int ExpressionParser::position(TreeNode* op)
{
string oper = op->data();
char c = oper.at(0);
switch (c)
{
case '+':
case '-':
case '*':
case '/':
case '|': // concat ||
return expression::infix;
case 'M':
case 'm':
case 'I':
case 'i': return expression::prefix;
case '(': return expression::open;
case '[': return expression::function_open;
case ')': return expression::close;
case ']': return expression::function_close;
default:
boost::algorithm::to_lower(oper);
if (oper.compare("and") == 0 || oper.compare("or") == 0)
return expression::infix;
}
ostringstream oss;
oss << "ExpressionParser::position(TreeNode*): invalid input token: >" << oper << '<';
throw std::runtime_error(oss.str());
}
ParseTree* ExpressionParser::as_operand(Token t)
{
return new ParseTree(t.value);
}
TreeNode* ExpressionParser::as_operator(Token t, int pos)
{
string oper = t.value->data();
char c = oper.at(0);
switch (c)
{
case '+':
if (pos == expression::infix)
return t.value;
else
{
delete t.value;
return new Operator("I");
}
case '-':
if (pos == expression::infix)
return t.value;
else
{
delete t.value;
return new Operator("M");
}
case '*':
case '/':
case ')':
case '|': return t.value;
case '(':
if (pos == expression::open)
return t.value;
else
{
delete t.value;
return new Operator("[");
}
default:
boost::algorithm::to_lower(oper);
if (oper.compare("and") == 0 || oper.compare("or") == 0)
return t.value;
}
ostringstream oss;
oss << "ExpressionParser::as_operator(Token,int): invalid input token: >" << oper << '<';
throw std::runtime_error(oss.str());
}
expression::precedence ExpressionParser::precedence(TreeNode* op1, TreeNode* op2)
{
int p1 = precnum(op1);
int p2 = precnum(op2);
if (p1 < p2)
return expression::lower;
else if (p1 > p2)
return expression::higher;
else if (p1 == p2)
return expression::equal;
else
return expression::none;
}
expression::associativity ExpressionParser::associativity(TreeNode* op1, TreeNode* op2)
{
expression::associativity assoc1 = assoc(op1);
expression::associativity assoc2 = assoc(op2);
if (assoc1 == assoc2)
return assoc1;
else
return expression::non_associative;
}
/**
* 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;
}
ParseTree* ExpressionParser::reduce(TreeNode* op, ParseTree* lhs, ParseTree* rhs)
{
ParseTree* root = new ParseTree(op);
root->left(lhs);
root->right(rhs);
return root;
}
// parenthesis
ParseTree* ExpressionParser::reduce(TreeNode* a, TreeNode* b, ParseTree* value)
{
delete a;
delete b;
return value;
}
// function call: handle aggregation functions and other functions
ParseTree* ExpressionParser::reduce(ParseTree* a, TreeNode* b, ParseTree* value, TreeNode* d)
{
string functionName = a->data()->data();
string content = value->data()->data();
ParseTree* root;
boost::algorithm::to_lower(functionName);
if (functionName.compare("sum") == 0 || functionName.compare("avg") == 0 ||
functionName.compare("count") == 0 || functionName.compare("min") == 0 ||
functionName.compare("max") == 0)
{
AggregateColumn* ac = new AggregateColumn(functionName, content);
root = new ParseTree(ac);
}
else
{
FunctionColumn* fc = new FunctionColumn(functionName, content);
root = new ParseTree(fc);
}
delete a;
delete value;
delete b;
delete d;
return root;
}
int ExpressionParser::precnum(TreeNode* op)
{
string oper = op->data();
char c = oper.at(0);
switch (c)
{
case '+':
case '-':
case '|': return 3;
case '*':
case '/': return 4;
case 'M':
case 'I': return 5;
case '(': return 6;
case '[': return 7;
default:
boost::algorithm::to_lower(oper);
if (oper.compare("or") == 0)
return 1;
else if (oper.compare("and") == 0)
return 2;
}
return 0;
}
expression::associativity ExpressionParser::assoc(TreeNode* op)
{
string oper = op->data();
char c = oper.at(0);
switch (c)
{
case '+':
case '-':
case '*':
case '/':
case '|': return expression::left_associative;
default:
boost::algorithm::to_lower(oper);
if (oper.compare("or") == 0 || oper.compare("and") == 0)
return expression::left_associative;
return expression::non_associative;
}
}
void ExpressionParser::cleanup(stack<ParseTree*> operandStack, stack<TreeNode*> operatorStack)
{
while (!operandStack.empty())
{
ParseTree* a = operandStack.top();
operandStack.pop();
delete a;
}
while (!operatorStack.empty())
{
TreeNode* a = operatorStack.top();
operatorStack.pop();
delete a;
}
}
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;
}
bool operator!=(const ParseTree& t1, const ParseTree& t2)
{
return !(t1 == t2);
}
} // namespace execplan