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
Replace recursion with iteration in ParseTree (and some related walkers)
This commit is contained in:
@ -195,33 +195,102 @@ void ObjectReader::writeParseTree(const ParseTree* tree, messageqcpp::ByteStream
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
b << (id_t)PARSETREE;
|
DFSStack stack;
|
||||||
writeParseTree(tree->left(), b);
|
stack.emplace_back(const_cast<ParseTree*>(tree));
|
||||||
writeParseTree(tree->right(), b);
|
while (!stack.empty())
|
||||||
|
{
|
||||||
if (tree->data() == NULL)
|
auto [node, dir] = stack.back();
|
||||||
b << (id_t)NULL_CLASS;
|
if (node == NULL)
|
||||||
else
|
{
|
||||||
tree->data()->serialize(b);
|
b << (id_t)NULL_CLASS;
|
||||||
|
stack.pop_back();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dir == ParseTree::GoTo::Left)
|
||||||
|
{
|
||||||
|
b << (id_t)PARSETREE;
|
||||||
|
stack.back().direction = ParseTree::GoTo::Right;
|
||||||
|
stack.emplace_back(node->left());
|
||||||
|
}
|
||||||
|
else if (dir == ParseTree::GoTo::Right)
|
||||||
|
{
|
||||||
|
stack.back().direction = ParseTree::GoTo::Up;
|
||||||
|
stack.emplace_back(node->right());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (node->data() == NULL)
|
||||||
|
b << (id_t)NULL_CLASS;
|
||||||
|
else
|
||||||
|
node->data()->serialize(b);
|
||||||
|
stack.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseTree* ObjectReader::createParseTree(messageqcpp::ByteStream& b)
|
ParseTree* ObjectReader::createParseTree(messageqcpp::ByteStream& b)
|
||||||
{
|
{
|
||||||
CLASSID id = ZERO;
|
CLASSID id = ZERO;
|
||||||
ParseTree* ret;
|
ParseTree* ret;
|
||||||
|
DFSStack stack;
|
||||||
b >> (id_t&)id;
|
b >> (id_t&)id;
|
||||||
|
|
||||||
if (id == NULL_CLASS)
|
if (id == NULL_CLASS)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (id != PARSETREE)
|
if (id != PARSETREE)
|
||||||
throw UnserializeException("Not a ParseTree");
|
throw UnserializeException("Not a ParseTree");
|
||||||
|
|
||||||
ret = new ParseTree();
|
ret = new ParseTree();
|
||||||
ret->left(createParseTree(b));
|
stack.emplace_back(ret);
|
||||||
ret->right(createParseTree(b));
|
while (!stack.empty())
|
||||||
ret->data(createTreeNode(b));
|
{
|
||||||
|
auto [node, dir] = stack.back();
|
||||||
|
if (dir == ParseTree::GoTo::Left)
|
||||||
|
{
|
||||||
|
id = ZERO;
|
||||||
|
ParseTree* cur = NULL;
|
||||||
|
b >> (id_t&)id;
|
||||||
|
|
||||||
|
if (id == NULL_CLASS)
|
||||||
|
{
|
||||||
|
stack.back().node->left(cur);
|
||||||
|
stack.back().direction = ParseTree::GoTo::Right;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (id != PARSETREE)
|
||||||
|
throw UnserializeException("Not a ParseTree");
|
||||||
|
|
||||||
|
cur = new ParseTree();
|
||||||
|
stack.back().direction = ParseTree::GoTo::Right;
|
||||||
|
stack.back().node->left(cur);
|
||||||
|
stack.emplace_back(node->left());
|
||||||
|
}
|
||||||
|
else if (dir == ParseTree::GoTo::Right)
|
||||||
|
{
|
||||||
|
id = ZERO;
|
||||||
|
ParseTree* cur = NULL;
|
||||||
|
b >> (id_t&)id;
|
||||||
|
|
||||||
|
if (id == NULL_CLASS)
|
||||||
|
{
|
||||||
|
stack.back().node->right(cur);
|
||||||
|
stack.back().direction = ParseTree::GoTo::Up;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (id != PARSETREE)
|
||||||
|
throw UnserializeException("Not a ParseTree");
|
||||||
|
|
||||||
|
cur = new ParseTree();
|
||||||
|
stack.back().direction = ParseTree::GoTo::Up;
|
||||||
|
stack.back().node->right(cur);
|
||||||
|
stack.emplace_back(node->right());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack.back().node->data(createTreeNode(b));
|
||||||
|
stack.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +227,22 @@ class ParseTree
|
|||||||
|
|
||||||
inline void setDerivedTable();
|
inline void setDerivedTable();
|
||||||
|
|
||||||
|
enum class GoTo
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Up
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StackFrame
|
||||||
|
{
|
||||||
|
ParseTree* node;
|
||||||
|
GoTo direction;
|
||||||
|
StackFrame(ParseTree* node_, GoTo direction_ = GoTo::Left) : node(node_), direction(direction_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TreeNode* fData;
|
TreeNode* fData;
|
||||||
ParseTree* fLeft;
|
ParseTree* fLeft;
|
||||||
@ -378,65 +394,174 @@ inline ParseTree::ParseTree(const ParseTree& rhs)
|
|||||||
copyTree(rhs);
|
copyTree(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using DFSStack = std::vector<ParseTree::StackFrame>;
|
||||||
|
|
||||||
inline ParseTree::~ParseTree()
|
inline ParseTree::~ParseTree()
|
||||||
{
|
{
|
||||||
if (fLeft != NULL)
|
if (fLeft == nullptr && fRight == nullptr)
|
||||||
delete fLeft;
|
{
|
||||||
|
|
||||||
if (fRight != NULL)
|
|
||||||
delete fRight;
|
|
||||||
|
|
||||||
if (fData != NULL)
|
|
||||||
delete fData;
|
delete fData;
|
||||||
|
fData = nullptr;
|
||||||
fLeft = NULL;
|
}
|
||||||
fRight = NULL;
|
else
|
||||||
fData = NULL;
|
{
|
||||||
|
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
|
inline void ParseTree::walk(void (*fn)(ParseTree* n)) const
|
||||||
{
|
{
|
||||||
if (fLeft != 0)
|
DFSStack stack;
|
||||||
fLeft->walk(fn);
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
||||||
|
|
||||||
if (fRight != 0)
|
while (!stack.empty())
|
||||||
fRight->walk(fn);
|
{
|
||||||
|
auto [node, dir] = stack.back();
|
||||||
ParseTree* temp = const_cast<ParseTree*>(this);
|
if (dir == GoTo::Left)
|
||||||
fn(temp);
|
{
|
||||||
|
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
|
inline void ParseTree::walk(void (*fn)(const ParseTree* n)) const
|
||||||
{
|
{
|
||||||
if (fLeft != 0)
|
DFSStack stack;
|
||||||
fLeft->walk(fn);
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
||||||
|
|
||||||
if (fRight != 0)
|
while (!stack.empty())
|
||||||
fRight->walk(fn);
|
{
|
||||||
|
auto [node, dir] = stack.back();
|
||||||
fn(this);
|
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
|
inline void ParseTree::walk(void (*fn)(const ParseTree* n, std::ostream& output), std::ostream& output) const
|
||||||
{
|
{
|
||||||
if (fLeft != 0)
|
DFSStack stack;
|
||||||
fLeft->walk(fn, output);
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
||||||
|
|
||||||
if (fRight != 0)
|
while (!stack.empty())
|
||||||
fRight->walk(fn, output);
|
{
|
||||||
|
auto [node, dir] = stack.back();
|
||||||
fn(this, output);
|
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
|
inline void ParseTree::walk(void (*fn)(const ParseTree* n, void* obj), void* obj) const
|
||||||
{
|
{
|
||||||
if (fLeft != 0)
|
DFSStack stack;
|
||||||
fLeft->walk(fn, obj);
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
||||||
|
|
||||||
if (fRight != 0)
|
while (!stack.empty())
|
||||||
fRight->walk(fn, obj);
|
{
|
||||||
|
auto [node, dir] = stack.back();
|
||||||
fn(this, obj);
|
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
|
inline std::string ParseTree::toString() const
|
||||||
@ -448,13 +573,31 @@ inline std::string ParseTree::toString() const
|
|||||||
|
|
||||||
inline void ParseTree::walk(void (*fn)(ParseTree* n, void* obj), void* obj) const
|
inline void ParseTree::walk(void (*fn)(ParseTree* n, void* obj), void* obj) const
|
||||||
{
|
{
|
||||||
if (fLeft != 0)
|
DFSStack stack;
|
||||||
fLeft->walk(fn, obj);
|
stack.emplace_back(const_cast<ParseTree*>(this));
|
||||||
|
|
||||||
if (fRight != 0)
|
while (!stack.empty())
|
||||||
fRight->walk(fn, obj);
|
{
|
||||||
|
auto [node, dir] = stack.back();
|
||||||
fn(const_cast<ParseTree*>(this), obj);
|
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)
|
inline ParseTree& ParseTree::operator=(const ParseTree& rhs)
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "rewrites.h"
|
#include "rewrites.h"
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include "objectreader.h"
|
#include "objectreader.h"
|
||||||
@ -42,7 +40,6 @@ void printContainer(std::ostream& os, const T& container, const std::string& del
|
|||||||
os << std::endl;
|
os << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using CommonContainer =
|
using CommonContainer =
|
||||||
std::pair<std::set<execplan::ParseTree*, NodeSemanticComparator>, std::set<execplan::ParseTree*>>;
|
std::pair<std::set<execplan::ParseTree*, NodeSemanticComparator>, std::set<execplan::ParseTree*>>;
|
||||||
|
|
||||||
@ -110,44 +107,104 @@ bool simpleFiltersCmp(const SimpleFilter* left, const SimpleFilter* right)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Walk the tree and find out common conjuctions
|
// Walk the tree and find out common conjuctions
|
||||||
void collectCommonConjuctions(execplan::ParseTree* root, CommonContainer& accumulator, int level = 0,
|
struct StackFrameWithSet
|
||||||
bool orMeeted = false, bool andParent = false)
|
{
|
||||||
|
execplan::ParseTree* node;
|
||||||
|
ParseTree::GoTo direction;
|
||||||
|
bool orMet;
|
||||||
|
bool andParent;
|
||||||
|
CommonContainer localset;
|
||||||
|
StackFrameWithSet(execplan::ParseTree* node_, ParseTree::GoTo direction_, bool orMet_ = false, bool andParent_ = false)
|
||||||
|
: node(node_), direction(direction_), orMet(orMet_), andParent(andParent_), localset({{}, {}})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void advanceSetUp(std::vector<StackFrameWithSet>& stack, CommonContainer& accumulator)
|
||||||
|
{
|
||||||
|
if (stack.size() == 1)
|
||||||
|
accumulator = stack.back().localset;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto sz = stack.size();
|
||||||
|
if (operatorType(stack.at(sz - 2).node) == OP_OR)
|
||||||
|
{
|
||||||
|
if (stack.at(sz - 2).direction == ParseTree::GoTo::Right)
|
||||||
|
stack[sz - 2].localset = stack.back().localset;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CommonContainer intsersection;
|
||||||
|
std::set_intersection(stack[sz - 2].localset.first.begin(), stack[sz - 2].localset.first.end(),
|
||||||
|
stack.back().localset.first.begin(), stack.back().localset.first.end(),
|
||||||
|
std::inserter(intsersection.first, intsersection.first.begin()),
|
||||||
|
NodeSemanticComparator{});
|
||||||
|
stack[sz - 2].localset.first = intsersection.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (stack.at(sz - 2).direction == ParseTree::GoTo::Right)
|
||||||
|
stack[sz - 2].localset = stack.back().localset;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::set_union(stack[sz - 2].localset.first.begin(), stack[sz - 2].localset.first.end(),
|
||||||
|
stack.back().localset.first.begin(), stack.back().localset.first.end(),
|
||||||
|
std::inserter(stack[sz - 2].localset.first, stack[sz - 2].localset.first.begin()),
|
||||||
|
NodeSemanticComparator{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void collectCommonConjuctions(execplan::ParseTree* root, CommonContainer& accumulator)
|
||||||
{
|
{
|
||||||
if (root == nullptr)
|
if (root == nullptr)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printTreeLevel(root, level);
|
std::vector<StackFrameWithSet> stack;
|
||||||
// the condition below means leaf node
|
stack.emplace_back(root, ParseTree::GoTo::Left);
|
||||||
if (root->left() == nullptr && root->right() == nullptr && orMeeted && andParent)
|
while (!stack.empty())
|
||||||
{
|
{
|
||||||
// we want to collect it if it is a child of and node and or node was met before
|
auto [node, dir, orMet, andParent, localset] = stack.back();
|
||||||
if (castToFilter(root))
|
|
||||||
|
if (dir == ParseTree::GoTo::Left)
|
||||||
{
|
{
|
||||||
accumulator.first.insert(root);
|
stack.back().direction = ParseTree::GoTo::Right;
|
||||||
|
if (node->left() != nullptr)
|
||||||
|
{
|
||||||
|
if (operatorType(node) == OP_OR)
|
||||||
|
stack.emplace_back(node->left(), ParseTree::GoTo::Left, true);
|
||||||
|
else
|
||||||
|
stack.emplace_back(node->left(), ParseTree::GoTo::Left, orMet, operatorType(node) == OP_AND);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (dir == ParseTree::GoTo::Right)
|
||||||
|
{
|
||||||
|
stack.back().direction = ParseTree::GoTo::Up;
|
||||||
|
if (node->right() != nullptr)
|
||||||
|
{
|
||||||
|
if (operatorType(node) == OP_OR)
|
||||||
|
stack.emplace_back(node->right(), ParseTree::GoTo::Left, true);
|
||||||
|
else
|
||||||
|
stack.emplace_back(node->right(), ParseTree::GoTo::Left, orMet, operatorType(node) == OP_AND);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (node->left() == nullptr && node->right() == nullptr && orMet && andParent)
|
||||||
|
{
|
||||||
|
if (castToFilter(node))
|
||||||
|
stack.back().localset.first.insert(node);
|
||||||
|
}
|
||||||
|
advanceSetUp(stack, accumulator);
|
||||||
|
stack.pop_back();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// we do set intersection for all the lower levels for the or node
|
|
||||||
if (operatorType(root) == OP_OR)
|
|
||||||
{
|
|
||||||
CommonContainer leftAcc;
|
|
||||||
CommonContainer rightAcc;
|
|
||||||
collectCommonConjuctions(root->left(), leftAcc, ++level, true, false);
|
|
||||||
collectCommonConjuctions(root->right(), rightAcc, ++level, true, false);
|
|
||||||
CommonContainer intersection;
|
|
||||||
std::set_intersection(leftAcc.first.begin(), leftAcc.first.end(), rightAcc.first.begin(),
|
|
||||||
rightAcc.first.end(), std::inserter(intersection.first, intersection.first.begin()),
|
|
||||||
NodeSemanticComparator{});
|
|
||||||
|
|
||||||
accumulator = intersection;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
collectCommonConjuctions(root->left(), accumulator, ++level, orMeeted, operatorType(root) == OP_AND);
|
|
||||||
collectCommonConjuctions(root->right(), accumulator, ++level, orMeeted, operatorType(root) == OP_AND);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this utility function creates new and node
|
// this utility function creates new and node
|
||||||
@ -191,20 +248,13 @@ execplan::ParseTree* appendToRoot(execplan::ParseTree* tree, const Common& commo
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class GoTo
|
|
||||||
{
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Up
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StackFrame
|
struct StackFrame
|
||||||
{
|
{
|
||||||
execplan::ParseTree** node;
|
execplan::ParseTree** node;
|
||||||
GoTo direction;
|
ParseTree::GoTo direction;
|
||||||
ChildType containsLeft;
|
ChildType containsLeft;
|
||||||
ChildType containsRight;
|
ChildType containsRight;
|
||||||
StackFrame(execplan::ParseTree** node_, GoTo direction_)
|
StackFrame(execplan::ParseTree** node_, ParseTree::GoTo direction_)
|
||||||
: node(node_), direction(direction_), containsLeft(ChildType::Leave), containsRight(ChildType::Leave)
|
: node(node_), direction(direction_), containsLeft(ChildType::Leave), containsRight(ChildType::Leave)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -231,24 +281,24 @@ void deleteOneNode(execplan::ParseTree** node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this utility function adds one stack frame to a stack for dfs traversal
|
// this utility function adds one stack frame to a stack for dfs traversal
|
||||||
void addStackFrame(DFSStack& stack, GoTo direction, execplan::ParseTree* node)
|
void addStackFrame(DFSStack& stack, ParseTree::GoTo direction, execplan::ParseTree* node)
|
||||||
{
|
{
|
||||||
if (direction == GoTo::Left)
|
if (direction == ParseTree::GoTo::Left)
|
||||||
{
|
{
|
||||||
stack.back().direction = GoTo::Right;
|
stack.back().direction = ParseTree::GoTo::Right;
|
||||||
if (node->left() != nullptr)
|
if (node->left() != nullptr)
|
||||||
{
|
{
|
||||||
auto left = node->leftRef();
|
auto left = node->leftRef();
|
||||||
stack.emplace_back(left, GoTo::Left);
|
stack.emplace_back(left, ParseTree::GoTo::Left);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (direction == GoTo::Right)
|
else if (direction == ParseTree::GoTo::Right)
|
||||||
{
|
{
|
||||||
stack.back().direction = GoTo::Up;
|
stack.back().direction = ParseTree::GoTo::Up;
|
||||||
if (node->right() != nullptr)
|
if (node->right() != nullptr)
|
||||||
{
|
{
|
||||||
auto right = node->rightRef();
|
auto right = node->rightRef();
|
||||||
stack.emplace_back(right, GoTo::Left);
|
stack.emplace_back(right, ParseTree::GoTo::Left);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,7 +308,7 @@ void addStackFrame(DFSStack& stack, GoTo direction, execplan::ParseTree* node)
|
|||||||
// specified in the stack frame
|
// specified in the stack frame
|
||||||
void replaceContainsTypeFlag(StackFrame& stackframe, ChildType containsflag)
|
void replaceContainsTypeFlag(StackFrame& stackframe, ChildType containsflag)
|
||||||
{
|
{
|
||||||
if (stackframe.direction == GoTo::Right)
|
if (stackframe.direction == ParseTree::GoTo::Right)
|
||||||
stackframe.containsLeft = containsflag;
|
stackframe.containsLeft = containsflag;
|
||||||
else
|
else
|
||||||
stackframe.containsRight = containsflag;
|
stackframe.containsRight = containsflag;
|
||||||
@ -270,18 +320,18 @@ void fixUpTree(execplan::ParseTree** node, ChildType ltype, ChildType rtype,
|
|||||||
{
|
{
|
||||||
if (ltype == ChildType::Leave)
|
if (ltype == ChildType::Leave)
|
||||||
{
|
{
|
||||||
if (rtype != ChildType::Leave) // if we don't leave the right node, we replace
|
if (rtype != ChildType::Leave) // if we don't leave the right node, we replace
|
||||||
{ // the parent node with the left child
|
{ // the parent node with the left child
|
||||||
execplan::ParseTree* oldNode = *node;
|
execplan::ParseTree* oldNode = *node;
|
||||||
if (rtype == ChildType::Delete) // we delete the node that is a duplicate
|
if (rtype == ChildType::Delete) // we delete the node that is a duplicate
|
||||||
deleteOneNode((*node)->rightRef()); // of something in the common
|
deleteOneNode((*node)->rightRef()); // of something in the common
|
||||||
*node = (*node)->left();
|
*node = (*node)->left();
|
||||||
deleteOneNode(&oldNode);
|
deleteOneNode(&oldNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ltype == ChildType::Delete) // same as above
|
if (ltype == ChildType::Delete) // same as above
|
||||||
deleteOneNode((*node)->leftRef());
|
deleteOneNode((*node)->leftRef());
|
||||||
if (rtype == ChildType::Leave) // replace the parent with the right child
|
if (rtype == ChildType::Leave) // replace the parent with the right child
|
||||||
{
|
{
|
||||||
@ -310,11 +360,11 @@ void removeFromTreeIterative(execplan::ParseTree** root, const CommonContainer&
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
DFSStack stack;
|
DFSStack stack;
|
||||||
stack.emplace_back(root, GoTo::Left);
|
stack.emplace_back(root, ParseTree::GoTo::Left);
|
||||||
while (!stack.empty())
|
while (!stack.empty())
|
||||||
{
|
{
|
||||||
auto [node, flag, ltype, rtype] = stack.back();
|
auto [node, flag, ltype, rtype] = stack.back();
|
||||||
if (flag != GoTo::Up)
|
if (flag != ParseTree::GoTo::Up)
|
||||||
{
|
{
|
||||||
addStackFrame(stack, flag, *node);
|
addStackFrame(stack, flag, *node);
|
||||||
continue;
|
continue;
|
||||||
@ -418,7 +468,6 @@ execplan::OpType oppositeOperator(execplan::OpType op)
|
|||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template execplan::ParseTree* extractCommonLeafConjunctionsToRoot<false>(execplan::ParseTree* tree);
|
template execplan::ParseTree* extractCommonLeafConjunctionsToRoot<false>(execplan::ParseTree* tree);
|
||||||
template execplan::ParseTree* extractCommonLeafConjunctionsToRoot<true>(execplan::ParseTree* tree);
|
template execplan::ParseTree* extractCommonLeafConjunctionsToRoot<true>(execplan::ParseTree* tree);
|
||||||
|
|
||||||
|
2
mysql-test/columnstore/bugfixes/mcol-5468.result
Normal file
2
mysql-test/columnstore/bugfixes/mcol-5468.result
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
m0
|
||||||
|
0
|
30
mysql-test/columnstore/bugfixes/mcol-5468.test
Normal file
30
mysql-test/columnstore/bugfixes/mcol-5468.test
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user