OmniSciDB  fe05a0c208
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ExpressionRewrite.cpp File Reference
#include "ExpressionRewrite.h"
#include "../Analyzer/Analyzer.h"
#include "../Parser/ParserNode.h"
#include "../Shared/sqldefs.h"
#include "DeepCopyVisitor.h"
#include "Execute.h"
#include "Logger/Logger.h"
#include "RelAlgTranslator.h"
#include "ScalarExprVisitor.h"
#include "WindowExpressionRewrite.h"
#include <boost/locale/conversion.hpp>
#include <unordered_set>
+ Include dependency graph for ExpressionRewrite.cpp:

Go to the source code of this file.

Classes

class  anonymous_namespace{ExpressionRewrite.cpp}::OrToInVisitor
 
class  anonymous_namespace{ExpressionRewrite.cpp}::RecursiveOrToInVisitor
 
class  anonymous_namespace{ExpressionRewrite.cpp}::ArrayElementStringLiteralEncodingVisitor
 
class  anonymous_namespace{ExpressionRewrite.cpp}::ConstantFoldingVisitor
 
class  JoinCoveredQualVisitor
 

Namespaces

 anonymous_namespace{ExpressionRewrite.cpp}
 

Functions

const Analyzer::Expranonymous_namespace{ExpressionRewrite.cpp}::strip_likelihood (const Analyzer::Expr *expr)
 
Analyzer::ExpressionPtr rewrite_array_elements (Analyzer::Expr const *expr)
 
Analyzer::ExpressionPtr rewrite_expr (const Analyzer::Expr *expr)
 
boost::optional
< OverlapsJoinConjunction
rewrite_overlaps_conjunction (const std::shared_ptr< Analyzer::Expr > expr)
 
std::list< std::shared_ptr
< Analyzer::Expr > > 
strip_join_covered_filter_quals (const std::list< std::shared_ptr< Analyzer::Expr >> &quals, const JoinQualsPerNestingLevel &join_quals)
 
std::shared_ptr< Analyzer::Exprfold_expr (const Analyzer::Expr *expr)
 
bool self_join_not_covered_by_left_deep_tree (const Analyzer::ColumnVar *key_side, const Analyzer::ColumnVar *val_side, const int max_rte_covered)
 
const int get_max_rte_scan_table (std::unordered_map< int, llvm::Value * > &scan_idx_to_hash_pos)
 

Variables

static const
std::unordered_set
< std::string > 
anonymous_namespace{ExpressionRewrite.cpp}::overlaps_supported_functions
 
static const
std::unordered_set
< std::string > 
anonymous_namespace{ExpressionRewrite.cpp}::requires_many_to_many
 

Function Documentation

std::shared_ptr<Analyzer::Expr> fold_expr ( const Analyzer::Expr expr)

Definition at line 947 of file ExpressionRewrite.cpp.

References kBIGINT, and anonymous_namespace{ExpressionRewrite.cpp}::strip_likelihood().

Referenced by RelAlgExecutor::createFilterWorkUnit(), anonymous_namespace{RelAlgExecutor.cpp}::set_transient_dict_maybe(), anonymous_namespace{RelAlgExecutor.cpp}::translate_quals(), anonymous_namespace{RelAlgExecutor.cpp}::translate_scalar_sources(), anonymous_namespace{RelAlgExecutor.cpp}::translate_targets(), RelAlgTranslator::translateBinaryGeoFunction(), RelAlgTranslator::translateDatePlusMinus(), and RelAlgTranslator::translateGeoFunctionArg().

947  {
948  if (!expr) {
949  return nullptr;
950  }
951  const auto expr_no_likelihood = strip_likelihood(expr);
952  ConstantFoldingVisitor visitor;
953  auto rewritten_expr = visitor.visit(expr_no_likelihood);
954  if (visitor.get_num_overflows() > 0 && rewritten_expr->get_type_info().is_integer() &&
955  rewritten_expr->get_type_info().get_type() != kBIGINT) {
956  auto rewritten_expr_const =
957  std::dynamic_pointer_cast<const Analyzer::Constant>(rewritten_expr);
958  if (!rewritten_expr_const) {
959  // Integer expression didn't fold completely the first time due to
960  // overflows in smaller type subexpressions, trying again with a cast
961  const auto& ti = SQLTypeInfo(kBIGINT, false);
962  auto bigint_expr_no_likelihood = expr_no_likelihood->deep_copy()->add_cast(ti);
963  auto rewritten_expr_take2 = visitor.visit(bigint_expr_no_likelihood.get());
964  auto rewritten_expr_take2_const =
965  std::dynamic_pointer_cast<Analyzer::Constant>(rewritten_expr_take2);
966  if (rewritten_expr_take2_const) {
967  // Managed to fold, switch to the new constant
968  rewritten_expr = rewritten_expr_take2_const;
969  }
970  }
971  }
972  const auto expr_with_likelihood = dynamic_cast<const Analyzer::LikelihoodExpr*>(expr);
973  if (expr_with_likelihood) {
974  // Add back likelihood
975  return std::make_shared<Analyzer::LikelihoodExpr>(
976  rewritten_expr, expr_with_likelihood->get_likelihood());
977  }
978  return rewritten_expr;
979 }
const Analyzer::Expr * strip_likelihood(const Analyzer::Expr *expr)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

const int get_max_rte_scan_table ( std::unordered_map< int, llvm::Value * > &  scan_idx_to_hash_pos)

Definition at line 992 of file ExpressionRewrite.cpp.

References INT32_MIN.

Referenced by BaselineJoinHashTable::codegenKey(), PerfectJoinHashTable::codegenMatchingSet(), and PerfectJoinHashTable::codegenSlot().

993  {
994  int ret = INT32_MIN;
995  for (auto& kv : scan_idx_to_hash_pos) {
996  if (kv.first > ret) {
997  ret = kv.first;
998  }
999  }
1000  return ret;
1001 }
#define INT32_MIN

+ Here is the caller graph for this function:

Analyzer::ExpressionPtr rewrite_array_elements ( Analyzer::Expr const expr)

Definition at line 697 of file ExpressionRewrite.cpp.

Referenced by anonymous_namespace{RelAlgExecutor.cpp}::translate_scalar_sources(), and anonymous_namespace{RelAlgExecutor.cpp}::translate_scalar_sources_for_update().

697  {
698  return ArrayElementStringLiteralEncodingVisitor().visit(expr);
699 }

+ Here is the caller graph for this function:

Analyzer::ExpressionPtr rewrite_expr ( const Analyzer::Expr expr)

Definition at line 701 of file ExpressionRewrite.cpp.

References rewrite_avg_window(), rewrite_sum_window(), and anonymous_namespace{ExpressionRewrite.cpp}::strip_likelihood().

Referenced by RelAlgExecutor::createFilterWorkUnit(), qual_to_conjunctive_form(), qual_to_disjunctive_form(), anonymous_namespace{RelAlgExecutor.cpp}::rewrite_quals(), QueryRewriter::rewriteConstrainedByIn(), anonymous_namespace{RelAlgExecutor.cpp}::translate_scalar_sources(), anonymous_namespace{RelAlgExecutor.cpp}::translate_scalar_sources_for_update(), and anonymous_namespace{RelAlgExecutor.cpp}::translate_targets().

701  {
702  const auto sum_window = rewrite_sum_window(expr);
703  if (sum_window) {
704  return sum_window;
705  }
706  const auto avg_window = rewrite_avg_window(expr);
707  if (avg_window) {
708  return avg_window;
709  }
710  const auto expr_no_likelihood = strip_likelihood(expr);
711  // The following check is not strictly needed, but seems silly to transform a
712  // simple string comparison to an IN just to codegen the same thing anyway.
713 
714  RecursiveOrToInVisitor visitor;
715  auto rewritten_expr = visitor.visit(expr_no_likelihood);
716  const auto expr_with_likelihood =
717  std::dynamic_pointer_cast<const Analyzer::LikelihoodExpr>(rewritten_expr);
718  if (expr_with_likelihood) {
719  // Add back likelihood
720  return std::make_shared<Analyzer::LikelihoodExpr>(
721  rewritten_expr, expr_with_likelihood->get_likelihood());
722  }
723  return rewritten_expr;
724 }
std::shared_ptr< Analyzer::WindowFunction > rewrite_avg_window(const Analyzer::Expr *expr)
std::shared_ptr< Analyzer::WindowFunction > rewrite_sum_window(const Analyzer::Expr *expr)
const Analyzer::Expr * strip_likelihood(const Analyzer::Expr *expr)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

boost::optional<OverlapsJoinConjunction> rewrite_overlaps_conjunction ( const std::shared_ptr< Analyzer::Expr expr)

Definition at line 758 of file ExpressionRewrite.cpp.

References CHECK, CHECK_GE, g_enable_hashjoin_many_to_many, logger::INFO, is_constructed_point(), kBOOLEAN, kONE, kOVERLAPS, LOG, anonymous_namespace{ExpressionRewrite.cpp}::overlaps_supported_functions, anonymous_namespace{ExpressionRewrite.cpp}::requires_many_to_many, ScalarExprVisitor< T >::visit(), VLOG, and logger::WARNING.

Referenced by QueryRewriter::rewriteOverlapsJoin().

759  {
760  auto func_oper = dynamic_cast<Analyzer::FunctionOper*>(expr.get());
761  if (func_oper) {
762  const auto needs_many_many = [func_oper]() {
763  return requires_many_to_many.find(func_oper->getName()) !=
764  requires_many_to_many.end();
765  };
766  // TODO(adb): consider converting unordered set to an unordered map, potentially
767  // storing the rewrite function we want to apply in the map
768  if (overlaps_supported_functions.find(func_oper->getName()) !=
770  if (!g_enable_hashjoin_many_to_many && needs_many_many()) {
771  LOG(WARNING) << "Many-to-many hashjoin support is disabled, unable to rewrite "
772  << func_oper->toString() << " to use accelerated geo join.";
773  return boost::none;
774  }
775 
776  DeepCopyVisitor deep_copy_visitor;
777  if (func_oper->getName() == "ST_Overlaps") {
778  CHECK_GE(func_oper->getArity(), size_t(2));
779  // return empty quals, overlaps join quals
780  // TODO(adb): we will likely want to actually check for true overlaps, but this
781  // works for now
782 
783  auto lhs = func_oper->getOwnArg(0);
784  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
785  CHECK(rewritten_lhs);
786 
787  auto rhs = func_oper->getOwnArg(1);
788  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
789  CHECK(rewritten_rhs);
790 
791  auto overlaps_oper = makeExpr<Analyzer::BinOper>(
792  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
793  return OverlapsJoinConjunction{{}, {overlaps_oper}};
794  }
795 
796  // TODO(jclay): This will work for Poly_Poly,but needs to change for others.
797  CHECK_GE(func_oper->getArity(), size_t(4));
798  if (func_oper->getName() == "ST_Contains_Polygon_Polygon" ||
799  func_oper->getName() == "ST_Intersects_Polygon_Polygon" ||
800  func_oper->getName() == "ST_Intersects_MultiPolygon_MultiPolygon" ||
801  func_oper->getName() == "ST_Intersects_MultiPolygon_Polygon" ||
802  func_oper->getName() == "ST_Intersects_Polygon_MultiPolygon") {
803  auto lhs = func_oper->getOwnArg(3);
804  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
805  CHECK(rewritten_lhs);
806  auto rhs = func_oper->getOwnArg(1);
807  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
808  CHECK(rewritten_rhs);
809 
810  auto overlaps_oper = makeExpr<Analyzer::BinOper>(
811  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
812 
813  VLOG(1) << "Successfully converted to overlaps join";
814  return OverlapsJoinConjunction{{expr}, {overlaps_oper}};
815  }
816 
817  auto lhs = func_oper->getOwnArg(2);
818  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
819  CHECK(rewritten_lhs);
820  const auto& lhs_ti = rewritten_lhs->get_type_info();
821 
822  if (!lhs_ti.is_geometry() && !is_constructed_point(rewritten_lhs.get())) {
823  // TODO(adb): If ST_Contains is passed geospatial literals instead of columns, the
824  // function will be expanded during translation rather than during code
825  // generation. While this scenario does not make sense for the overlaps join, we
826  // need to detect and abort the overlaps rewrite. Adding a GeospatialConstant
827  // dervied class to the Analyzer may prove to be a better way to handle geo
828  // literals, but for now we ensure the LHS type is a geospatial type, which would
829  // mean the function has not been expanded to the physical types, yet.
830 
831  LOG(INFO) << "Unable to rewrite " << func_oper->getName()
832  << " to overlaps conjunction. LHS input type is neither a geospatial "
833  "column nor a constructed point\n"
834  << func_oper->toString();
835 
836  return boost::none;
837  }
838 
839  // Read the bounds arg from the ST_Contains FuncOper (second argument)instead of the
840  // poly column (first argument)
841  auto rhs = func_oper->getOwnArg(1);
842  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
843  CHECK(rewritten_rhs);
844 
845  // Check for compatible join ordering. If the join ordering does not match expected
846  // ordering for overlaps, the join builder will fail.
847  std::set<int> lhs_rte_idx;
848  lhs->collect_rte_idx(lhs_rte_idx);
849  CHECK(!lhs_rte_idx.empty());
850  std::set<int> rhs_rte_idx;
851  rhs->collect_rte_idx(rhs_rte_idx);
852  CHECK(!rhs_rte_idx.empty());
853 
854  if (lhs_rte_idx.size() > 1 || rhs_rte_idx.size() > 1 || lhs_rte_idx > rhs_rte_idx) {
855  LOG(INFO) << "Unable to rewrite " << func_oper->getName()
856  << " to overlaps conjunction. Cannot build hash table over LHS type. "
857  "Check join order.\n"
858  << func_oper->toString();
859  return boost::none;
860  }
861 
862  VLOG(1) << "Rewritten to use overlaps join with lhs as "
863  << rewritten_lhs->toString() << " and rhs as " << rewritten_rhs->toString();
864 
865  auto overlaps_oper = makeExpr<Analyzer::BinOper>(
866  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
867 
868  VLOG(1) << "Successfully converted to overlaps join";
869  if (func_oper->getName() == "ST_Approx_Overlaps_MultiPolygon_Point"sv) {
870  return OverlapsJoinConjunction{{}, {overlaps_oper}};
871  } else {
872  return OverlapsJoinConjunction{{expr}, {overlaps_oper}};
873  }
874  } else {
875  VLOG(1) << "Overlaps join not enabled for " << func_oper->getName();
876  }
877  }
878  return boost::none;
879 }
#define LOG(tag)
Definition: Logger.h:194
bool is_constructed_point(const Analyzer::Expr *expr)
Definition: Execute.h:1180
static const std::unordered_set< std::string > requires_many_to_many
#define CHECK_GE(x, y)
Definition: Logger.h:216
T visit(const Analyzer::Expr *expr) const
static const std::unordered_set< std::string > overlaps_supported_functions
bool g_enable_hashjoin_many_to_many
Definition: Execute.cpp:97
Definition: sqldefs.h:69
#define CHECK(condition)
Definition: Logger.h:203
#define VLOG(n)
Definition: Logger.h:297

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool self_join_not_covered_by_left_deep_tree ( const Analyzer::ColumnVar key_side,
const Analyzer::ColumnVar val_side,
const int  max_rte_covered 
)

Definition at line 981 of file ExpressionRewrite.cpp.

References Analyzer::ColumnVar::get_rte_idx(), and Analyzer::ColumnVar::get_table_id().

Referenced by BaselineJoinHashTable::codegenKey(), PerfectJoinHashTable::codegenMatchingSet(), and PerfectJoinHashTable::codegenSlot().

983  {
984  if (key_side->get_table_id() == val_side->get_table_id() &&
985  key_side->get_rte_idx() == val_side->get_rte_idx() &&
986  key_side->get_rte_idx() > max_rte_covered) {
987  return true;
988  }
989  return false;
990 }
int get_table_id() const
Definition: Analyzer.h:194
int get_rte_idx() const
Definition: Analyzer.h:196

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

std::list<std::shared_ptr<Analyzer::Expr> > strip_join_covered_filter_quals ( const std::list< std::shared_ptr< Analyzer::Expr >> &  quals,
const JoinQualsPerNestingLevel join_quals 
)

Definition at line 923 of file ExpressionRewrite.cpp.

References g_strip_join_covered_quals, and ScalarExprVisitor< T >::visit().

Referenced by create_count_all_execution_unit().

925  {
927  return quals;
928  }
929 
930  if (join_quals.empty()) {
931  return quals;
932  }
933 
934  std::list<std::shared_ptr<Analyzer::Expr>> quals_to_return;
935 
936  JoinCoveredQualVisitor visitor(join_quals);
937  for (const auto& qual : quals) {
938  if (!visitor.visit(qual.get())) {
939  // Not a covered qual, don't elide it from the filtered count
940  quals_to_return.push_back(qual);
941  }
942  }
943 
944  return quals_to_return;
945 }
bool g_strip_join_covered_quals
Definition: Execute.cpp:100

+ Here is the call graph for this function:

+ Here is the caller graph for this function: