mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-18 21:44:02 +03:00
789 lines
18 KiB
C++
789 lines
18 KiB
C++
/* Copyright (C) 2014 InfiniDB, Inc.
|
|
Copyright (C) 2019 MariaDB Corporation
|
|
|
|
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: parsetree.h 9635 2013-06-19 21:42:30Z bwilkinson $
|
|
*
|
|
*
|
|
***********************************************************************/
|
|
/** @file */
|
|
|
|
#pragma once
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include "treenode.h"
|
|
#include "operator.h"
|
|
#include "mcs_decimal.h"
|
|
#include <boost/core/demangle.hpp>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
|
|
namespace rowgroup
|
|
{
|
|
class Row;
|
|
}
|
|
|
|
namespace execplan
|
|
{
|
|
// class Operator;
|
|
/**
|
|
* @brief A template class template to represent an expression tree
|
|
*
|
|
* This class is a simple binary tree implementation which
|
|
* represents an expression tree. The expression can be used
|
|
* for both arithmetic and logical expression.
|
|
* Please note that to use this template class T can only be pointers.
|
|
*/
|
|
|
|
class ParseTree
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor / Destructor
|
|
*/
|
|
inline ParseTree();
|
|
inline explicit ParseTree(TreeNode* data);
|
|
inline ParseTree(TreeNode* data, ParseTree* left, ParseTree* right);
|
|
inline ParseTree(const ParseTree& rhs);
|
|
inline virtual ~ParseTree();
|
|
|
|
/**
|
|
* Access methods
|
|
*/
|
|
inline void left(ParseTree* expressionTree)
|
|
{
|
|
fLeft = expressionTree;
|
|
}
|
|
|
|
inline void left(TreeNode* node)
|
|
{
|
|
ParseTree* pt = new ParseTree(node);
|
|
left(pt);
|
|
}
|
|
|
|
inline ParseTree* left() const
|
|
{
|
|
return fLeft;
|
|
}
|
|
|
|
inline ParseTree** leftRef()
|
|
{
|
|
return &fLeft;
|
|
}
|
|
|
|
inline void nullRight()
|
|
{
|
|
fRight = nullptr;
|
|
}
|
|
|
|
inline void nullLeft()
|
|
{
|
|
fLeft = nullptr;
|
|
}
|
|
|
|
inline void right(ParseTree* expressionTree)
|
|
{
|
|
fRight = expressionTree;
|
|
}
|
|
|
|
inline void right(TreeNode* node)
|
|
{
|
|
ParseTree* pt = new ParseTree(node);
|
|
right(pt);
|
|
}
|
|
|
|
inline ParseTree* right() const
|
|
{
|
|
return fRight;
|
|
}
|
|
|
|
inline ParseTree** rightRef()
|
|
{
|
|
return &fRight;
|
|
}
|
|
|
|
inline void data(TreeNode* data)
|
|
{
|
|
fData = data;
|
|
}
|
|
|
|
inline TreeNode* data() const
|
|
{
|
|
return fData;
|
|
}
|
|
|
|
/** walk the tree
|
|
*
|
|
* postfix walking of a const tree
|
|
*/
|
|
inline void walk(void (*fn)(ParseTree* n)) const;
|
|
|
|
/** walk the tree
|
|
*
|
|
* postfix walking of a non-const tree. This is for deleting the tree
|
|
*/
|
|
inline void walk(void (*fn)(const ParseTree* n)) const;
|
|
|
|
/** output the tree
|
|
*
|
|
* take ostream argument to walk and output the tree
|
|
*/
|
|
inline void walk(void (*fn)(const ParseTree* n, std::ostream& output), std::ostream& output) const;
|
|
|
|
/** output the tree
|
|
*
|
|
* take user argument to walk and output the tree
|
|
*/
|
|
inline void walk(void (*fn)(const ParseTree* n, void* obj), void* object) const;
|
|
|
|
/** output the tree
|
|
*
|
|
* take user argument to walk and output the tree
|
|
*/
|
|
inline void walk(void (*fn)(ParseTree* n, void* obj), void* object) const;
|
|
|
|
/** output the tree to string
|
|
* for debug purpose
|
|
*/
|
|
inline std::string toString() const;
|
|
|
|
inline std::string toCppCode(std::unordered_set<std::string>& includes) const;
|
|
|
|
inline void codeToFile(std::string filename, std::string varname) const;
|
|
/** assignment operator
|
|
*
|
|
*/
|
|
inline ParseTree& operator=(const ParseTree& rhs);
|
|
|
|
/** deep copy of a tree
|
|
*
|
|
* copy src tree on top of dest tree. Dest tree is destroyed before copy
|
|
* takes place. Src tree still owns the tree data, though. Assume tree node
|
|
* are pointers.
|
|
*/
|
|
inline void copyTree(const ParseTree& src);
|
|
|
|
/** destroy a tree
|
|
*
|
|
* destroy a tree where tree nodes are values
|
|
*/
|
|
inline static void destroyTree(ParseTree* root);
|
|
|
|
/** draw the tree using dot
|
|
*
|
|
* this function is mostly for debug purpose, where T represent a TreeNode
|
|
* pointer
|
|
*/
|
|
inline void drawTree(std::string filename);
|
|
|
|
/** print the tree
|
|
*
|
|
* this function is mostly for debug purpose, where T represent a TreeNode
|
|
* pointer
|
|
*/
|
|
inline static void print(const ParseTree* n, std::ostream& output)
|
|
{
|
|
output << *n->data() << std::endl;
|
|
}
|
|
|
|
/** delete treenode
|
|
*
|
|
* delete fData of a tree node, and then delete the treenode
|
|
*/
|
|
inline static void deleter(ParseTree*& n)
|
|
{
|
|
delete n->fData;
|
|
n->fData = nullptr;
|
|
delete n;
|
|
n = nullptr;
|
|
}
|
|
|
|
inline void derivedTable(const std::string& derivedTable)
|
|
{
|
|
fDerivedTable = derivedTable;
|
|
}
|
|
|
|
inline std::string& derivedTable()
|
|
{
|
|
return fDerivedTable;
|
|
}
|
|
|
|
inline void setDerivedTable();
|
|
|
|
enum class GoTo
|
|
{
|
|
Left,
|
|
Right,
|
|
Up
|
|
};
|
|
|
|
struct StackFrame
|
|
{
|
|
ParseTree* node;
|
|
GoTo direction;
|
|
explicit StackFrame(ParseTree* node_, GoTo direction_ = GoTo::Left) : node(node_), direction(direction_)
|
|
{
|
|
}
|
|
};
|
|
|
|
private:
|
|
TreeNode* fData;
|
|
ParseTree* fLeft;
|
|
ParseTree* fRight;
|
|
std::string fDerivedTable;
|
|
|
|
/**********************************************************************
|
|
* F&E Framework *
|
|
**********************************************************************/
|
|
|
|
public:
|
|
inline const utils::NullString& getStrVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getStrVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getStrVal(row, isNull);
|
|
}
|
|
|
|
inline int64_t getIntVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getIntVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getIntVal(row, isNull);
|
|
}
|
|
|
|
inline uint64_t getUintVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getUintVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getUintVal(row, isNull);
|
|
}
|
|
|
|
inline float getFloatVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getFloatVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getFloatVal(row, isNull);
|
|
}
|
|
|
|
inline double getDoubleVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getDoubleVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getDoubleVal(row, isNull);
|
|
}
|
|
|
|
inline long double getLongDoubleVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getLongDoubleVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getLongDoubleVal(row, isNull);
|
|
}
|
|
|
|
inline IDB_Decimal getDecimalVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getDecimalVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getDecimalVal(row, isNull);
|
|
}
|
|
|
|
inline bool getBoolVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getBoolVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getBoolVal(row, isNull);
|
|
}
|
|
|
|
inline int32_t getDateIntVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getDateIntVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getDateIntVal(row, isNull);
|
|
}
|
|
|
|
inline int64_t getDatetimeIntVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getDatetimeIntVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getDatetimeIntVal(row, isNull);
|
|
}
|
|
|
|
inline int64_t getTimestampIntVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getTimestampIntVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getTimestampIntVal(row, isNull);
|
|
}
|
|
|
|
inline int64_t getTimeIntVal(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
if (fLeft && fRight)
|
|
return (reinterpret_cast<Operator*>(fData))->getTimeIntVal(row, isNull, fLeft, fRight);
|
|
else
|
|
return fData->getTimeIntVal(row, isNull);
|
|
}
|
|
|
|
private:
|
|
/** draw the tree
|
|
*
|
|
* this function is used by draw tree to print out dot file
|
|
*/
|
|
static void draw(const ParseTree* n, std::ostream& dotFile);
|
|
|
|
// F&E framework
|
|
void evaluate(rowgroup::Row& row, bool& isNull);
|
|
};
|
|
|
|
} // namespace execplan
|
|
|
|
#include "operator.h"
|
|
|
|
namespace execplan
|
|
{
|
|
/**
|
|
* Class Definition
|
|
*/
|
|
inline ParseTree::ParseTree() : fData(nullptr), fLeft(nullptr), fRight(nullptr), fDerivedTable("")
|
|
{
|
|
}
|
|
|
|
inline ParseTree::ParseTree(TreeNode* data) : fData(data), fLeft(nullptr), fRight(nullptr)
|
|
{
|
|
// bug5984. Need to validate data to be not null
|
|
if (data)
|
|
fDerivedTable = data->derivedTable();
|
|
}
|
|
|
|
inline ParseTree::ParseTree(TreeNode* data, ParseTree* left, ParseTree* right)
|
|
: fData(data), fLeft(left), fRight(right)
|
|
{
|
|
if (data)
|
|
fDerivedTable = data->derivedTable();
|
|
}
|
|
|
|
inline ParseTree::ParseTree(const ParseTree& rhs)
|
|
: fData(nullptr), fLeft(nullptr), fRight(nullptr), fDerivedTable(rhs.fDerivedTable)
|
|
{
|
|
copyTree(rhs);
|
|
}
|
|
|
|
using DFSStack = std::vector<ParseTree::StackFrame>;
|
|
|
|
inline ParseTree::~ParseTree()
|
|
{
|
|
if (fLeft == nullptr && fRight == nullptr)
|
|
{
|
|
delete fData;
|
|
fData = nullptr;
|
|
}
|
|
else
|
|
{
|
|
DFSStack stack;
|
|
stack.emplace_back(this);
|
|
while (!stack.empty())
|
|
{
|
|
auto [node, dir] = stack.back();
|
|
if (dir == GoTo::Left)
|
|
{
|
|
stack.back().direction = GoTo::Right;
|
|
if (node->fLeft != nullptr)
|
|
{
|
|
stack.emplace_back(node->fLeft);
|
|
}
|
|
}
|
|
else if (dir == GoTo::Right)
|
|
{
|
|
stack.back().direction = GoTo::Up;
|
|
if (node->fRight != nullptr)
|
|
{
|
|
stack.emplace_back(node->fRight);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (stack.size() == 1)
|
|
{
|
|
node->fLeft = nullptr;
|
|
node->fRight = nullptr;
|
|
delete fData;
|
|
fData = nullptr;
|
|
stack.pop_back();
|
|
}
|
|
else
|
|
{
|
|
node->fLeft = nullptr;
|
|
node->fRight = nullptr;
|
|
delete node;
|
|
stack.pop_back();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void ParseTree::walk(void (*fn)(ParseTree* n)) const
|
|
{
|
|
DFSStack stack;
|
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
|
|
|
while (!stack.empty())
|
|
{
|
|
auto [node, dir] = stack.back();
|
|
if (dir == GoTo::Left)
|
|
{
|
|
stack.back().direction = GoTo::Right;
|
|
if (node->fLeft != nullptr)
|
|
stack.emplace_back(node->fLeft);
|
|
}
|
|
else if (dir == GoTo::Right)
|
|
{
|
|
stack.back().direction = GoTo::Up;
|
|
if (node->fRight != nullptr)
|
|
stack.emplace_back(node->fRight);
|
|
}
|
|
else
|
|
{
|
|
ParseTree* temp = const_cast<ParseTree*>(node);
|
|
fn(temp);
|
|
stack.pop_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void ParseTree::walk(void (*fn)(const ParseTree* n)) const
|
|
{
|
|
DFSStack stack;
|
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
|
|
|
while (!stack.empty())
|
|
{
|
|
auto [node, dir] = stack.back();
|
|
if (dir == GoTo::Left)
|
|
{
|
|
stack.back().direction = GoTo::Right;
|
|
if (node->fLeft != nullptr)
|
|
stack.emplace_back(node->fLeft);
|
|
}
|
|
else if (dir == GoTo::Right)
|
|
{
|
|
stack.back().direction = GoTo::Up;
|
|
if (node->fRight != nullptr)
|
|
stack.emplace_back(node->fRight);
|
|
}
|
|
else
|
|
{
|
|
ParseTree* temp = const_cast<ParseTree*>(node);
|
|
fn(temp);
|
|
stack.pop_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void ParseTree::walk(void (*fn)(const ParseTree* n, std::ostream& output), std::ostream& output) const
|
|
{
|
|
DFSStack stack;
|
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
|
|
|
while (!stack.empty())
|
|
{
|
|
auto [node, dir] = stack.back();
|
|
if (dir == GoTo::Left)
|
|
{
|
|
stack.back().direction = GoTo::Right;
|
|
if (node->fLeft != nullptr)
|
|
stack.emplace_back(node->fLeft);
|
|
}
|
|
else if (dir == GoTo::Right)
|
|
{
|
|
stack.back().direction = GoTo::Up;
|
|
if (node->fRight != nullptr)
|
|
stack.emplace_back(node->fRight);
|
|
}
|
|
else
|
|
{
|
|
ParseTree* temp = const_cast<ParseTree*>(node);
|
|
fn(temp, output);
|
|
stack.pop_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void ParseTree::walk(void (*fn)(const ParseTree* n, void* obj), void* obj) const
|
|
{
|
|
DFSStack stack;
|
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
|
|
|
while (!stack.empty())
|
|
{
|
|
auto [node, dir] = stack.back();
|
|
if (dir == GoTo::Left)
|
|
{
|
|
stack.back().direction = GoTo::Right;
|
|
if (node->fLeft != nullptr)
|
|
stack.emplace_back(node->fLeft);
|
|
}
|
|
else if (dir == GoTo::Right)
|
|
{
|
|
stack.back().direction = GoTo::Up;
|
|
if (node->fRight != nullptr)
|
|
stack.emplace_back(node->fRight);
|
|
}
|
|
else
|
|
{
|
|
ParseTree* temp = const_cast<ParseTree*>(node);
|
|
fn(temp, obj);
|
|
stack.pop_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline std::string ParseTree::toString() const
|
|
{
|
|
std::ostringstream oss;
|
|
walk(ParseTree::print, oss);
|
|
return oss.str();
|
|
}
|
|
|
|
inline void ParseTree::walk(void (*fn)(ParseTree* n, void* obj), void* obj) const
|
|
{
|
|
DFSStack stack;
|
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
|
|
|
while (!stack.empty())
|
|
{
|
|
auto [node, dir] = stack.back();
|
|
if (dir == GoTo::Left)
|
|
{
|
|
stack.back().direction = GoTo::Right;
|
|
if (node->fLeft != nullptr)
|
|
stack.emplace_back(node->fLeft);
|
|
}
|
|
else if (dir == GoTo::Right)
|
|
{
|
|
stack.back().direction = GoTo::Up;
|
|
if (node->fRight != nullptr)
|
|
stack.emplace_back(node->fRight);
|
|
}
|
|
else
|
|
{
|
|
ParseTree* temp = const_cast<ParseTree*>(node);
|
|
fn(temp, obj);
|
|
stack.pop_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline ParseTree& ParseTree::operator=(const ParseTree& rhs)
|
|
{
|
|
if (this != &rhs)
|
|
{
|
|
// copyTree(*this, rhs);
|
|
copyTree(rhs);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
inline void ParseTree::copyTree(const ParseTree& src)
|
|
{
|
|
if (fLeft != nullptr)
|
|
delete fLeft;
|
|
|
|
if (fRight != nullptr)
|
|
delete fRight;
|
|
|
|
fLeft = nullptr;
|
|
fRight = nullptr;
|
|
|
|
if (src.left() != nullptr)
|
|
{
|
|
fLeft = new ParseTree();
|
|
fLeft->copyTree(*(src.left()));
|
|
}
|
|
|
|
if (src.right() != nullptr)
|
|
{
|
|
fRight = new ParseTree();
|
|
fRight->copyTree(*(src.right()));
|
|
}
|
|
|
|
delete fData;
|
|
|
|
if (src.data() == nullptr)
|
|
fData = nullptr;
|
|
else
|
|
fData = src.data()->clone();
|
|
}
|
|
|
|
inline void ParseTree::destroyTree(ParseTree* root)
|
|
{
|
|
if (root == nullptr)
|
|
return;
|
|
|
|
if (root->left() != nullptr)
|
|
{
|
|
destroyTree(root->fLeft);
|
|
}
|
|
|
|
if (root->right() != nullptr)
|
|
{
|
|
destroyTree(root->fRight);
|
|
}
|
|
|
|
delete root;
|
|
root = nullptr;
|
|
}
|
|
|
|
inline void ParseTree::draw(const ParseTree* n, std::ostream& dotFile)
|
|
{
|
|
const ParseTree* r;
|
|
const ParseTree* l;
|
|
l = n->left();
|
|
r = n->right();
|
|
|
|
if (l != nullptr)
|
|
dotFile << "n" << (void*)n << " -> " << "n" << (void*)l << std::endl;
|
|
|
|
if (r != nullptr)
|
|
dotFile << "n" << (void*)n << " -> " << "n" << (void*)r << std::endl;
|
|
|
|
auto& node = *(n->data());
|
|
dotFile << "n" << (void*)n << " [label=\"" << n->data()->data() << " (" << n << ") "
|
|
<< boost::core::demangle(typeid(node).name()) << "\"]" << std::endl;
|
|
}
|
|
|
|
inline void ParseTree::drawTree(std::string filename)
|
|
{
|
|
std::ofstream dotFile(filename.c_str(), std::ios::out);
|
|
|
|
dotFile << "digraph G {" << std::endl;
|
|
walk(draw, dotFile);
|
|
dotFile << "}" << std::endl;
|
|
|
|
dotFile.close();
|
|
}
|
|
|
|
inline string ParseTree::toCppCode(IncludeSet& includes) const
|
|
{
|
|
includes.insert("parsetree.h");
|
|
std::stringstream ss;
|
|
ss << "ParseTree(" << (data() ? ("new " + data()->toCppCode(includes)) : "nullptr") << ", "
|
|
<< (left() ? ("new " + left()->toCppCode(includes)) : "nullptr") << ", "
|
|
<< (right() ? ("new " + right()->toCppCode(includes)) : "nullptr") << ")";
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
inline void ParseTree::codeToFile(std::string filename, std::string varname) const
|
|
{
|
|
ofstream hFile(filename.c_str(), std::ios::app);
|
|
IncludeSet includes;
|
|
auto result = toCppCode(includes);
|
|
for (const auto& inc : includes)
|
|
hFile << "#include \"" << inc << "\"\n";
|
|
hFile << "\n";
|
|
hFile << "namespace execplan \n{ auto " << varname << " = new " << result << ";\n}\n\n";
|
|
|
|
hFile.close();
|
|
}
|
|
|
|
inline void ParseTree::evaluate(rowgroup::Row& row, bool& isNull)
|
|
{
|
|
// Non-leaf node is operator. leaf node is SimpleFilter for logical expression,
|
|
// or ReturnedColumn for arithmetical expression.
|
|
if (fLeft && fRight)
|
|
{
|
|
Operator* op = reinterpret_cast<Operator*>(fData);
|
|
op->evaluate(row, isNull, fLeft, fRight);
|
|
}
|
|
else
|
|
{
|
|
fData->evaluate(row, isNull);
|
|
}
|
|
}
|
|
|
|
inline void ParseTree::setDerivedTable()
|
|
{
|
|
std::string lDerivedTable = "";
|
|
std::string rDerivedTable = "";
|
|
|
|
if (fLeft)
|
|
{
|
|
fLeft->setDerivedTable();
|
|
lDerivedTable = fLeft->derivedTable();
|
|
}
|
|
else
|
|
{
|
|
lDerivedTable = "*";
|
|
}
|
|
|
|
if (fRight)
|
|
{
|
|
fRight->setDerivedTable();
|
|
rDerivedTable = fRight->derivedTable();
|
|
}
|
|
else
|
|
{
|
|
rDerivedTable = "*";
|
|
}
|
|
|
|
Operator* op = dynamic_cast<Operator*>(fData);
|
|
|
|
if (op)
|
|
{
|
|
if (lDerivedTable == "*")
|
|
{
|
|
fDerivedTable = rDerivedTable;
|
|
}
|
|
else if (rDerivedTable == "*")
|
|
{
|
|
fDerivedTable = lDerivedTable;
|
|
}
|
|
else if (lDerivedTable == rDerivedTable)
|
|
{
|
|
fDerivedTable = lDerivedTable; // should be the same as rhs
|
|
}
|
|
else
|
|
{
|
|
fDerivedTable = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fData->setDerivedTable();
|
|
fDerivedTable = fData->derivedTable();
|
|
fDerivedTable = fData->derivedTable();
|
|
}
|
|
}
|
|
|
|
typedef boost::shared_ptr<ParseTree> SPTP;
|
|
|
|
} // namespace execplan
|