You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-07-30 19:23:07 +03:00
the begginning
This commit is contained in:
441
dbcon/execplan/arithmeticcolumn.cpp
Normal file
441
dbcon/execplan/arithmeticcolumn.cpp
Normal file
@ -0,0 +1,441 @@
|
||||
/* 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: arithmeticcolumn.cpp 9679 2013-07-11 22:32:03Z zzhu $
|
||||
*
|
||||
*
|
||||
***********************************************************************/
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#include "arithmeticcolumn.h"
|
||||
#include "constantcolumn.h"
|
||||
#include "simplecolumn.h"
|
||||
#include "operator.h"
|
||||
#include "bytestream.h"
|
||||
using namespace messageqcpp;
|
||||
|
||||
#include "objectreader.h"
|
||||
#include "expressionparser.h"
|
||||
#include "calpontselectexecutionplan.h"
|
||||
#include "treenodeimpl.h"
|
||||
#include "functioncolumn.h"
|
||||
#include "aggregatecolumn.h"
|
||||
#include "windowfunctioncolumn.h"
|
||||
|
||||
namespace {
|
||||
/** print the tree
|
||||
*
|
||||
* this function is mostly for debug purpose
|
||||
*/
|
||||
void walkfn(const execplan::ParseTree* n, ostream& output)
|
||||
{
|
||||
output << *(n->data()) << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace execplan {
|
||||
|
||||
/**
|
||||
* Constructors/Destructors
|
||||
*/
|
||||
ArithmeticColumn::ArithmeticColumn():
|
||||
ReturnedColumn(),
|
||||
fExpression (0)
|
||||
{}
|
||||
|
||||
ArithmeticColumn::ArithmeticColumn(const string& sql, const uint32_t sessionID):
|
||||
ReturnedColumn(sessionID),
|
||||
fData(sql),
|
||||
fExpression(0)
|
||||
{
|
||||
buildTree();
|
||||
}
|
||||
|
||||
ArithmeticColumn::ArithmeticColumn(const ArithmeticColumn& rhs, const uint32_t sessionID):
|
||||
ReturnedColumn(rhs, sessionID),
|
||||
fTableAlias (rhs.fTableAlias),
|
||||
fAsc (rhs.fAsc),
|
||||
fData (rhs.fData),
|
||||
fExpression (new ParseTree (*(rhs.expression())))
|
||||
{
|
||||
fAlias = rhs.fAlias;
|
||||
fSimpleColumnList.clear();
|
||||
fExpression->walk(getSimpleCols, &fSimpleColumnList);
|
||||
fAggColumnList.clear();
|
||||
fExpression->walk(getAggCols, &fAggColumnList);
|
||||
fWindowFunctionColumnList.clear();
|
||||
fExpression->walk(getWindowFunctionCols, &fWindowFunctionColumnList);
|
||||
}
|
||||
|
||||
ArithmeticColumn::~ArithmeticColumn()
|
||||
{
|
||||
if (fExpression != NULL)
|
||||
delete fExpression;
|
||||
fExpression = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
void ArithmeticColumn::expression(ParseTree*& expression)
|
||||
{
|
||||
if (fExpression != NULL)
|
||||
delete fExpression;
|
||||
fExpression = expression;
|
||||
expression = 0;
|
||||
}
|
||||
|
||||
void ArithmeticColumn::buildTree()
|
||||
{
|
||||
CalpontSelectExecutionPlan::Parser parser;
|
||||
vector<Token> tokens;
|
||||
Token t;
|
||||
|
||||
string::size_type i = 0;
|
||||
|
||||
//string fData = ReturnedColumn::data();
|
||||
|
||||
try {
|
||||
while (fData[i])
|
||||
{
|
||||
if (isdigit(fData[i]) || fData[i] == '.')
|
||||
{
|
||||
string num;
|
||||
while (isdigit(fData[i]) || fData[i] == '.')
|
||||
{
|
||||
num.push_back(fData[i++]);
|
||||
}
|
||||
|
||||
ConstantColumn *cc = new ConstantColumn(num, ConstantColumn::NUM);
|
||||
t.value = cc;
|
||||
|
||||
tokens.push_back(t);
|
||||
continue;
|
||||
}
|
||||
else if (fData[i] == '+' ||
|
||||
fData[i] == '-' ||
|
||||
fData[i] == '*' ||
|
||||
fData[i] == '/' ||
|
||||
fData[i] == '^' ||
|
||||
fData[i] == '(' ||
|
||||
fData[i] == ')' )
|
||||
{
|
||||
// t.is_operator now indicate the previous token type
|
||||
// if prev token is operand, then this '(' is func_open
|
||||
// otherwise, this '(' is open
|
||||
if (fData[i] == '(' && fData[i+1] != '-' && !t.is_operator())
|
||||
{
|
||||
// open '('
|
||||
Operator *op1 = new Operator("(");
|
||||
t.value = op1;
|
||||
tokens.push_back(t);
|
||||
|
||||
//This is not complete... we shouldn't be creating TreeNodes
|
||||
string param = nextToken(++i, ')');
|
||||
|
||||
TreeNode *tn = new TreeNodeImpl(param);
|
||||
t.value = tn;
|
||||
|
||||
tokens.push_back(t);
|
||||
|
||||
// close ')'
|
||||
Operator *op2 = new Operator(")");
|
||||
t.value = op2;
|
||||
tokens.push_back(t);
|
||||
continue;
|
||||
}
|
||||
|
||||
string op;
|
||||
|
||||
// Bug 319 fix. recover '^' to '||'
|
||||
if (fData[i] == '^')
|
||||
op = "||";
|
||||
else
|
||||
op.push_back(fData[i]);
|
||||
Operator *oper = new Operator(op);
|
||||
t.value = oper;
|
||||
|
||||
tokens.push_back(t);
|
||||
++i;
|
||||
|
||||
// t.is_operator now indicate the previous token type
|
||||
// if prev token is operand, then this '(' is func_open
|
||||
// otherwise, this '(' is open
|
||||
// @bug 241 fix. check (-n_nationkey) case
|
||||
if (fData[i] == '(' && fData[i] != '-' && !t.is_operator())
|
||||
{
|
||||
//This is not complete... we shouldn't be creating TreeNodes
|
||||
string param = nextToken(++i, ')');
|
||||
TreeNode *sc = new TreeNodeImpl(param);
|
||||
t.value = sc;
|
||||
|
||||
tokens.push_back(t);
|
||||
|
||||
// close ')'
|
||||
Operator *oper = new Operator(")");
|
||||
t.value = oper;
|
||||
tokens.push_back(t);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (isalpha(fData[i]) || fData[i] == '_' )
|
||||
{
|
||||
string identifier;
|
||||
while (isalnum(fData[i]) ||
|
||||
fData[i] == '_' ||
|
||||
fData[i] == '.' )
|
||||
{
|
||||
identifier.push_back(fData[i++]);
|
||||
}
|
||||
|
||||
SimpleColumn *sc = new SimpleColumn(identifier, fSessionID );
|
||||
t.value = sc;
|
||||
|
||||
tokens.push_back(t);
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (fData[i] == '\'')
|
||||
{
|
||||
string literal = nextToken(++i, '\'');
|
||||
ConstantColumn *cc = new ConstantColumn (literal, ConstantColumn::LITERAL);
|
||||
t.value = cc;
|
||||
|
||||
tokens.push_back(t);
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
fExpression = parser.parse(tokens.begin(), tokens.end());
|
||||
}
|
||||
catch (const invalid_argument& e)
|
||||
{
|
||||
// clean up tokens
|
||||
for (unsigned int i=0; i<tokens.size(); i++)
|
||||
{
|
||||
delete tokens[i].value;
|
||||
tokens[i].value = 0;
|
||||
}
|
||||
throw runtime_error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
const string ArithmeticColumn::nextToken(string::size_type &pos, char end) const
|
||||
{
|
||||
string token;
|
||||
// string fData = ReturnedColumn::data();
|
||||
|
||||
// increment num when get '(' and decrement when get ')'
|
||||
// to find the mathing ')' when num = 0
|
||||
int num = 1;
|
||||
for (; pos < fData.length(); )
|
||||
{
|
||||
if (end == ')')
|
||||
{
|
||||
if (fData[pos] == '(')
|
||||
num++;
|
||||
else if (fData[pos] == ')')
|
||||
num--;
|
||||
if (num == 0)
|
||||
{
|
||||
pos++;
|
||||
return token;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fData[pos] == end)
|
||||
{
|
||||
pos++;
|
||||
return token;
|
||||
}
|
||||
}
|
||||
token.push_back(fData[pos++]);
|
||||
}
|
||||
|
||||
string msg = "No ";
|
||||
msg.append(1, end);
|
||||
msg.append(" found in " + fData);
|
||||
throw invalid_argument ( msg );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ostream& operator<<(ostream& output, const ArithmeticColumn& rhs)
|
||||
{
|
||||
output << rhs.toString();
|
||||
return output;
|
||||
}
|
||||
|
||||
const string ArithmeticColumn::toString() const
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "ArithmeticColumn: ";
|
||||
if (fAlias.length() > 0) oss << "Alias: " << fAlias << endl;
|
||||
if (fExpression != 0) fExpression->walk(walkfn, oss);
|
||||
oss << "expressionId=" << fExpressionId << endl;
|
||||
oss << "joinInfo=" << fJoinInfo << " returnAll=" << fReturnAll << " sequence#=" << fSequence << endl;
|
||||
oss << "resultType=" << colDataTypeToString(fResultType.colDataType) << "|" << fResultType.colWidth <<
|
||||
endl;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void ArithmeticColumn::serialize(messageqcpp::ByteStream& b) const
|
||||
{
|
||||
b << static_cast<ObjectReader::id_t>(ObjectReader::ARITHMETICCOLUMN);
|
||||
ReturnedColumn::serialize(b);
|
||||
ObjectReader::writeParseTree(fExpression, b);
|
||||
b << fTableAlias;
|
||||
b << fData;
|
||||
b << static_cast<const ByteStream::doublebyte>(fAsc);
|
||||
}
|
||||
|
||||
void ArithmeticColumn::unserialize(messageqcpp::ByteStream& b)
|
||||
{
|
||||
ObjectReader::checkType(b, ObjectReader::ARITHMETICCOLUMN);
|
||||
ReturnedColumn::unserialize(b);
|
||||
if (fExpression != NULL)
|
||||
delete fExpression;
|
||||
fExpression = ObjectReader::createParseTree(b);
|
||||
b >> fTableAlias;
|
||||
b >> fData;
|
||||
b >> reinterpret_cast< ByteStream::doublebyte&>(fAsc);
|
||||
|
||||
fSimpleColumnList.clear();
|
||||
fExpression->walk(getSimpleCols, &fSimpleColumnList);
|
||||
fAggColumnList.clear();
|
||||
fExpression->walk(getAggCols, &fAggColumnList);
|
||||
fWindowFunctionColumnList.clear();
|
||||
fExpression->walk(getWindowFunctionCols, &fWindowFunctionColumnList);
|
||||
}
|
||||
|
||||
bool ArithmeticColumn::operator==(const ArithmeticColumn& t) const
|
||||
{
|
||||
const ReturnedColumn *rc1, *rc2;
|
||||
|
||||
rc1 = static_cast<const ReturnedColumn*>(this);
|
||||
rc2 = static_cast<const ReturnedColumn*>(&t);
|
||||
if (*rc1 != *rc2)
|
||||
return false;
|
||||
if (fExpression != NULL && t.fExpression != NULL) {
|
||||
if (*fExpression != *t.fExpression)
|
||||
return false;
|
||||
}
|
||||
else if (fExpression != NULL || t.fExpression != NULL)
|
||||
return false;
|
||||
if (fAlias != t.fAlias)
|
||||
return false;
|
||||
if (fTableAlias != t.fTableAlias)
|
||||
return false;
|
||||
if (fData != t.fData)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArithmeticColumn::operator==(const TreeNode* t) const
|
||||
{
|
||||
const ArithmeticColumn *o;
|
||||
|
||||
o = dynamic_cast<const ArithmeticColumn*>(t);
|
||||
if (o == NULL)
|
||||
return false;
|
||||
return *this == *o;
|
||||
}
|
||||
|
||||
bool ArithmeticColumn::operator!=(const ArithmeticColumn& t) const
|
||||
{
|
||||
return (!(*this == t));
|
||||
}
|
||||
|
||||
bool ArithmeticColumn::operator!=(const TreeNode* t) const
|
||||
{
|
||||
return (!(*this == t));
|
||||
}
|
||||
|
||||
bool ArithmeticColumn::hasAggregate()
|
||||
{
|
||||
if (fHasAggregate) return true;
|
||||
fAggColumnList.clear();
|
||||
fExpression->walk(getAggCols, &fAggColumnList);
|
||||
if (!fAggColumnList.empty())
|
||||
fHasAggregate = true;
|
||||
return fHasAggregate;
|
||||
}
|
||||
|
||||
bool ArithmeticColumn::hasWindowFunc()
|
||||
{
|
||||
fWindowFunctionColumnList.clear();
|
||||
fExpression->walk(getWindowFunctionCols, &fWindowFunctionColumnList);
|
||||
if (fWindowFunctionColumnList.empty())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArithmeticColumn::setDerivedTable()
|
||||
{
|
||||
if (hasAggregate())
|
||||
{
|
||||
fDerivedTable = "";
|
||||
return;
|
||||
}
|
||||
if (fExpression)
|
||||
{
|
||||
fExpression->setDerivedTable();
|
||||
fDerivedTable = fExpression->derivedTable();
|
||||
}
|
||||
}
|
||||
|
||||
void ArithmeticColumn::replaceRealCol(std::vector<SRCP>& derivedColList)
|
||||
{
|
||||
if (fExpression)
|
||||
replaceRefCol(fExpression, derivedColList);
|
||||
}
|
||||
|
||||
void ArithmeticColumn::setSimpleColumnList()
|
||||
{
|
||||
fSimpleColumnList.clear();
|
||||
fExpression->walk(getSimpleCols, &fSimpleColumnList);
|
||||
}
|
||||
|
||||
bool ArithmeticColumn::singleTable(CalpontSystemCatalog::TableAliasName& tan)
|
||||
{
|
||||
tan.clear();
|
||||
setSimpleColumnList();
|
||||
for (uint32_t i = 0; i < fSimpleColumnList.size(); i++)
|
||||
{
|
||||
CalpontSystemCatalog::TableAliasName stan(fSimpleColumnList[i]->schemaName(),
|
||||
fSimpleColumnList[i]->tableName(),
|
||||
fSimpleColumnList[i]->tableAlias(),
|
||||
fSimpleColumnList[i]->viewName());
|
||||
if (tan.table.empty())
|
||||
tan = stan;
|
||||
else if (stan != tan)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user