You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-11-03 17:13:17 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			796 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			796 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
 | 
						|
{
 | 
						|
 | 
						|
using ParseTreeWalker = void (*)(ParseTree* n);
 | 
						|
using ParseTreeConstWalker = void (*)(const ParseTree* n);
 | 
						|
 | 
						|
using ParseTreePrinter = void (*)(const ParseTree* n, std::ostream& output);
 | 
						|
 | 
						|
using ParseTreeWalkerWithContext = void (*)(ParseTree* n, void* obj);
 | 
						|
using ParseTreeConstWalkerWithContext = void (*)(const ParseTree* n, void* obj);
 | 
						|
// class ParseTree;
 | 
						|
/**
 | 
						|
 * @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(ParseTreeWalker fn) const;
 | 
						|
 | 
						|
  /** walk the tree
 | 
						|
   *
 | 
						|
   * postfix walking of a non-const tree. This is for deleting the tree
 | 
						|
   */
 | 
						|
  inline void walk(ParseTreeConstWalker fn) const;
 | 
						|
 | 
						|
  /** output the tree
 | 
						|
   *
 | 
						|
   * take ostream argument to walk and output the tree
 | 
						|
   */
 | 
						|
  inline void walk(ParseTreePrinter fn, std::ostream& output) const;
 | 
						|
 | 
						|
  /** output the tree
 | 
						|
   *
 | 
						|
   * take user argument to walk and output the tree
 | 
						|
   */
 | 
						|
  inline void walk(ParseTreeConstWalkerWithContext fn, void* object) const;
 | 
						|
 | 
						|
  /** output the tree
 | 
						|
   *
 | 
						|
   * take user argument to walk and output the tree
 | 
						|
   */
 | 
						|
  inline void walk(ParseTreeWalkerWithContext fn, 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(ParseTreeWalker fn) 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(ParseTreeConstWalker fn) 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(ParseTreePrinter fn, 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(ParseTreeConstWalkerWithContext fn, 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(ParseTreeWalkerWithContext fn, 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(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 std::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
 | 
						|
{
 | 
						|
  std::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
 |