OmniSciDB  c1a53651b2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ExpressionRewrite.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <algorithm>
20 #include <boost/locale/conversion.hpp>
21 #include <unordered_set>
22 
23 #include "Analyzer/Analyzer.h"
24 #include "Logger/Logger.h"
25 #include "Parser/ParserNode.h"
27 #include "QueryEngine/Execute.h"
31 #include "Shared/sqldefs.h"
32 #include "StringOps/StringOps.h"
33 
34 namespace {
35 
36 class OrToInVisitor : public ScalarExprVisitor<std::shared_ptr<Analyzer::InValues>> {
37  protected:
38  std::shared_ptr<Analyzer::InValues> visitBinOper(
39  const Analyzer::BinOper* bin_oper) const override {
40  switch (bin_oper->get_optype()) {
41  case kEQ: {
42  const auto rhs_owned = bin_oper->get_own_right_operand();
43  auto rhs_no_cast = extract_cast_arg(rhs_owned.get());
44  if (!dynamic_cast<const Analyzer::Constant*>(rhs_no_cast)) {
45  return nullptr;
46  }
47  const auto arg = bin_oper->get_own_left_operand();
48  const auto& arg_ti = arg->get_type_info();
49  auto rhs = rhs_no_cast->deep_copy()->add_cast(arg_ti);
50  return makeExpr<Analyzer::InValues>(
51  arg, std::list<std::shared_ptr<Analyzer::Expr>>{rhs});
52  }
53  case kOR: {
54  return aggregateResult(visit(bin_oper->get_left_operand()),
55  visit(bin_oper->get_right_operand()));
56  }
57  default:
58  break;
59  }
60  return nullptr;
61  }
62 
63  std::shared_ptr<Analyzer::InValues> visitUOper(
64  const Analyzer::UOper* uoper) const override {
65  return nullptr;
66  }
67 
68  std::shared_ptr<Analyzer::InValues> visitInValues(
69  const Analyzer::InValues*) const override {
70  return nullptr;
71  }
72 
73  std::shared_ptr<Analyzer::InValues> visitInIntegerSet(
74  const Analyzer::InIntegerSet*) const override {
75  return nullptr;
76  }
77 
78  std::shared_ptr<Analyzer::InValues> visitCharLength(
79  const Analyzer::CharLengthExpr*) const override {
80  return nullptr;
81  }
82 
83  std::shared_ptr<Analyzer::InValues> visitKeyForString(
84  const Analyzer::KeyForStringExpr*) const override {
85  return nullptr;
86  }
87 
88  std::shared_ptr<Analyzer::InValues> visitSampleRatio(
89  const Analyzer::SampleRatioExpr*) const override {
90  return nullptr;
91  }
92 
93  std::shared_ptr<Analyzer::InValues> visitCardinality(
94  const Analyzer::CardinalityExpr*) const override {
95  return nullptr;
96  }
97 
98  std::shared_ptr<Analyzer::InValues> visitLikeExpr(
99  const Analyzer::LikeExpr*) const override {
100  return nullptr;
101  }
102 
103  std::shared_ptr<Analyzer::InValues> visitRegexpExpr(
104  const Analyzer::RegexpExpr*) const override {
105  return nullptr;
106  }
107 
108  std::shared_ptr<Analyzer::InValues> visitCaseExpr(
109  const Analyzer::CaseExpr*) const override {
110  return nullptr;
111  }
112 
113  std::shared_ptr<Analyzer::InValues> visitDatetruncExpr(
114  const Analyzer::DatetruncExpr*) const override {
115  return nullptr;
116  }
117 
118  std::shared_ptr<Analyzer::InValues> visitDatediffExpr(
119  const Analyzer::DatediffExpr*) const override {
120  return nullptr;
121  }
122 
123  std::shared_ptr<Analyzer::InValues> visitDateaddExpr(
124  const Analyzer::DateaddExpr*) const override {
125  return nullptr;
126  }
127 
128  std::shared_ptr<Analyzer::InValues> visitExtractExpr(
129  const Analyzer::ExtractExpr*) const override {
130  return nullptr;
131  }
132 
133  std::shared_ptr<Analyzer::InValues> visitLikelihood(
134  const Analyzer::LikelihoodExpr*) const override {
135  return nullptr;
136  }
137 
138  std::shared_ptr<Analyzer::InValues> visitAggExpr(
139  const Analyzer::AggExpr*) const override {
140  return nullptr;
141  }
142 
143  std::shared_ptr<Analyzer::InValues> aggregateResult(
144  const std::shared_ptr<Analyzer::InValues>& lhs,
145  const std::shared_ptr<Analyzer::InValues>& rhs) const override {
146  if (!lhs || !rhs) {
147  return nullptr;
148  }
149 
150  if (lhs->get_arg()->get_type_info() == rhs->get_arg()->get_type_info() &&
151  (*lhs->get_arg() == *rhs->get_arg())) {
152  auto union_values = lhs->get_value_list();
153  const auto& rhs_values = rhs->get_value_list();
154  union_values.insert(union_values.end(), rhs_values.begin(), rhs_values.end());
155  return makeExpr<Analyzer::InValues>(lhs->get_own_arg(), union_values);
156  }
157  return nullptr;
158  }
159 };
160 
162  protected:
163  std::shared_ptr<Analyzer::Expr> visitBinOper(
164  const Analyzer::BinOper* bin_oper) const override {
165  OrToInVisitor simple_visitor;
166  if (bin_oper->get_optype() == kOR) {
167  auto rewritten = simple_visitor.visit(bin_oper);
168  if (rewritten) {
169  return rewritten;
170  }
171  }
172  auto lhs = bin_oper->get_own_left_operand();
173  auto rhs = bin_oper->get_own_right_operand();
174  auto rewritten_lhs = visit(lhs.get());
175  auto rewritten_rhs = visit(rhs.get());
176  return makeExpr<Analyzer::BinOper>(bin_oper->get_type_info(),
177  bin_oper->get_contains_agg(),
178  bin_oper->get_optype(),
179  bin_oper->get_qualifier(),
180  rewritten_lhs ? rewritten_lhs : lhs,
181  rewritten_rhs ? rewritten_rhs : rhs);
182  }
183 };
184 
186  protected:
188 
189  RetType visitArrayOper(const Analyzer::ArrayExpr* array_expr) const override {
190  std::vector<std::shared_ptr<Analyzer::Expr>> args_copy;
191  for (size_t i = 0; i < array_expr->getElementCount(); ++i) {
192  auto const element_expr_ptr = visit(array_expr->getElement(i));
193  auto const& element_expr_type_info = element_expr_ptr->get_type_info();
194 
195  if (!element_expr_type_info.is_string() ||
196  element_expr_type_info.get_compression() != kENCODING_NONE) {
197  args_copy.push_back(element_expr_ptr);
198  } else {
199  auto transient_dict_type_info = element_expr_type_info;
200 
201  transient_dict_type_info.set_compression(kENCODING_DICT);
202  transient_dict_type_info.set_comp_param(TRANSIENT_DICT_ID);
203  transient_dict_type_info.set_fixed_size();
204  args_copy.push_back(element_expr_ptr->add_cast(transient_dict_type_info));
205  }
206  }
207 
208  const auto& type_info = array_expr->get_type_info();
209  return makeExpr<Analyzer::ArrayExpr>(
210  type_info, args_copy, array_expr->isNull(), array_expr->isLocalAlloc());
211  }
212 };
213 
215  template <typename T>
216  bool foldComparison(SQLOps optype, T t1, T t2) const {
217  switch (optype) {
218  case kEQ:
219  return t1 == t2;
220  case kNE:
221  return t1 != t2;
222  case kLT:
223  return t1 < t2;
224  case kLE:
225  return t1 <= t2;
226  case kGT:
227  return t1 > t2;
228  case kGE:
229  return t1 >= t2;
230  default:
231  break;
232  }
233  throw std::runtime_error("Unable to fold");
234  return false;
235  }
236 
237  template <typename T>
238  bool foldLogic(SQLOps optype, T t1, T t2) const {
239  switch (optype) {
240  case kAND:
241  return t1 && t2;
242  case kOR:
243  return t1 || t2;
244  case kNOT:
245  return !t1;
246  default:
247  break;
248  }
249  throw std::runtime_error("Unable to fold");
250  return false;
251  }
252 
253  template <typename T>
254  T foldArithmetic(SQLOps optype, T t1, T t2) const {
255  bool t2_is_zero = (t2 == (t2 - t2));
256  bool t2_is_negative = (t2 < (t2 - t2));
257  switch (optype) {
258  case kPLUS:
259  // The MIN limit for float and double is the smallest representable value,
260  // not the lowest negative value! Switching to C++11 lowest.
261  if ((t2_is_negative && t1 < std::numeric_limits<T>::lowest() - t2) ||
262  (!t2_is_negative && t1 > std::numeric_limits<T>::max() - t2)) {
263  num_overflows_++;
264  throw std::runtime_error("Plus overflow");
265  }
266  return t1 + t2;
267  case kMINUS:
268  if ((t2_is_negative && t1 > std::numeric_limits<T>::max() + t2) ||
269  (!t2_is_negative && t1 < std::numeric_limits<T>::lowest() + t2)) {
270  num_overflows_++;
271  throw std::runtime_error("Minus overflow");
272  }
273  return t1 - t2;
274  case kMULTIPLY: {
275  if (t2_is_zero) {
276  return t2;
277  }
278  auto ct1 = t1;
279  auto ct2 = t2;
280  // Need to keep t2's sign on the left
281  if (t2_is_negative) {
282  if (t1 == std::numeric_limits<T>::lowest() ||
283  t2 == std::numeric_limits<T>::lowest()) {
284  // negation could overflow - bail
285  num_overflows_++;
286  throw std::runtime_error("Mul neg overflow");
287  }
288  ct1 = -t1; // ct1 gets t2's negativity
289  ct2 = -t2; // ct2 is now positive
290  }
291  // Don't check overlow if we are folding FP mul by a fraction
292  bool ct2_is_fraction = (ct2 < (ct2 / ct2));
293  if (!ct2_is_fraction) {
294  if (ct1 > std::numeric_limits<T>::max() / ct2 ||
295  ct1 < std::numeric_limits<T>::lowest() / ct2) {
296  num_overflows_++;
297  throw std::runtime_error("Mul overflow");
298  }
299  }
300  return t1 * t2;
301  }
302  case kDIVIDE:
303  if (t2_is_zero) {
304  throw std::runtime_error("Will not fold division by zero");
305  }
306  return t1 / t2;
307  default:
308  break;
309  }
310  throw std::runtime_error("Unable to fold");
311  }
312 
313  bool foldOper(SQLOps optype,
314  SQLTypes type,
315  Datum lhs,
316  Datum rhs,
317  Datum& result,
318  SQLTypes& result_type) const {
319  result_type = type;
320 
321  try {
322  switch (type) {
323  case kBOOLEAN:
324  if (IS_COMPARISON(optype)) {
325  result.boolval = foldComparison<bool>(optype, lhs.boolval, rhs.boolval);
326  result_type = kBOOLEAN;
327  return true;
328  }
329  if (IS_LOGIC(optype)) {
330  result.boolval = foldLogic<bool>(optype, lhs.boolval, rhs.boolval);
331  result_type = kBOOLEAN;
332  return true;
333  }
334  CHECK(!IS_ARITHMETIC(optype));
335  break;
336  case kTINYINT:
337  if (IS_COMPARISON(optype)) {
338  result.boolval =
339  foldComparison<int8_t>(optype, lhs.tinyintval, rhs.tinyintval);
340  result_type = kBOOLEAN;
341  return true;
342  }
343  if (IS_ARITHMETIC(optype)) {
344  result.tinyintval =
345  foldArithmetic<int8_t>(optype, lhs.tinyintval, rhs.tinyintval);
346  result_type = kTINYINT;
347  return true;
348  }
349  CHECK(!IS_LOGIC(optype));
350  break;
351  case kSMALLINT:
352  if (IS_COMPARISON(optype)) {
353  result.boolval =
354  foldComparison<int16_t>(optype, lhs.smallintval, rhs.smallintval);
355  result_type = kBOOLEAN;
356  return true;
357  }
358  if (IS_ARITHMETIC(optype)) {
359  result.smallintval =
360  foldArithmetic<int16_t>(optype, lhs.smallintval, rhs.smallintval);
361  result_type = kSMALLINT;
362  return true;
363  }
364  CHECK(!IS_LOGIC(optype));
365  break;
366  case kINT:
367  if (IS_COMPARISON(optype)) {
368  result.boolval = foldComparison<int32_t>(optype, lhs.intval, rhs.intval);
369  result_type = kBOOLEAN;
370  return true;
371  }
372  if (IS_ARITHMETIC(optype)) {
373  result.intval = foldArithmetic<int32_t>(optype, lhs.intval, rhs.intval);
374  result_type = kINT;
375  return true;
376  }
377  CHECK(!IS_LOGIC(optype));
378  break;
379  case kBIGINT:
380  if (IS_COMPARISON(optype)) {
381  result.boolval =
382  foldComparison<int64_t>(optype, lhs.bigintval, rhs.bigintval);
383  result_type = kBOOLEAN;
384  return true;
385  }
386  if (IS_ARITHMETIC(optype)) {
387  result.bigintval =
388  foldArithmetic<int64_t>(optype, lhs.bigintval, rhs.bigintval);
389  result_type = kBIGINT;
390  return true;
391  }
392  CHECK(!IS_LOGIC(optype));
393  break;
394  case kFLOAT:
395  if (IS_COMPARISON(optype)) {
396  result.boolval = foldComparison<float>(optype, lhs.floatval, rhs.floatval);
397  result_type = kBOOLEAN;
398  return true;
399  }
400  if (IS_ARITHMETIC(optype)) {
401  result.floatval = foldArithmetic<float>(optype, lhs.floatval, rhs.floatval);
402  result_type = kFLOAT;
403  return true;
404  }
405  CHECK(!IS_LOGIC(optype));
406  break;
407  case kDOUBLE:
408  if (IS_COMPARISON(optype)) {
409  result.boolval = foldComparison<double>(optype, lhs.doubleval, rhs.doubleval);
410  result_type = kBOOLEAN;
411  return true;
412  }
413  if (IS_ARITHMETIC(optype)) {
414  result.doubleval =
415  foldArithmetic<double>(optype, lhs.doubleval, rhs.doubleval);
416  result_type = kDOUBLE;
417  return true;
418  }
419  CHECK(!IS_LOGIC(optype));
420  break;
421  default:
422  break;
423  }
424  } catch (...) {
425  return false;
426  }
427  return false;
428  }
429 
430  std::shared_ptr<Analyzer::Expr> visitUOper(
431  const Analyzer::UOper* uoper) const override {
432  const auto unvisited_operand = uoper->get_operand();
433  const auto optype = uoper->get_optype();
434  const auto& ti = uoper->get_type_info();
435  if (optype == kCAST) {
436  // Cache the cast type so it could be used in operand rewriting/folding
437  casts_.insert({unvisited_operand, ti});
438  }
439  const auto operand = visit(unvisited_operand);
440 
441  const auto& operand_ti = operand->get_type_info();
442  const auto operand_type =
443  operand_ti.is_decimal() ? decimal_to_int_type(operand_ti) : operand_ti.get_type();
444  const auto const_operand =
445  std::dynamic_pointer_cast<const Analyzer::Constant>(operand);
446 
447  if (const_operand) {
448  const auto operand_datum = const_operand->get_constval();
449  Datum zero_datum = {};
450  Datum result_datum = {};
451  SQLTypes result_type;
452  switch (optype) {
453  case kNOT: {
454  if (foldOper(kEQ,
455  operand_type,
456  zero_datum,
457  operand_datum,
458  result_datum,
459  result_type)) {
460  CHECK_EQ(result_type, kBOOLEAN);
461  return makeExpr<Analyzer::Constant>(result_type, false, result_datum);
462  }
463  break;
464  }
465  case kUMINUS: {
466  if (foldOper(kMINUS,
467  operand_type,
468  zero_datum,
469  operand_datum,
470  result_datum,
471  result_type)) {
472  if (!operand_ti.is_decimal()) {
473  return makeExpr<Analyzer::Constant>(result_type, false, result_datum);
474  }
475  return makeExpr<Analyzer::Constant>(ti, false, result_datum);
476  }
477  break;
478  }
479  case kCAST: {
480  // Trying to fold number to number casts only
481  if (!ti.is_number() || !operand_ti.is_number()) {
482  break;
483  }
484  // Disallowing folding of FP to DECIMAL casts for now:
485  // allowing them would make this test pass:
486  // update dectest set d=cast( 1234.0 as float );
487  // which is expected to throw in Update.ImplicitCastToNumericTypes
488  // due to cast codegen currently not supporting these casts
489  if (ti.is_decimal() && operand_ti.is_fp()) {
490  break;
491  }
492  auto operand_copy = const_operand->deep_copy();
493  auto cast_operand = operand_copy->add_cast(ti);
494  auto const_cast_operand =
495  std::dynamic_pointer_cast<const Analyzer::Constant>(cast_operand);
496  if (const_cast_operand) {
497  auto const_cast_datum = const_cast_operand->get_constval();
498  return makeExpr<Analyzer::Constant>(ti, false, const_cast_datum);
499  }
500  }
501  default:
502  break;
503  }
504  }
505 
506  return makeExpr<Analyzer::UOper>(
507  uoper->get_type_info(), uoper->get_contains_agg(), optype, operand);
508  }
509 
510  std::shared_ptr<Analyzer::Expr> visitBinOper(
511  const Analyzer::BinOper* bin_oper) const override {
512  const auto optype = bin_oper->get_optype();
513  auto ti = bin_oper->get_type_info();
514  auto left_operand = bin_oper->get_own_left_operand();
515  auto right_operand = bin_oper->get_own_right_operand();
516 
517  // Check if bin_oper result is cast to a larger int or fp type
518  if (casts_.find(bin_oper) != casts_.end()) {
519  const auto cast_ti = casts_[bin_oper];
520  const auto& lhs_ti = bin_oper->get_left_operand()->get_type_info();
521  // Propagate cast down to the operands for folding
522  if ((cast_ti.is_integer() || cast_ti.is_fp()) && lhs_ti.is_integer() &&
523  cast_ti.get_size() > lhs_ti.get_size() &&
524  (optype == kMINUS || optype == kPLUS || optype == kMULTIPLY)) {
525  // Before folding, cast the operands to the bigger type to avoid overflows.
526  // Currently upcasting smaller integer types to larger integers or double.
527  left_operand = left_operand->deep_copy()->add_cast(cast_ti);
528  right_operand = right_operand->deep_copy()->add_cast(cast_ti);
529  ti = cast_ti;
530  }
531  }
532 
533  const auto lhs = visit(left_operand.get());
534  const auto rhs = visit(right_operand.get());
535 
536  auto const_lhs = std::dynamic_pointer_cast<Analyzer::Constant>(lhs);
537  auto const_rhs = std::dynamic_pointer_cast<Analyzer::Constant>(rhs);
538  const auto& lhs_ti = lhs->get_type_info();
539  const auto& rhs_ti = rhs->get_type_info();
540  auto lhs_type = lhs_ti.is_decimal() ? decimal_to_int_type(lhs_ti) : lhs_ti.get_type();
541  auto rhs_type = rhs_ti.is_decimal() ? decimal_to_int_type(rhs_ti) : rhs_ti.get_type();
542 
543  if (const_lhs && const_rhs && lhs_type == rhs_type) {
544  auto lhs_datum = const_lhs->get_constval();
545  auto rhs_datum = const_rhs->get_constval();
546  Datum result_datum = {};
547  SQLTypes result_type;
548  if (foldOper(optype, lhs_type, lhs_datum, rhs_datum, result_datum, result_type)) {
549  // Fold all ops that don't take in decimal operands, and also decimal comparisons
550  if (!lhs_ti.is_decimal() || IS_COMPARISON(optype)) {
551  return makeExpr<Analyzer::Constant>(result_type, false, result_datum);
552  }
553  // Decimal arithmetic has been done as kBIGINT. Selectively fold some decimal ops,
554  // using result_datum and BinOper expr typeinfo which was adjusted for these ops.
555  if (optype == kMINUS || optype == kPLUS || optype == kMULTIPLY) {
556  return makeExpr<Analyzer::Constant>(ti, false, result_datum);
557  }
558  }
559  }
560 
561  if (optype == kAND && lhs_type == rhs_type && lhs_type == kBOOLEAN) {
562  if (const_rhs && !const_rhs->get_is_null()) {
563  auto rhs_datum = const_rhs->get_constval();
564  if (rhs_datum.boolval == false) {
565  Datum d;
566  d.boolval = false;
567  // lhs && false --> false
568  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
569  }
570  // lhs && true --> lhs
571  return lhs;
572  }
573  if (const_lhs && !const_lhs->get_is_null()) {
574  auto lhs_datum = const_lhs->get_constval();
575  if (lhs_datum.boolval == false) {
576  Datum d;
577  d.boolval = false;
578  // false && rhs --> false
579  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
580  }
581  // true && rhs --> rhs
582  return rhs;
583  }
584  }
585  if (optype == kOR && lhs_type == rhs_type && lhs_type == kBOOLEAN) {
586  if (const_rhs && !const_rhs->get_is_null()) {
587  auto rhs_datum = const_rhs->get_constval();
588  if (rhs_datum.boolval == true) {
589  Datum d;
590  d.boolval = true;
591  // lhs || true --> true
592  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
593  }
594  // lhs || false --> lhs
595  return lhs;
596  }
597  if (const_lhs && !const_lhs->get_is_null()) {
598  auto lhs_datum = const_lhs->get_constval();
599  if (lhs_datum.boolval == true) {
600  Datum d;
601  d.boolval = true;
602  // true || rhs --> true
603  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
604  }
605  // false || rhs --> rhs
606  return rhs;
607  }
608  }
609  if (*lhs == *rhs) {
610  if (!lhs_ti.get_notnull()) {
611  CHECK(!rhs_ti.get_notnull());
612  // We can't fold the ostensible tautaulogy
613  // for nullable lhs and rhs types, as
614  // lhs <> rhs when they are null
615 
616  // We likely could turn this into a lhs is not null
617  // operatation, but is it worth it?
618  return makeExpr<Analyzer::BinOper>(ti,
619  bin_oper->get_contains_agg(),
620  bin_oper->get_optype(),
621  bin_oper->get_qualifier(),
622  lhs,
623  rhs);
624  }
625  CHECK(rhs_ti.get_notnull());
626  // Tautologies: v=v; v<=v; v>=v
627  if (optype == kEQ || optype == kLE || optype == kGE) {
628  Datum d;
629  d.boolval = true;
630  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
631  }
632  // Contradictions: v!=v; v<v; v>v
633  if (optype == kNE || optype == kLT || optype == kGT) {
634  Datum d;
635  d.boolval = false;
636  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
637  }
638  // v-v
639  if (optype == kMINUS) {
640  Datum d = {};
641  return makeExpr<Analyzer::Constant>(lhs_type, false, d);
642  }
643  }
644  // Convert fp division by a constant to multiplication by 1/constant
645  if (optype == kDIVIDE && const_rhs && rhs_ti.is_fp()) {
646  auto rhs_datum = const_rhs->get_constval();
647  std::shared_ptr<Analyzer::Expr> recip_rhs = nullptr;
648  if (rhs_ti.get_type() == kFLOAT) {
649  if (rhs_datum.floatval == 1.0) {
650  return lhs;
651  }
652  auto f = std::fabs(rhs_datum.floatval);
653  if (f > 1.0 || (f != 0.0 && 1.0 < f * std::numeric_limits<float>::max())) {
654  rhs_datum.floatval = 1.0 / rhs_datum.floatval;
655  recip_rhs = makeExpr<Analyzer::Constant>(rhs_type, false, rhs_datum);
656  }
657  } else if (rhs_ti.get_type() == kDOUBLE) {
658  if (rhs_datum.doubleval == 1.0) {
659  return lhs;
660  }
661  auto d = std::fabs(rhs_datum.doubleval);
662  if (d > 1.0 || (d != 0.0 && 1.0 < d * std::numeric_limits<double>::max())) {
663  rhs_datum.doubleval = 1.0 / rhs_datum.doubleval;
664  recip_rhs = makeExpr<Analyzer::Constant>(rhs_type, false, rhs_datum);
665  }
666  }
667  if (recip_rhs) {
668  return makeExpr<Analyzer::BinOper>(ti,
669  bin_oper->get_contains_agg(),
670  kMULTIPLY,
671  bin_oper->get_qualifier(),
672  lhs,
673  recip_rhs);
674  }
675  }
676 
677  return makeExpr<Analyzer::BinOper>(ti,
678  bin_oper->get_contains_agg(),
679  bin_oper->get_optype(),
680  bin_oper->get_qualifier(),
681  lhs,
682  rhs);
683  }
684 
685  std::shared_ptr<Analyzer::Expr> visitStringOper(
686  const Analyzer::StringOper* string_oper) const override {
687  // Todo(todd): For clarity and modularity we should move string
688  // operator rewrites into their own visitor class.
689  // String operation rewrites were originally put here as they only
690  // handled string operators on rewrite, but now handle variable
691  // inputs as well.
692  const auto original_args = string_oper->getOwnArgs();
693  std::vector<std::shared_ptr<Analyzer::Expr>> rewritten_args;
694  const auto non_literal_arity = string_oper->getNonLiteralsArity();
695  const auto parent_in_string_op_chain = in_string_op_chain_;
696  const auto in_string_op_chain = non_literal_arity <= 1UL;
697  in_string_op_chain_ = in_string_op_chain;
698 
699  size_t rewritten_arg_literal_arity = 0;
700  for (auto original_arg : original_args) {
701  rewritten_args.emplace_back(visit(original_arg.get()));
702  if (dynamic_cast<const Analyzer::Constant*>(rewritten_args.back().get())) {
703  rewritten_arg_literal_arity++;
704  }
705  }
706  in_string_op_chain_ = parent_in_string_op_chain;
707  const auto kind = string_oper->get_kind();
708  const auto& return_ti = string_oper->get_type_info();
709 
710  if (string_oper->getArity() == rewritten_arg_literal_arity) {
711  Analyzer::StringOper literal_string_oper(
712  kind, string_oper->get_type_info(), rewritten_args);
713  const auto literal_args = literal_string_oper.getLiteralArgs();
714  const auto string_op_info =
715  StringOps_Namespace::StringOpInfo(kind, return_ti, literal_args);
716  if (return_ti.is_string()) {
717  const auto literal_result =
719  return Parser::StringLiteral::analyzeValue(literal_result.first,
720  literal_result.second);
721  }
722  const auto literal_datum =
724  auto nullable_return_ti = return_ti;
725  nullable_return_ti.set_notnull(false);
726  return makeExpr<Analyzer::Constant>(nullable_return_ti,
727  IsNullDatum(literal_datum, nullable_return_ti),
728  literal_datum);
729  }
730  chained_string_op_exprs_.emplace_back(
731  makeExpr<Analyzer::StringOper>(kind, return_ti, rewritten_args));
732  if (parent_in_string_op_chain && in_string_op_chain) {
733  CHECK(rewritten_args[0]->get_type_info().is_string());
734  return rewritten_args[0]->deep_copy();
735  } else {
736  auto new_string_oper = makeExpr<Analyzer::StringOper>(
737  kind, return_ti, rewritten_args, chained_string_op_exprs_);
738  chained_string_op_exprs_.clear();
739  return new_string_oper;
740  }
741  }
742 
743  protected:
744  mutable bool in_string_op_chain_{false};
745  mutable std::vector<std::shared_ptr<Analyzer::Expr>> chained_string_op_exprs_;
746  mutable std::unordered_map<const Analyzer::Expr*, const SQLTypeInfo> casts_;
747  mutable int32_t num_overflows_;
748 
749  public:
750  ConstantFoldingVisitor() : num_overflows_(0) {}
751  int32_t get_num_overflows() { return num_overflows_; }
752  void reset_num_overflows() { num_overflows_ = 0; }
753 };
754 
756  const auto with_likelihood = dynamic_cast<const Analyzer::LikelihoodExpr*>(expr);
757  if (!with_likelihood) {
758  return expr;
759  }
760  return with_likelihood->get_arg();
761 }
762 
763 } // namespace
764 
766  return ArrayElementStringLiteralEncodingVisitor().visit(expr);
767 }
768 
770  const auto sum_window = rewrite_sum_window(expr);
771  if (sum_window) {
772  return sum_window;
773  }
774  const auto avg_window = rewrite_avg_window(expr);
775  if (avg_window) {
776  return avg_window;
777  }
778  const auto expr_no_likelihood = strip_likelihood(expr);
779  // The following check is not strictly needed, but seems silly to transform a
780  // simple string comparison to an IN just to codegen the same thing anyway.
781 
782  RecursiveOrToInVisitor visitor;
783  auto rewritten_expr = visitor.visit(expr_no_likelihood);
784  const auto expr_with_likelihood =
785  std::dynamic_pointer_cast<const Analyzer::LikelihoodExpr>(rewritten_expr);
786  if (expr_with_likelihood) {
787  // Add back likelihood
788  return std::make_shared<Analyzer::LikelihoodExpr>(
789  rewritten_expr, expr_with_likelihood->get_likelihood());
790  }
791  return rewritten_expr;
792 }
793 
794 boost::optional<OverlapsJoinConjunction> rewrite_overlaps_conjunction(
795  const std::shared_ptr<Analyzer::Expr> expr,
796  const std::vector<InputDescriptor>& input_table_info,
797  const OverlapsJoinRewriteType rewrite_type,
798  const Executor* executor) {
799  auto collect_table_cardinality =
800  [](const Analyzer::Expr* lhs, const Analyzer::Expr* rhs, const Executor* executor) {
801  const auto lhs_cv = dynamic_cast<const Analyzer::ColumnVar*>(lhs);
802  const auto rhs_cv = dynamic_cast<const Analyzer::ColumnVar*>(rhs);
803  if (lhs_cv && rhs_cv) {
804  const auto inner_table_metadata = Catalog_Namespace::get_metadata_for_table(
805  {lhs_cv->getColumnKey().db_id, lhs_cv->getColumnKey().table_id});
806  const auto outer_table_metadata = Catalog_Namespace::get_metadata_for_table(
807  {rhs_cv->getColumnKey().db_id, rhs_cv->getColumnKey().table_id});
808  if (inner_table_metadata->fragmenter && outer_table_metadata->fragmenter) {
809  return std::make_pair<int64_t, int64_t>(
810  inner_table_metadata->fragmenter->getNumRows(),
811  outer_table_metadata->fragmenter->getNumRows());
812  }
813  }
814  // otherwise, return an invalid table cardinality
815  return std::make_pair<int64_t, int64_t>(-1, -1);
816  };
817 
818  auto has_invalid_join_col_order = [](const Analyzer::Expr* lhs,
819  const Analyzer::Expr* rhs) {
820  // Check for compatible join ordering. If the join ordering does not match expected
821  // ordering for overlaps, the join builder will fail.
822  std::set<int> lhs_rte_idx;
823  lhs->collect_rte_idx(lhs_rte_idx);
824  CHECK(!lhs_rte_idx.empty());
825  std::set<int> rhs_rte_idx;
826  rhs->collect_rte_idx(rhs_rte_idx);
827  CHECK(!rhs_rte_idx.empty());
828  auto has_invalid_num_join_cols = lhs_rte_idx.size() > 1 || rhs_rte_idx.size() > 1;
829  auto has_invalid_rte_idx = lhs_rte_idx > rhs_rte_idx;
830  return std::make_pair(has_invalid_num_join_cols || has_invalid_rte_idx,
831  has_invalid_rte_idx);
832  };
833 
835  [&](std::string_view func_name,
836  const std::shared_ptr<Analyzer::Expr> expr,
837  const Analyzer::BinOper* range_join_expr,
838  const Analyzer::GeoOperator* lhs,
839  const Analyzer::Constant* rhs,
840  const Executor* executor) -> std::shared_ptr<Analyzer::BinOper> {
842  CHECK_EQ(lhs->size(), size_t(2));
843  auto l_arg = lhs->getOperand(0);
844  // we try to build an overlaps join hash table based on the rhs
845  auto r_arg = lhs->getOperand(1);
846  const bool is_geography = l_arg->get_type_info().get_subtype() == kGEOGRAPHY ||
847  r_arg->get_type_info().get_subtype() == kGEOGRAPHY;
848  if (is_geography) {
849  VLOG(1) << "Range join not yet supported for geodesic distance "
850  << expr->toString();
851  return nullptr;
852  }
853 
854  // Check for compatible join ordering. If the join ordering does not match expected
855  // ordering for overlaps, the join builder will fail.
856  Analyzer::Expr* range_join_arg = r_arg;
857  Analyzer::Expr* bin_oper_arg = l_arg;
858  auto invalid_range_join_qual =
859  has_invalid_join_col_order(bin_oper_arg, range_join_arg);
860  if (invalid_range_join_qual.first) {
861  LOG(INFO) << "Unable to rewrite " << func_name
862  << " to overlaps conjunction. Cannot build hash table over LHS type. "
863  "Check join order.\n"
864  << range_join_expr->toString();
865  return nullptr;
866  }
867  // swapping rule for range join argument
868  // lhs | rhs
869  // 1. pt | pt : swap if |lhs| < |rhs| or has invalid rte values
870  // 2. pt | non-pt : return nullptr
871  // 3. non-pt | pt : return nullptr
872  // 4. non-pt | non-pt : return nullptr
873  // todo (yoonmin) : improve logic for cases 2 and 3
874  bool lhs_is_point{l_arg->get_type_info().get_type() == kPOINT};
875  bool rhs_is_point{r_arg->get_type_info().get_type() == kPOINT};
876  if (!lhs_is_point || !rhs_is_point) {
877  // case 2 ~ 4
878  VLOG(1) << "Currently, we only support range hash join for Point-to-Point "
879  "distance query: fallback to a loop join";
880  return nullptr;
881  }
882 
883  bool swap_args = false;
884  auto const card_info =
885  collect_table_cardinality(range_join_arg, bin_oper_arg, executor);
886  if (invalid_range_join_qual.second && card_info.first > 0 && lhs_is_point) {
887  swap_args = true;
888  } else if (card_info.first >= 0 && card_info.first < card_info.second) {
889  swap_args = true;
890  }
891 
892  if (swap_args) {
893  // to exploit range hash join, we need to assign point geometry to rhs
894  r_arg = lhs->getOperand(0);
895  l_arg = lhs->getOperand(1);
896  VLOG(1) << "Swap range join qual's input arguments to exploit overlaps "
897  "hash join framework";
898  invalid_range_join_qual.first = false;
899  }
900 
901  const bool inclusive = range_join_expr->get_optype() == kLE;
902  auto range_expr = makeExpr<Analyzer::RangeOper>(
903  inclusive, inclusive, r_arg->deep_copy(), rhs->deep_copy());
904  VLOG(1) << "Successfully converted to range hash join";
905  return makeExpr<Analyzer::BinOper>(
906  kBOOLEAN, kOVERLAPS, kONE, l_arg->deep_copy(), range_expr);
907  }
908  return nullptr;
909  };
910 
911  /*
912  * Currently, our overlaps hash join framework supports limited join quals especially
913  * when 1) the FunctionOperator is listed in the function list, i.e.,
914  * is_overlaps_supported_func, 2) the argument order of the join qual must match the
915  * input argument order of the corresponding native function, and 3) input tables match
916  * rte index requirement (the column used to build a hash table has larger rte compared
917  * with that of probing column) And depending on the type of the function, we try to
918  * convert it to corresponding overlaps hash join qual if possible After rewriting, we
919  * create an overlaps join operator which is converted from the original expression and
920  * return OverlapsJoinConjunction object which is a pair of 1) the original expr and 2)
921  * converted overlaps join expr Here, returning the original expr means we additionally
922  * call its corresponding native function to compute the result accurately (i.e.,
923  * overlaps hash join operates a kind of filter expression which may include
924  * false-positive of the true resultset) Note that ST_Overlaps is the only function that
925  * does not return the original expr
926  * */
927  std::shared_ptr<Analyzer::BinOper> overlaps_oper{nullptr};
928  bool needs_to_return_original_expr = false;
929  std::string func_name{""};
930  if (rewrite_type == OverlapsJoinRewriteType::OVERLAPS_JOIN) {
931  auto func_oper = dynamic_cast<Analyzer::FunctionOper*>(expr.get());
932  CHECK(func_oper);
933  func_name = func_oper->getName();
936  LOG(WARNING) << "Many-to-many hashjoin support is disabled, unable to rewrite "
937  << func_oper->toString() << " to use accelerated geo join.";
938  return boost::none;
939  }
940  DeepCopyVisitor deep_copy_visitor;
942  CHECK_GE(func_oper->getArity(), size_t(2));
943  // this case returns {empty quals, overlaps join quals} b/c our join key matching
944  // logic for this case is the same as the implementation of ST_Overlaps function
945  // Note that we can build an overlaps join hash table regardless of table ordering
946  // and the argument order in this case b/c selecting lhs and rhs by arguments 0
947  // and 1 always match the rte index requirement (rte_lhs < rte_rhs)
948  // so what table ordering we take, the rte index requirement satisfies
949  // TODO(adb): we will likely want to actually check for true overlaps, but this
950  // works for now
951  auto lhs = func_oper->getOwnArg(0);
952  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
953  CHECK(rewritten_lhs);
954 
955  auto rhs = func_oper->getOwnArg(1);
956  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
957  CHECK(rewritten_rhs);
958  overlaps_oper = makeExpr<Analyzer::BinOper>(
959  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
961  CHECK_EQ(func_oper->getArity(), size_t(8));
962  const auto lhs = func_oper->getOwnArg(0);
963  const auto rhs = func_oper->getOwnArg(1);
964  // the correctness of geo args used in the ST_DWithin function is checked by
965  // geo translation logic, i.e., RelAlgTranslator::translateTernaryGeoFunction
966  const auto distance_const_val =
967  dynamic_cast<const Analyzer::Constant*>(func_oper->getArg(7));
968  if (lhs && rhs && distance_const_val) {
969  std::vector<std::shared_ptr<Analyzer::Expr>> args{lhs, rhs};
970  auto range_oper = makeExpr<Analyzer::GeoOperator>(
971  SQLTypeInfo(kDOUBLE, 0, 8, true),
973  args,
974  std::nullopt);
975  auto distance_oper = makeExpr<Analyzer::BinOper>(
976  kBOOLEAN, kLE, kONE, range_oper, distance_const_val->deep_copy());
977  VLOG(1) << "Rewrite " << func_oper->getName() << " to ST_Distance_Point_Point";
978  overlaps_oper =
980  distance_oper,
981  distance_oper.get(),
982  range_oper.get(),
983  distance_const_val,
984  executor);
985  needs_to_return_original_expr = true;
986  }
988  func_name)) {
989  // in the five functions fall into this case,
990  // ST_Contains is for a pair of polygons, and for ST_Intersect cases they are
991  // combo of polygon and multipolygon so what table orders we choose, rte index
992  // requirement for overlaps join can be satisfied if we choose lhs and rhs
993  // from left-to-right order (i.e., get lhs from the arg-1 instead of arg-3)
994  // Note that we choose them from right-to-left argument order in the past
995  CHECK_GE(func_oper->getArity(), size_t(4));
996  auto lhs = func_oper->getOwnArg(1);
997  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
998  CHECK(rewritten_lhs);
999  auto rhs = func_oper->getOwnArg(3);
1000  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
1001  CHECK(rewritten_rhs);
1002 
1003  overlaps_oper = makeExpr<Analyzer::BinOper>(
1004  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
1005  needs_to_return_original_expr = true;
1007  func_name)) {
1008  // now, we try to look at one more chance to exploit overlaps hash join by
1009  // rewriting the qual as: ST_INTERSECT(POLY, POINT) -> ST_INTERSECT(POINT, POLY)
1010  // to support efficient evaluation of 1) ST_Intersects_Point_Polygon and
1011  // 2) ST_Intersects_Point_MultiPolygon based on our overlaps hash join framework
1012  // here, we have implementation of native functions for both 1) Point-Polygon pair
1013  // and 2) Polygon-Point pair, but we currently do not support hash table
1014  // generation on top of point column thus, the goal of this rewriting is to place
1015  // a non-point geometry to the right-side of the overlaps join operator (to build
1016  // hash table based on it) iff the inner table is larger than that of non-point
1017  // geometry (to reduce expensive hash join performance)
1018  size_t point_arg_idx = 0;
1019  size_t poly_arg_idx = 2;
1020  if (func_oper->getOwnArg(point_arg_idx)->get_type_info().get_type() != kPOINT) {
1021  point_arg_idx = 2;
1022  poly_arg_idx = 1;
1023  }
1024  auto point_cv = func_oper->getOwnArg(point_arg_idx);
1025  auto poly_cv = func_oper->getOwnArg(poly_arg_idx);
1026  CHECK_EQ(point_cv->get_type_info().get_type(), kPOINT);
1027  CHECK_EQ(poly_cv->get_type_info().get_type(), kARRAY);
1028  auto rewritten_lhs = deep_copy_visitor.visit(point_cv.get());
1029  CHECK(rewritten_lhs);
1030  auto rewritten_rhs = deep_copy_visitor.visit(poly_cv.get());
1031  CHECK(rewritten_rhs);
1032  VLOG(1) << "Rewriting the " << func_name << " to use overlaps join with lhs as "
1033  << rewritten_lhs->toString() << " and rhs as " << rewritten_rhs->toString();
1034  overlaps_oper = makeExpr<Analyzer::BinOper>(
1035  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
1036  needs_to_return_original_expr = true;
1038  func_name)) {
1039  // rest of functions reaching here is poly and point geo join query
1040  // to use overlaps hash join in this case, poly column must have its rte == 1
1041  // lhs is the point col_var
1042  auto lhs = func_oper->getOwnArg(2);
1043  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
1044  CHECK(rewritten_lhs);
1045  const auto& lhs_ti = rewritten_lhs->get_type_info();
1046 
1047  if (!lhs_ti.is_geometry() && !is_constructed_point(rewritten_lhs.get())) {
1048  // TODO(adb): If ST_Contains is passed geospatial literals instead of columns,
1049  // the function will be expanded during translation rather than during code
1050  // generation. While this scenario does not make sense for the overlaps join, we
1051  // need to detect and abort the overlaps rewrite. Adding a GeospatialConstant
1052  // dervied class to the Analyzer may prove to be a better way to handle geo
1053  // literals, but for now we ensure the LHS type is a geospatial type, which
1054  // would mean the function has not been expanded to the physical types, yet.
1055  LOG(INFO) << "Unable to rewrite " << func_name
1056  << " to overlaps conjunction. LHS input type is neither a geospatial "
1057  "column nor a constructed point"
1058  << func_oper->toString();
1059  return boost::none;
1060  }
1061 
1062  // rhs is coordinates of the poly col
1063  auto rhs = func_oper->getOwnArg(1);
1064  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
1065  CHECK(rewritten_rhs);
1066 
1067  if (has_invalid_join_col_order(lhs.get(), rhs.get()).first) {
1068  LOG(INFO) << "Unable to rewrite " << func_name
1069  << " to overlaps conjunction. Cannot build hash table over LHS type. "
1070  "Check join order."
1071  << func_oper->toString();
1072  return boost::none;
1073  }
1074 
1075  VLOG(1) << "Rewriting " << func_name << " to use overlaps join with lhs as "
1076  << rewritten_lhs->toString() << " and rhs as " << rewritten_rhs->toString();
1077 
1078  overlaps_oper = makeExpr<Analyzer::BinOper>(
1079  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
1080  if (func_name !=
1082  needs_to_return_original_expr = true;
1083  }
1084  }
1085  } else if (rewrite_type == OverlapsJoinRewriteType::RANGE_JOIN) {
1086  auto bin_oper = dynamic_cast<Analyzer::BinOper*>(expr.get());
1087  CHECK(bin_oper);
1088  auto lhs = dynamic_cast<const Analyzer::GeoOperator*>(bin_oper->get_left_operand());
1089  CHECK(lhs);
1090  auto rhs = dynamic_cast<const Analyzer::Constant*>(bin_oper->get_right_operand());
1091  CHECK(rhs);
1092  func_name = lhs->getName();
1093  overlaps_oper =
1094  convert_to_range_join_oper(func_name, expr, bin_oper, lhs, rhs, executor);
1095  needs_to_return_original_expr = true;
1096  }
1097  const auto expr_str = !func_name.empty() ? func_name : expr->toString();
1098  if (overlaps_oper) {
1099  VLOG(1) << "Successfully converted " << expr_str << " to overlaps join";
1100  if (needs_to_return_original_expr) {
1101  return OverlapsJoinConjunction{{expr}, {overlaps_oper}};
1102  } else {
1103  return OverlapsJoinConjunction{{}, {overlaps_oper}};
1104  }
1105  }
1106  VLOG(1) << "Overlaps join not enabled for " << expr_str;
1107  return boost::none;
1108 }
1109 
1119  public:
1121  for (const auto& join_condition : join_quals) {
1122  for (const auto& qual : join_condition.quals) {
1123  auto qual_bin_oper = dynamic_cast<Analyzer::BinOper*>(qual.get());
1124  if (qual_bin_oper) {
1125  join_qual_pairs.emplace_back(qual_bin_oper->get_left_operand(),
1126  qual_bin_oper->get_right_operand());
1127  }
1128  }
1129  }
1130  }
1131 
1132  bool visitFunctionOper(const Analyzer::FunctionOper* func_oper) const override {
1134  const auto lhs = func_oper->getArg(2);
1135  const auto rhs = func_oper->getArg(1);
1136  for (const auto& qual_pair : join_qual_pairs) {
1137  if (*lhs == *qual_pair.first && *rhs == *qual_pair.second) {
1138  return true;
1139  }
1140  }
1141  }
1142  return false;
1143  }
1144 
1145  bool defaultResult() const override { return false; }
1146 
1147  private:
1148  std::vector<std::pair<const Analyzer::Expr*, const Analyzer::Expr*>> join_qual_pairs;
1149 };
1150 
1151 std::list<std::shared_ptr<Analyzer::Expr>> strip_join_covered_filter_quals(
1152  const std::list<std::shared_ptr<Analyzer::Expr>>& quals,
1153  const JoinQualsPerNestingLevel& join_quals) {
1155  return quals;
1156  }
1157 
1158  if (join_quals.empty()) {
1159  return quals;
1160  }
1161 
1162  std::list<std::shared_ptr<Analyzer::Expr>> quals_to_return;
1163 
1164  JoinCoveredQualVisitor visitor(join_quals);
1165  for (const auto& qual : quals) {
1166  if (!visitor.visit(qual.get())) {
1167  // Not a covered qual, don't elide it from the filtered count
1168  quals_to_return.push_back(qual);
1169  }
1170  }
1171 
1172  return quals_to_return;
1173 }
1174 
1175 std::shared_ptr<Analyzer::Expr> fold_expr(const Analyzer::Expr* expr) {
1176  if (!expr) {
1177  return nullptr;
1178  }
1179  const auto expr_no_likelihood = strip_likelihood(expr);
1180  ConstantFoldingVisitor visitor;
1181  auto rewritten_expr = visitor.visit(expr_no_likelihood);
1182  if (visitor.get_num_overflows() > 0 && rewritten_expr->get_type_info().is_integer() &&
1183  rewritten_expr->get_type_info().get_type() != kBIGINT) {
1184  auto rewritten_expr_const =
1185  std::dynamic_pointer_cast<const Analyzer::Constant>(rewritten_expr);
1186  if (!rewritten_expr_const) {
1187  // Integer expression didn't fold completely the first time due to
1188  // overflows in smaller type subexpressions, trying again with a cast
1189  const auto& ti = SQLTypeInfo(kBIGINT, false);
1190  auto bigint_expr_no_likelihood = expr_no_likelihood->deep_copy()->add_cast(ti);
1191  auto rewritten_expr_take2 = visitor.visit(bigint_expr_no_likelihood.get());
1192  auto rewritten_expr_take2_const =
1193  std::dynamic_pointer_cast<Analyzer::Constant>(rewritten_expr_take2);
1194  if (rewritten_expr_take2_const) {
1195  // Managed to fold, switch to the new constant
1196  rewritten_expr = rewritten_expr_take2_const;
1197  }
1198  }
1199  }
1200  const auto expr_with_likelihood = dynamic_cast<const Analyzer::LikelihoodExpr*>(expr);
1201  if (expr_with_likelihood) {
1202  // Add back likelihood
1203  return std::make_shared<Analyzer::LikelihoodExpr>(
1204  rewritten_expr, expr_with_likelihood->get_likelihood());
1205  }
1206  return rewritten_expr;
1207 }
1208 
1210  const Analyzer::ColumnVar* val_side,
1211  const int max_rte_covered) {
1212  if (key_side->getTableKey() == val_side->getTableKey() &&
1213  key_side->get_rte_idx() == val_side->get_rte_idx() &&
1214  key_side->get_rte_idx() > max_rte_covered) {
1215  return true;
1216  }
1217  return false;
1218 }
1219 
1221  std::unordered_map<int, llvm::Value*>& scan_idx_to_hash_pos) {
1222  int ret = INT32_MIN;
1223  for (auto& kv : scan_idx_to_hash_pos) {
1224  if (kv.first > ret) {
1225  ret = kv.first;
1226  }
1227  }
1228  return ret;
1229 }
int8_t tinyintval
Definition: Datum.h:69
Defines data structures for the semantic analysis phase of query processing.
Analyzer::ExpressionPtr rewrite_array_elements(Analyzer::Expr const *expr)
static bool is_poly_mpoly_rewrite_target_func(std::string_view target_func_name)
#define CHECK_EQ(x, y)
Definition: Logger.h:301
#define IS_LOGIC(X)
Definition: sqldefs.h:61
std::shared_ptr< Analyzer::InValues > visitLikeExpr(const Analyzer::LikeExpr *) const override
std::shared_ptr< Analyzer::InValues > visitDateaddExpr(const Analyzer::DateaddExpr *) const override
Datum apply_numeric_op_to_literals(const StringOpInfo &string_op_info)
Definition: StringOps.cpp:916
bool self_join_not_covered_by_left_deep_tree(const Analyzer::ColumnVar *key_side, const Analyzer::ColumnVar *val_side, const int max_rte_covered)
SQLTypes
Definition: sqltypes.h:55
std::shared_ptr< Analyzer::WindowFunction > rewrite_avg_window(const Analyzer::Expr *expr)
bool g_strip_join_covered_quals
Definition: Execute.cpp:107
std::shared_ptr< Analyzer::InValues > visitKeyForString(const Analyzer::KeyForStringExpr *) const override
boost::optional< OverlapsJoinConjunction > rewrite_overlaps_conjunction(const std::shared_ptr< Analyzer::Expr > expr, const std::vector< InputDescriptor > &input_table_info, const OverlapsJoinRewriteType rewrite_type, const Executor *executor)
std::shared_ptr< Analyzer::WindowFunction > rewrite_sum_window(const Analyzer::Expr *expr)
static bool is_overlaps_supported_func(std::string_view target_func_name)
std::shared_ptr< Analyzer::InValues > visitBinOper(const Analyzer::BinOper *bin_oper) const override
#define LOG(tag)
Definition: Logger.h:285
const Expr * get_right_operand() const
Definition: Analyzer.h:456
bool is_constructed_point(const Analyzer::Expr *expr)
Definition: Execute.h:1508
SQLOps
Definition: sqldefs.h:28
Definition: sqldefs.h:34
int8_t boolval
Definition: Datum.h:68
Definition: sqldefs.h:35
Definition: sqldefs.h:37
const TableDescriptor * get_metadata_for_table(const ::shared::TableKey &table_key, bool populate_fragmenter)
#define CHECK_GE(x, y)
Definition: Logger.h:306
bool get_contains_agg() const
Definition: Analyzer.h:81
Definition: sqldefs.h:48
Definition: sqldefs.h:29
std::shared_ptr< Analyzer::Expr > ExpressionPtr
Definition: Analyzer.h:184
size_t getArity() const
Definition: Analyzer.h:1548
const Analyzer::Expr * extract_cast_arg(const Analyzer::Expr *expr)
Definition: Execute.h:201
Definition: sqldefs.h:40
std::vector< JoinCondition > JoinQualsPerNestingLevel
T visit(const Analyzer::Expr *expr) const
Analyzer::ExpressionPtr rewrite_expr(const Analyzer::Expr *expr)
bool isNull() const
Definition: Analyzer.h:2669
#define TRANSIENT_DICT_ID
Definition: DbObjectKeys.h:24
static constexpr std::string_view ST_DWITHIN_POINT_POINT_sv
std::shared_ptr< Analyzer::InValues > aggregateResult(const std::shared_ptr< Analyzer::InValues > &lhs, const std::shared_ptr< Analyzer::InValues > &rhs) const override
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::InValues > visitUOper(const Analyzer::UOper *uoper) const override
const int get_max_rte_scan_table(std::unordered_map< int, llvm::Value * > &scan_idx_to_hash_pos)
static constexpr std::string_view ST_OVERLAPS_sv
std::shared_ptr< Analyzer::Expr > visitBinOper(const Analyzer::BinOper *bin_oper) const override
std::shared_ptr< Analyzer::Expr > RetType
int32_t intval
Definition: Datum.h:71
static constexpr std::string_view ST_DISTANCE_sv
constexpr double f
Definition: Utm.h:31
std::shared_ptr< Analyzer::InValues > visitCharLength(const Analyzer::CharLengthExpr *) const override
std::shared_ptr< Analyzer::InValues > visitInIntegerSet(const Analyzer::InIntegerSet *) const override
SQLOps get_optype() const
Definition: Analyzer.h:452
float floatval
Definition: Datum.h:73
std::shared_ptr< Analyzer::Expr > visitUOper(const Analyzer::UOper *uoper) const override
LiteralArgMap getLiteralArgs() const
Definition: Analyzer.cpp:4077
Classes representing a parse tree.
bool g_enable_hashjoin_many_to_many
Definition: Execute.cpp:104
std::shared_ptr< Analyzer::InValues > visitRegexpExpr(const Analyzer::RegexpExpr *) const override
static bool is_many_to_many_func(std::string_view target_func_name)
int64_t bigintval
Definition: Datum.h:72
static bool is_range_join_rewrite_target_func(std::string_view target_func_name)
std::shared_ptr< Analyzer::InValues > visitAggExpr(const Analyzer::AggExpr *) const override
bool visitFunctionOper(const Analyzer::FunctionOper *func_oper) const override
Definition: sqldefs.h:36
bool foldOper(SQLOps optype, SQLTypes type, Datum lhs, Datum rhs, Datum &result, SQLTypes &result_type) const
int16_t smallintval
Definition: Datum.h:70
std::pair< std::string, bool > apply_string_op_to_literals(const StringOpInfo &string_op_info)
Definition: StringOps.cpp:905
bool defaultResult() const override
std::shared_ptr< Analyzer::Expr > visitStringOper(const Analyzer::StringOper *string_oper) const override
static bool is_poly_point_rewrite_target_func(std::string_view target_func_name)
RetType visitArrayOper(const Analyzer::ArrayExpr *array_expr) const override
bool IsNullDatum(const Datum datum, const SQLTypeInfo &ti)
Definition: Datum.cpp:329
static constexpr std::string_view ST_APPROX_OVERLAPS_MULTIPOLYGON_POINT_sv
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
std::shared_ptr< Analyzer::Expr > visitBinOper(const Analyzer::BinOper *bin_oper) const override
size_t getElementCount() const
Definition: Analyzer.h:2667
SQLTypes decimal_to_int_type(const SQLTypeInfo &ti)
Definition: Datum.cpp:559
Definition: sqldefs.h:33
std::vector< std::shared_ptr< Analyzer::Expr > > chained_string_op_exprs_
Definition: sqldefs.h:39
std::vector< std::pair< const Analyzer::Expr *, const Analyzer::Expr * > > join_qual_pairs
Definition: sqldefs.h:71
Expression class for string functions The &quot;arg&quot; constructor parameter must be an expression that reso...
Definition: Analyzer.h:1479
static std::shared_ptr< Analyzer::Expr > analyzeValue(const std::string &stringval, const bool is_null)
Definition: ParserNode.cpp:143
bool isLocalAlloc() const
Definition: Analyzer.h:2668
SqlStringOpKind get_kind() const
Definition: Analyzer.h:1546
const Analyzer::Expr * getArg(const size_t i) const
Definition: Analyzer.h:2410
#define IS_ARITHMETIC(X)
Definition: sqldefs.h:62
const Expr * get_operand() const
Definition: Analyzer.h:384
Datum get_constval() const
Definition: Analyzer.h:348
Definition: sqldefs.h:31
std::unordered_map< const Analyzer::Expr *, const SQLTypeInfo > casts_
std::shared_ptr< Analyzer::InValues > visitDatediffExpr(const Analyzer::DatediffExpr *) const override
std::shared_ptr< Analyzer::InValues > visitLikelihood(const Analyzer::LikelihoodExpr *) const override
std::shared_ptr< Analyzer::InValues > visitInValues(const Analyzer::InValues *) const override
#define CHECK(condition)
Definition: Logger.h:291
OverlapsJoinRewriteType
boost::optional< OverlapsJoinConjunction > convert_to_range_join_oper(const std::shared_ptr< Analyzer::Expr > expr, const Analyzer::BinOper *range_join_expr, const Analyzer::GeoOperator *lhs, const Analyzer::Constant *rhs)
virtual void collect_rte_idx(std::set< int > &rte_idx_set) const
Definition: Analyzer.h:110
Definition: sqldefs.h:32
const Expr * get_left_operand() const
Definition: Analyzer.h:455
Common Enum definitions for SQL processing.
std::shared_ptr< Analyzer::InValues > visitCaseExpr(const Analyzer::CaseExpr *) const override
Definition: sqltypes.h:62
JoinCoveredQualVisitor(const JoinQualsPerNestingLevel &join_quals)
const std::shared_ptr< Analyzer::Expr > get_own_right_operand() const
Definition: Analyzer.h:460
std::string getName() const
Definition: Analyzer.h:2406
int32_t get_rte_idx() const
Definition: Analyzer.h:202
Definition: Datum.h:67
bool is_decimal() const
Definition: sqltypes.h:583
size_t getNonLiteralsArity() const
Definition: Analyzer.h:1560
std::shared_ptr< Analyzer::InValues > visitDatetruncExpr(const Analyzer::DatetruncExpr *) const override
Definition: sqldefs.h:38
const std::shared_ptr< Analyzer::Expr > get_own_left_operand() const
Definition: Analyzer.h:457
std::vector< std::shared_ptr< Analyzer::Expr > > getOwnArgs() const
Definition: Analyzer.h:1572
SQLOps get_optype() const
Definition: Analyzer.h:383
#define VLOG(n)
Definition: Logger.h:387
std::shared_ptr< Analyzer::Expr > fold_expr(const Analyzer::Expr *expr)
shared::TableKey getTableKey() const
Definition: Analyzer.h:199
#define IS_COMPARISON(X)
Definition: sqldefs.h:58
double doubleval
Definition: Datum.h:74
std::shared_ptr< Analyzer::InValues > visitExtractExpr(const Analyzer::ExtractExpr *) const override
static bool is_point_poly_rewrite_target_func(std::string_view target_func_name)
const Analyzer::Expr * getElement(const size_t i) const
Definition: Analyzer.h:2671
SQLQualifier get_qualifier() const
Definition: Analyzer.h:454
const Analyzer::Expr * strip_likelihood(const Analyzer::Expr *expr)
std::shared_ptr< Analyzer::InValues > visitSampleRatio(const Analyzer::SampleRatioExpr *) const override
std::shared_ptr< Analyzer::InValues > visitCardinality(const Analyzer::CardinalityExpr *) const override