OmniSciDB  eb3a3d0a03
 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 2021 OmniSci, 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 
33 namespace {
34 
35 class OrToInVisitor : public ScalarExprVisitor<std::shared_ptr<Analyzer::InValues>> {
36  protected:
37  std::shared_ptr<Analyzer::InValues> visitBinOper(
38  const Analyzer::BinOper* bin_oper) const override {
39  switch (bin_oper->get_optype()) {
40  case kEQ: {
41  const auto rhs_owned = bin_oper->get_own_right_operand();
42  auto rhs_no_cast = extract_cast_arg(rhs_owned.get());
43  if (!dynamic_cast<const Analyzer::Constant*>(rhs_no_cast)) {
44  return nullptr;
45  }
46  const auto arg = bin_oper->get_own_left_operand();
47  const auto& arg_ti = arg->get_type_info();
48  auto rhs = rhs_no_cast->deep_copy()->add_cast(arg_ti);
49  return makeExpr<Analyzer::InValues>(
50  arg, std::list<std::shared_ptr<Analyzer::Expr>>{rhs});
51  }
52  case kOR: {
53  return aggregateResult(visit(bin_oper->get_left_operand()),
54  visit(bin_oper->get_right_operand()));
55  }
56  default:
57  break;
58  }
59  return nullptr;
60  }
61 
62  std::shared_ptr<Analyzer::InValues> visitUOper(
63  const Analyzer::UOper* uoper) const override {
64  return nullptr;
65  }
66 
67  std::shared_ptr<Analyzer::InValues> visitInValues(
68  const Analyzer::InValues*) const override {
69  return nullptr;
70  }
71 
72  std::shared_ptr<Analyzer::InValues> visitInIntegerSet(
73  const Analyzer::InIntegerSet*) const override {
74  return nullptr;
75  }
76 
77  std::shared_ptr<Analyzer::InValues> visitCharLength(
78  const Analyzer::CharLengthExpr*) const override {
79  return nullptr;
80  }
81 
82  std::shared_ptr<Analyzer::InValues> visitKeyForString(
83  const Analyzer::KeyForStringExpr*) const override {
84  return nullptr;
85  }
86 
87  std::shared_ptr<Analyzer::InValues> visitSampleRatio(
88  const Analyzer::SampleRatioExpr*) const override {
89  return nullptr;
90  }
91 
92  std::shared_ptr<Analyzer::InValues> visitCardinality(
93  const Analyzer::CardinalityExpr*) const override {
94  return nullptr;
95  }
96 
97  std::shared_ptr<Analyzer::InValues> visitLikeExpr(
98  const Analyzer::LikeExpr*) const override {
99  return nullptr;
100  }
101 
102  std::shared_ptr<Analyzer::InValues> visitRegexpExpr(
103  const Analyzer::RegexpExpr*) const override {
104  return nullptr;
105  }
106 
107  std::shared_ptr<Analyzer::InValues> visitCaseExpr(
108  const Analyzer::CaseExpr*) const override {
109  return nullptr;
110  }
111 
112  std::shared_ptr<Analyzer::InValues> visitDatetruncExpr(
113  const Analyzer::DatetruncExpr*) const override {
114  return nullptr;
115  }
116 
117  std::shared_ptr<Analyzer::InValues> visitDatediffExpr(
118  const Analyzer::DatediffExpr*) const override {
119  return nullptr;
120  }
121 
122  std::shared_ptr<Analyzer::InValues> visitDateaddExpr(
123  const Analyzer::DateaddExpr*) const override {
124  return nullptr;
125  }
126 
127  std::shared_ptr<Analyzer::InValues> visitExtractExpr(
128  const Analyzer::ExtractExpr*) const override {
129  return nullptr;
130  }
131 
132  std::shared_ptr<Analyzer::InValues> visitLikelihood(
133  const Analyzer::LikelihoodExpr*) const override {
134  return nullptr;
135  }
136 
137  std::shared_ptr<Analyzer::InValues> visitAggExpr(
138  const Analyzer::AggExpr*) const override {
139  return nullptr;
140  }
141 
142  std::shared_ptr<Analyzer::InValues> aggregateResult(
143  const std::shared_ptr<Analyzer::InValues>& lhs,
144  const std::shared_ptr<Analyzer::InValues>& rhs) const override {
145  if (!lhs || !rhs) {
146  return nullptr;
147  }
148 
149  if (lhs->get_arg()->get_type_info() == rhs->get_arg()->get_type_info() &&
150  (*lhs->get_arg() == *rhs->get_arg())) {
151  auto union_values = lhs->get_value_list();
152  const auto& rhs_values = rhs->get_value_list();
153  union_values.insert(union_values.end(), rhs_values.begin(), rhs_values.end());
154  return makeExpr<Analyzer::InValues>(lhs->get_own_arg(), union_values);
155  }
156  return nullptr;
157  }
158 };
159 
161  protected:
162  std::shared_ptr<Analyzer::Expr> visitBinOper(
163  const Analyzer::BinOper* bin_oper) const override {
164  OrToInVisitor simple_visitor;
165  if (bin_oper->get_optype() == kOR) {
166  auto rewritten = simple_visitor.visit(bin_oper);
167  if (rewritten) {
168  return rewritten;
169  }
170  }
171  auto lhs = bin_oper->get_own_left_operand();
172  auto rhs = bin_oper->get_own_right_operand();
173  auto rewritten_lhs = visit(lhs.get());
174  auto rewritten_rhs = visit(rhs.get());
175  return makeExpr<Analyzer::BinOper>(bin_oper->get_type_info(),
176  bin_oper->get_contains_agg(),
177  bin_oper->get_optype(),
178  bin_oper->get_qualifier(),
179  rewritten_lhs ? rewritten_lhs : lhs,
180  rewritten_rhs ? rewritten_rhs : rhs);
181  }
182 };
183 
185  protected:
187 
188  RetType visitArrayOper(const Analyzer::ArrayExpr* array_expr) const override {
189  std::vector<std::shared_ptr<Analyzer::Expr>> args_copy;
190  for (size_t i = 0; i < array_expr->getElementCount(); ++i) {
191  auto const element_expr_ptr = visit(array_expr->getElement(i));
192  auto const& element_expr_type_info = element_expr_ptr->get_type_info();
193 
194  if (!element_expr_type_info.is_string() ||
195  element_expr_type_info.get_compression() != kENCODING_NONE) {
196  args_copy.push_back(element_expr_ptr);
197  } else {
198  auto transient_dict_type_info = element_expr_type_info;
199 
200  transient_dict_type_info.set_compression(kENCODING_DICT);
201  transient_dict_type_info.set_comp_param(TRANSIENT_DICT_ID);
202  transient_dict_type_info.set_fixed_size();
203  args_copy.push_back(element_expr_ptr->add_cast(transient_dict_type_info));
204  }
205  }
206 
207  const auto& type_info = array_expr->get_type_info();
208  return makeExpr<Analyzer::ArrayExpr>(
209  type_info, args_copy, array_expr->isNull(), array_expr->isLocalAlloc());
210  }
211 };
212 
214  template <typename T>
215  bool foldComparison(SQLOps optype, T t1, T t2) const {
216  switch (optype) {
217  case kEQ:
218  return t1 == t2;
219  case kNE:
220  return t1 != t2;
221  case kLT:
222  return t1 < t2;
223  case kLE:
224  return t1 <= t2;
225  case kGT:
226  return t1 > t2;
227  case kGE:
228  return t1 >= t2;
229  default:
230  break;
231  }
232  throw std::runtime_error("Unable to fold");
233  return false;
234  }
235 
236  template <typename T>
237  bool foldLogic(SQLOps optype, T t1, T t2) const {
238  switch (optype) {
239  case kAND:
240  return t1 && t2;
241  case kOR:
242  return t1 || t2;
243  case kNOT:
244  return !t1;
245  default:
246  break;
247  }
248  throw std::runtime_error("Unable to fold");
249  return false;
250  }
251 
252  template <typename T>
253  T foldArithmetic(SQLOps optype, T t1, T t2) const {
254  bool t2_is_zero = (t2 == (t2 - t2));
255  bool t2_is_negative = (t2 < (t2 - t2));
256  switch (optype) {
257  case kPLUS:
258  // The MIN limit for float and double is the smallest representable value,
259  // not the lowest negative value! Switching to C++11 lowest.
260  if ((t2_is_negative && t1 < std::numeric_limits<T>::lowest() - t2) ||
261  (!t2_is_negative && t1 > std::numeric_limits<T>::max() - t2)) {
262  num_overflows_++;
263  throw std::runtime_error("Plus overflow");
264  }
265  return t1 + t2;
266  case kMINUS:
267  if ((t2_is_negative && t1 > std::numeric_limits<T>::max() + t2) ||
268  (!t2_is_negative && t1 < std::numeric_limits<T>::lowest() + t2)) {
269  num_overflows_++;
270  throw std::runtime_error("Minus overflow");
271  }
272  return t1 - t2;
273  case kMULTIPLY: {
274  if (t2_is_zero) {
275  return t2;
276  }
277  auto ct1 = t1;
278  auto ct2 = t2;
279  // Need to keep t2's sign on the left
280  if (t2_is_negative) {
281  if (t1 == std::numeric_limits<T>::lowest() ||
282  t2 == std::numeric_limits<T>::lowest()) {
283  // negation could overflow - bail
284  num_overflows_++;
285  throw std::runtime_error("Mul neg overflow");
286  }
287  ct1 = -t1; // ct1 gets t2's negativity
288  ct2 = -t2; // ct2 is now positive
289  }
290  // Don't check overlow if we are folding FP mul by a fraction
291  bool ct2_is_fraction = (ct2 < (ct2 / ct2));
292  if (!ct2_is_fraction) {
293  if (ct1 > std::numeric_limits<T>::max() / ct2 ||
294  ct1 < std::numeric_limits<T>::lowest() / ct2) {
295  num_overflows_++;
296  throw std::runtime_error("Mul overflow");
297  }
298  }
299  return t1 * t2;
300  }
301  case kDIVIDE:
302  if (t2_is_zero) {
303  throw std::runtime_error("Will not fold division by zero");
304  }
305  return t1 / t2;
306  default:
307  break;
308  }
309  throw std::runtime_error("Unable to fold");
310  }
311 
312  bool foldOper(SQLOps optype,
313  SQLTypes type,
314  Datum lhs,
315  Datum rhs,
316  Datum& result,
317  SQLTypes& result_type) const {
318  result_type = type;
319 
320  try {
321  switch (type) {
322  case kBOOLEAN:
323  if (IS_COMPARISON(optype)) {
324  result.boolval = foldComparison<bool>(optype, lhs.boolval, rhs.boolval);
325  result_type = kBOOLEAN;
326  return true;
327  }
328  if (IS_LOGIC(optype)) {
329  result.boolval = foldLogic<bool>(optype, lhs.boolval, rhs.boolval);
330  result_type = kBOOLEAN;
331  return true;
332  }
333  CHECK(!IS_ARITHMETIC(optype));
334  break;
335  case kTINYINT:
336  if (IS_COMPARISON(optype)) {
337  result.boolval =
338  foldComparison<int8_t>(optype, lhs.tinyintval, rhs.tinyintval);
339  result_type = kBOOLEAN;
340  return true;
341  }
342  if (IS_ARITHMETIC(optype)) {
343  result.tinyintval =
344  foldArithmetic<int8_t>(optype, lhs.tinyintval, rhs.tinyintval);
345  result_type = kTINYINT;
346  return true;
347  }
348  CHECK(!IS_LOGIC(optype));
349  break;
350  case kSMALLINT:
351  if (IS_COMPARISON(optype)) {
352  result.boolval =
353  foldComparison<int16_t>(optype, lhs.smallintval, rhs.smallintval);
354  result_type = kBOOLEAN;
355  return true;
356  }
357  if (IS_ARITHMETIC(optype)) {
358  result.smallintval =
359  foldArithmetic<int16_t>(optype, lhs.smallintval, rhs.smallintval);
360  result_type = kSMALLINT;
361  return true;
362  }
363  CHECK(!IS_LOGIC(optype));
364  break;
365  case kINT:
366  if (IS_COMPARISON(optype)) {
367  result.boolval = foldComparison<int32_t>(optype, lhs.intval, rhs.intval);
368  result_type = kBOOLEAN;
369  return true;
370  }
371  if (IS_ARITHMETIC(optype)) {
372  result.intval = foldArithmetic<int32_t>(optype, lhs.intval, rhs.intval);
373  result_type = kINT;
374  return true;
375  }
376  CHECK(!IS_LOGIC(optype));
377  break;
378  case kBIGINT:
379  if (IS_COMPARISON(optype)) {
380  result.boolval =
381  foldComparison<int64_t>(optype, lhs.bigintval, rhs.bigintval);
382  result_type = kBOOLEAN;
383  return true;
384  }
385  if (IS_ARITHMETIC(optype)) {
386  result.bigintval =
387  foldArithmetic<int64_t>(optype, lhs.bigintval, rhs.bigintval);
388  result_type = kBIGINT;
389  return true;
390  }
391  CHECK(!IS_LOGIC(optype));
392  break;
393  case kFLOAT:
394  if (IS_COMPARISON(optype)) {
395  result.boolval = foldComparison<float>(optype, lhs.floatval, rhs.floatval);
396  result_type = kBOOLEAN;
397  return true;
398  }
399  if (IS_ARITHMETIC(optype)) {
400  result.floatval = foldArithmetic<float>(optype, lhs.floatval, rhs.floatval);
401  result_type = kFLOAT;
402  return true;
403  }
404  CHECK(!IS_LOGIC(optype));
405  break;
406  case kDOUBLE:
407  if (IS_COMPARISON(optype)) {
408  result.boolval = foldComparison<double>(optype, lhs.doubleval, rhs.doubleval);
409  result_type = kBOOLEAN;
410  return true;
411  }
412  if (IS_ARITHMETIC(optype)) {
413  result.doubleval =
414  foldArithmetic<double>(optype, lhs.doubleval, rhs.doubleval);
415  result_type = kDOUBLE;
416  return true;
417  }
418  CHECK(!IS_LOGIC(optype));
419  break;
420  default:
421  break;
422  }
423  } catch (...) {
424  return false;
425  }
426  return false;
427  }
428 
429  std::shared_ptr<Analyzer::Expr> visitUOper(
430  const Analyzer::UOper* uoper) const override {
431  const auto unvisited_operand = uoper->get_operand();
432  const auto optype = uoper->get_optype();
433  const auto& ti = uoper->get_type_info();
434  if (optype == kCAST) {
435  // Cache the cast type so it could be used in operand rewriting/folding
436  casts_.insert({unvisited_operand, ti});
437  }
438  const auto operand = visit(unvisited_operand);
439 
440  const auto& operand_ti = operand->get_type_info();
441  const auto operand_type =
442  operand_ti.is_decimal() ? decimal_to_int_type(operand_ti) : operand_ti.get_type();
443  const auto const_operand =
444  std::dynamic_pointer_cast<const Analyzer::Constant>(operand);
445 
446  if (const_operand) {
447  const auto operand_datum = const_operand->get_constval();
448  Datum zero_datum = {};
449  Datum result_datum = {};
450  SQLTypes result_type;
451  switch (optype) {
452  case kNOT: {
453  if (foldOper(kEQ,
454  operand_type,
455  zero_datum,
456  operand_datum,
457  result_datum,
458  result_type)) {
459  CHECK_EQ(result_type, kBOOLEAN);
460  return makeExpr<Analyzer::Constant>(result_type, false, result_datum);
461  }
462  break;
463  }
464  case kUMINUS: {
465  if (foldOper(kMINUS,
466  operand_type,
467  zero_datum,
468  operand_datum,
469  result_datum,
470  result_type)) {
471  if (!operand_ti.is_decimal()) {
472  return makeExpr<Analyzer::Constant>(result_type, false, result_datum);
473  }
474  return makeExpr<Analyzer::Constant>(ti, false, result_datum);
475  }
476  break;
477  }
478  case kCAST: {
479  // Trying to fold number to number casts only
480  if (!ti.is_number() || !operand_ti.is_number()) {
481  break;
482  }
483  // Disallowing folding of FP to DECIMAL casts for now:
484  // allowing them would make this test pass:
485  // update dectest set d=cast( 1234.0 as float );
486  // which is expected to throw in Update.ImplicitCastToNumericTypes
487  // due to cast codegen currently not supporting these casts
488  if (ti.is_decimal() && operand_ti.is_fp()) {
489  break;
490  }
491  auto operand_copy = const_operand->deep_copy();
492  auto cast_operand = operand_copy->add_cast(ti);
493  auto const_cast_operand =
494  std::dynamic_pointer_cast<const Analyzer::Constant>(cast_operand);
495  if (const_cast_operand) {
496  auto const_cast_datum = const_cast_operand->get_constval();
497  return makeExpr<Analyzer::Constant>(ti, false, const_cast_datum);
498  }
499  }
500  default:
501  break;
502  }
503  }
504 
505  return makeExpr<Analyzer::UOper>(
506  uoper->get_type_info(), uoper->get_contains_agg(), optype, operand);
507  }
508 
509  std::shared_ptr<Analyzer::Expr> visitBinOper(
510  const Analyzer::BinOper* bin_oper) const override {
511  const auto optype = bin_oper->get_optype();
512  auto ti = bin_oper->get_type_info();
513  auto left_operand = bin_oper->get_own_left_operand();
514  auto right_operand = bin_oper->get_own_right_operand();
515 
516  // Check if bin_oper result is cast to a larger int or fp type
517  if (casts_.find(bin_oper) != casts_.end()) {
518  const auto cast_ti = casts_[bin_oper];
519  const auto& lhs_ti = bin_oper->get_left_operand()->get_type_info();
520  // Propagate cast down to the operands for folding
521  if ((cast_ti.is_integer() || cast_ti.is_fp()) && lhs_ti.is_integer() &&
522  cast_ti.get_size() > lhs_ti.get_size() &&
523  (optype == kMINUS || optype == kPLUS || optype == kMULTIPLY)) {
524  // Before folding, cast the operands to the bigger type to avoid overflows.
525  // Currently upcasting smaller integer types to larger integers or double.
526  left_operand = left_operand->deep_copy()->add_cast(cast_ti);
527  right_operand = right_operand->deep_copy()->add_cast(cast_ti);
528  ti = cast_ti;
529  }
530  }
531 
532  const auto lhs = visit(left_operand.get());
533  const auto rhs = visit(right_operand.get());
534 
535  auto const_lhs = std::dynamic_pointer_cast<Analyzer::Constant>(lhs);
536  auto const_rhs = std::dynamic_pointer_cast<Analyzer::Constant>(rhs);
537  const auto& lhs_ti = lhs->get_type_info();
538  const auto& rhs_ti = rhs->get_type_info();
539  auto lhs_type = lhs_ti.is_decimal() ? decimal_to_int_type(lhs_ti) : lhs_ti.get_type();
540  auto rhs_type = rhs_ti.is_decimal() ? decimal_to_int_type(rhs_ti) : rhs_ti.get_type();
541 
542  if (const_lhs && const_rhs && lhs_type == rhs_type) {
543  auto lhs_datum = const_lhs->get_constval();
544  auto rhs_datum = const_rhs->get_constval();
545  Datum result_datum = {};
546  SQLTypes result_type;
547  if (foldOper(optype, lhs_type, lhs_datum, rhs_datum, result_datum, result_type)) {
548  // Fold all ops that don't take in decimal operands, and also decimal comparisons
549  if (!lhs_ti.is_decimal() || IS_COMPARISON(optype)) {
550  return makeExpr<Analyzer::Constant>(result_type, false, result_datum);
551  }
552  // Decimal arithmetic has been done as kBIGINT. Selectively fold some decimal ops,
553  // using result_datum and BinOper expr typeinfo which was adjusted for these ops.
554  if (optype == kMINUS || optype == kPLUS || optype == kMULTIPLY) {
555  return makeExpr<Analyzer::Constant>(ti, false, result_datum);
556  }
557  }
558  }
559 
560  if (optype == kAND && lhs_type == rhs_type && lhs_type == kBOOLEAN) {
561  if (const_rhs && !const_rhs->get_is_null()) {
562  auto rhs_datum = const_rhs->get_constval();
563  if (rhs_datum.boolval == false) {
564  Datum d;
565  d.boolval = false;
566  // lhs && false --> false
567  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
568  }
569  // lhs && true --> lhs
570  return lhs;
571  }
572  if (const_lhs && !const_lhs->get_is_null()) {
573  auto lhs_datum = const_lhs->get_constval();
574  if (lhs_datum.boolval == false) {
575  Datum d;
576  d.boolval = false;
577  // false && rhs --> false
578  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
579  }
580  // true && rhs --> rhs
581  return rhs;
582  }
583  }
584  if (optype == kOR && lhs_type == rhs_type && lhs_type == kBOOLEAN) {
585  if (const_rhs && !const_rhs->get_is_null()) {
586  auto rhs_datum = const_rhs->get_constval();
587  if (rhs_datum.boolval == true) {
588  Datum d;
589  d.boolval = true;
590  // lhs || true --> true
591  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
592  }
593  // lhs || false --> lhs
594  return lhs;
595  }
596  if (const_lhs && !const_lhs->get_is_null()) {
597  auto lhs_datum = const_lhs->get_constval();
598  if (lhs_datum.boolval == true) {
599  Datum d;
600  d.boolval = true;
601  // true || rhs --> true
602  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
603  }
604  // false || rhs --> rhs
605  return rhs;
606  }
607  }
608  if (*lhs == *rhs) {
609  // Tautologies: v=v; v<=v; v>=v
610  if (optype == kEQ || optype == kLE || optype == kGE) {
611  Datum d;
612  d.boolval = true;
613  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
614  }
615  // Contradictions: v!=v; v<v; v>v
616  if (optype == kNE || optype == kLT || optype == kGT) {
617  Datum d;
618  d.boolval = false;
619  return makeExpr<Analyzer::Constant>(kBOOLEAN, false, d);
620  }
621  // v-v
622  if (optype == kMINUS) {
623  Datum d = {};
624  return makeExpr<Analyzer::Constant>(lhs_type, false, d);
625  }
626  }
627  // Convert fp division by a constant to multiplication by 1/constant
628  if (optype == kDIVIDE && const_rhs && rhs_ti.is_fp()) {
629  auto rhs_datum = const_rhs->get_constval();
630  std::shared_ptr<Analyzer::Expr> recip_rhs = nullptr;
631  if (rhs_ti.get_type() == kFLOAT) {
632  if (rhs_datum.floatval == 1.0) {
633  return lhs;
634  }
635  auto f = std::fabs(rhs_datum.floatval);
636  if (f > 1.0 || (f != 0.0 && 1.0 < f * std::numeric_limits<float>::max())) {
637  rhs_datum.floatval = 1.0 / rhs_datum.floatval;
638  recip_rhs = makeExpr<Analyzer::Constant>(rhs_type, false, rhs_datum);
639  }
640  } else if (rhs_ti.get_type() == kDOUBLE) {
641  if (rhs_datum.doubleval == 1.0) {
642  return lhs;
643  }
644  auto d = std::fabs(rhs_datum.doubleval);
645  if (d > 1.0 || (d != 0.0 && 1.0 < d * std::numeric_limits<double>::max())) {
646  rhs_datum.doubleval = 1.0 / rhs_datum.doubleval;
647  recip_rhs = makeExpr<Analyzer::Constant>(rhs_type, false, rhs_datum);
648  }
649  }
650  if (recip_rhs) {
651  return makeExpr<Analyzer::BinOper>(ti,
652  bin_oper->get_contains_agg(),
653  kMULTIPLY,
654  bin_oper->get_qualifier(),
655  lhs,
656  recip_rhs);
657  }
658  }
659 
660  return makeExpr<Analyzer::BinOper>(ti,
661  bin_oper->get_contains_agg(),
662  bin_oper->get_optype(),
663  bin_oper->get_qualifier(),
664  lhs,
665  rhs);
666  }
667 
668  std::shared_ptr<Analyzer::Expr> visitLower(
669  const Analyzer::LowerExpr* lower_expr) const override {
670  const auto constant_arg_expr =
671  dynamic_cast<const Analyzer::Constant*>(lower_expr->get_arg());
672  if (constant_arg_expr) {
674  boost::locale::to_lower(*constant_arg_expr->get_constval().stringval));
675  }
676  return makeExpr<Analyzer::LowerExpr>(lower_expr->get_own_arg());
677  }
678 
679  protected:
680  mutable std::unordered_map<const Analyzer::Expr*, const SQLTypeInfo> casts_;
681  mutable int32_t num_overflows_;
682 
683  public:
684  ConstantFoldingVisitor() : num_overflows_(0) {}
685  int32_t get_num_overflows() { return num_overflows_; }
686  void reset_num_overflows() { num_overflows_ = 0; }
687 };
688 
690  const auto with_likelihood = dynamic_cast<const Analyzer::LikelihoodExpr*>(expr);
691  if (!with_likelihood) {
692  return expr;
693  }
694  return with_likelihood->get_arg();
695 }
696 
697 } // namespace
698 
700  return ArrayElementStringLiteralEncodingVisitor().visit(expr);
701 }
702 
704  const auto sum_window = rewrite_sum_window(expr);
705  if (sum_window) {
706  return sum_window;
707  }
708  const auto avg_window = rewrite_avg_window(expr);
709  if (avg_window) {
710  return avg_window;
711  }
712  const auto expr_no_likelihood = strip_likelihood(expr);
713  // The following check is not strictly needed, but seems silly to transform a
714  // simple string comparison to an IN just to codegen the same thing anyway.
715 
716  RecursiveOrToInVisitor visitor;
717  auto rewritten_expr = visitor.visit(expr_no_likelihood);
718  const auto expr_with_likelihood =
719  std::dynamic_pointer_cast<const Analyzer::LikelihoodExpr>(rewritten_expr);
720  if (expr_with_likelihood) {
721  // Add back likelihood
722  return std::make_shared<Analyzer::LikelihoodExpr>(
723  rewritten_expr, expr_with_likelihood->get_likelihood());
724  }
725  return rewritten_expr;
726 }
727 
728 namespace {
729 
730 static const std::unordered_set<std::string> overlaps_supported_functions = {
731  "ST_Contains_MultiPolygon_Point",
732  "ST_Contains_Polygon_Point",
733  "ST_cContains_MultiPolygon_Point", // compressed coords version
734  "ST_cContains_Polygon_Point",
735  "ST_Contains_Polygon_Polygon",
736  "ST_Contains_Polygon_MultiPolygon",
737  "ST_Contains_MultiPolygon_MultiPolygon",
738  "ST_Contains_MultiPolygon_Polygon",
739  "ST_Intersects_Polygon_Point",
740  "ST_Intersects_Polygon_Polygon",
741  "ST_Intersects_Polygon_MultiPolygon",
742  "ST_Intersects_MultiPolygon_MultiPolygon",
743  "ST_Intersects_MultiPolygon_Polygon",
744  "ST_Intersects_MultiPolygon_Point",
745  "ST_Approx_Overlaps_MultiPolygon_Point",
746  "ST_Overlaps"};
747 
748 static const std::unordered_set<std::string> requires_many_to_many = {
749  "ST_Contains_Polygon_Polygon",
750  "ST_Contains_Polygon_MultiPolygon",
751  "ST_Contains_MultiPolygon_MultiPolygon",
752  "ST_Contains_MultiPolygon_Polygon",
753  "ST_Intersects_Polygon_Polygon",
754  "ST_Intersects_Polygon_MultiPolygon",
755  "ST_Intersects_MultiPolygon_MultiPolygon",
756  "ST_Intersects_MultiPolygon_Polygon"};
757 
758 } // namespace
759 
760 boost::optional<OverlapsJoinConjunction> rewrite_overlaps_conjunction(
761  const std::shared_ptr<Analyzer::Expr> expr) {
762  auto func_oper = dynamic_cast<Analyzer::FunctionOper*>(expr.get());
763  if (func_oper) {
764  const auto needs_many_many = [func_oper]() {
765  return requires_many_to_many.find(func_oper->getName()) !=
766  requires_many_to_many.end();
767  };
768  // TODO(adb): consider converting unordered set to an unordered map, potentially
769  // storing the rewrite function we want to apply in the map
770  if (overlaps_supported_functions.find(func_oper->getName()) !=
772  if (!g_enable_hashjoin_many_to_many && needs_many_many()) {
773  LOG(WARNING) << "Many-to-many hashjoin support is disabled, unable to rewrite "
774  << func_oper->toString() << " to use accelerated geo join.";
775  return boost::none;
776  }
777 
778  DeepCopyVisitor deep_copy_visitor;
779  if (func_oper->getName() == "ST_Overlaps") {
780  CHECK_GE(func_oper->getArity(), size_t(2));
781  // return empty quals, overlaps join quals
782  // TODO(adb): we will likely want to actually check for true overlaps, but this
783  // works for now
784 
785  auto lhs = func_oper->getOwnArg(0);
786  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
787  CHECK(rewritten_lhs);
788 
789  auto rhs = func_oper->getOwnArg(1);
790  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
791  CHECK(rewritten_rhs);
792 
793  auto overlaps_oper = makeExpr<Analyzer::BinOper>(
794  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
795  return OverlapsJoinConjunction{{}, {overlaps_oper}};
796  }
797 
798  // TODO(jclay): This will work for Poly_Poly,but needs to change for others.
799  CHECK_GE(func_oper->getArity(), size_t(4));
800  if (func_oper->getName() == "ST_Contains_Polygon_Polygon" ||
801  func_oper->getName() == "ST_Intersects_Polygon_Polygon" ||
802  func_oper->getName() == "ST_Intersects_MultiPolygon_MultiPolygon" ||
803  func_oper->getName() == "ST_Intersects_MultiPolygon_Polygon" ||
804  func_oper->getName() == "ST_Intersects_Polygon_MultiPolygon") {
805  auto lhs = func_oper->getOwnArg(3);
806  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
807  CHECK(rewritten_lhs);
808  auto rhs = func_oper->getOwnArg(1);
809  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
810  CHECK(rewritten_rhs);
811 
812  auto overlaps_oper = makeExpr<Analyzer::BinOper>(
813  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
814 
815  VLOG(1) << "Successfully converted to overlaps join";
816  return OverlapsJoinConjunction{{expr}, {overlaps_oper}};
817  }
818 
819  auto lhs = func_oper->getOwnArg(2);
820  auto rewritten_lhs = deep_copy_visitor.visit(lhs.get());
821  CHECK(rewritten_lhs);
822  const auto& lhs_ti = rewritten_lhs->get_type_info();
823 
824  if (!lhs_ti.is_geometry() && !is_constructed_point(rewritten_lhs.get())) {
825  // TODO(adb): If ST_Contains is passed geospatial literals instead of columns, the
826  // function will be expanded during translation rather than during code
827  // generation. While this scenario does not make sense for the overlaps join, we
828  // need to detect and abort the overlaps rewrite. Adding a GeospatialConstant
829  // dervied class to the Analyzer may prove to be a better way to handle geo
830  // literals, but for now we ensure the LHS type is a geospatial type, which would
831  // mean the function has not been expanded to the physical types, yet.
832 
833  LOG(INFO) << "Unable to rewrite " << func_oper->getName()
834  << " to overlaps conjunction. LHS input type is neither a geospatial "
835  "column nor a constructed point\n"
836  << func_oper->toString();
837 
838  return boost::none;
839  }
840 
841  // Read the bounds arg from the ST_Contains FuncOper (second argument)instead of the
842  // poly column (first argument)
843  auto rhs = func_oper->getOwnArg(1);
844  auto rewritten_rhs = deep_copy_visitor.visit(rhs.get());
845  CHECK(rewritten_rhs);
846 
847  // Check for compatible join ordering. If the join ordering does not match expected
848  // ordering for overlaps, the join builder will fail.
849  std::set<int> lhs_rte_idx;
850  lhs->collect_rte_idx(lhs_rte_idx);
851  CHECK(!lhs_rte_idx.empty());
852  std::set<int> rhs_rte_idx;
853  rhs->collect_rte_idx(rhs_rte_idx);
854  CHECK(!rhs_rte_idx.empty());
855 
856  if (lhs_rte_idx.size() > 1 || rhs_rte_idx.size() > 1 || lhs_rte_idx > rhs_rte_idx) {
857  LOG(INFO) << "Unable to rewrite " << func_oper->getName()
858  << " to overlaps conjunction. Cannot build hash table over LHS type. "
859  "Check join order.\n"
860  << func_oper->toString();
861  return boost::none;
862  }
863 
864  VLOG(1) << "Rewritten to use overlaps join with lhs as "
865  << rewritten_lhs->toString() << " and rhs as " << rewritten_rhs->toString();
866 
867  auto overlaps_oper = makeExpr<Analyzer::BinOper>(
868  kBOOLEAN, kOVERLAPS, kONE, rewritten_lhs, rewritten_rhs);
869 
870  VLOG(1) << "Successfully converted to overlaps join";
871  if (func_oper->getName() == "ST_Approx_Overlaps_MultiPolygon_Point"sv) {
872  return OverlapsJoinConjunction{{}, {overlaps_oper}};
873  } else {
874  return OverlapsJoinConjunction{{expr}, {overlaps_oper}};
875  }
876  } else {
877  VLOG(1) << "Overlaps join not enabled for " << func_oper->getName();
878  }
879  return boost::none;
880  }
881  auto bin_oper = dynamic_cast<Analyzer::BinOper*>(expr.get());
882  if (g_enable_distance_rangejoin && bin_oper &&
883  (bin_oper->get_optype() == kLE || bin_oper->get_optype() == kLT)) {
884  auto lhs = dynamic_cast<const Analyzer::GeoOperator*>(bin_oper->get_left_operand());
885  auto rhs = dynamic_cast<const Analyzer::Constant*>(bin_oper->get_right_operand());
886  if (lhs && rhs && lhs->getName() == "ST_Distance") {
887  const auto args = lhs->getChildExprs();
888  CHECK_GE(args.size(), size_t(2));
889  auto l_arg = dynamic_cast<const Analyzer::ColumnVar*>(args[0]);
890  auto r_arg = dynamic_cast<const Analyzer::ColumnVar*>(args[1]);
891  if (l_arg && r_arg) {
892  const int64_t hash_table_arg_index =
893  l_arg->get_rte_idx() > r_arg->get_rte_idx() ? 0 : 1;
894  auto hash_table_col_var = args[hash_table_arg_index];
895  if (!hash_table_col_var->get_type_info().is_geometry()) {
896  return boost::none;
897  }
898  const int64_t probe_arg_index = std::max<int64_t>(hash_table_arg_index - 1, 0);
899  auto probe_col_var = args[probe_arg_index]->deep_copy();
900 
901  const bool inclusive = bin_oper->get_optype() == kLE;
902  auto range_expr = makeExpr<Analyzer::RangeOper>(
903  inclusive, inclusive, hash_table_col_var->deep_copy(), rhs->deep_copy());
904  auto overlaps_oper = makeExpr<Analyzer::BinOper>(
905  kBOOLEAN, kOVERLAPS, kONE, probe_col_var, range_expr);
906  return OverlapsJoinConjunction{{expr}, {overlaps_oper}};
907  }
908  }
909  }
910  return boost::none;
911 }
912 
922  public:
924  for (const auto& join_condition : join_quals) {
925  for (const auto& qual : join_condition.quals) {
926  auto qual_bin_oper = dynamic_cast<Analyzer::BinOper*>(qual.get());
927  if (qual_bin_oper) {
928  join_qual_pairs.emplace_back(qual_bin_oper->get_left_operand(),
929  qual_bin_oper->get_right_operand());
930  }
931  }
932  }
933  }
934 
935  bool visitFunctionOper(const Analyzer::FunctionOper* func_oper) const override {
936  if (overlaps_supported_functions.find(func_oper->getName()) !=
938  const auto lhs = func_oper->getArg(2);
939  const auto rhs = func_oper->getArg(1);
940  for (const auto& qual_pair : join_qual_pairs) {
941  if (*lhs == *qual_pair.first && *rhs == *qual_pair.second) {
942  return true;
943  }
944  }
945  }
946  return false;
947  }
948 
949  bool defaultResult() const override { return false; }
950 
951  private:
952  std::vector<std::pair<const Analyzer::Expr*, const Analyzer::Expr*>> join_qual_pairs;
953 };
954 
955 std::list<std::shared_ptr<Analyzer::Expr>> strip_join_covered_filter_quals(
956  const std::list<std::shared_ptr<Analyzer::Expr>>& quals,
957  const JoinQualsPerNestingLevel& join_quals) {
959  return quals;
960  }
961 
962  if (join_quals.empty()) {
963  return quals;
964  }
965 
966  std::list<std::shared_ptr<Analyzer::Expr>> quals_to_return;
967 
968  JoinCoveredQualVisitor visitor(join_quals);
969  for (const auto& qual : quals) {
970  if (!visitor.visit(qual.get())) {
971  // Not a covered qual, don't elide it from the filtered count
972  quals_to_return.push_back(qual);
973  }
974  }
975 
976  return quals_to_return;
977 }
978 
979 std::shared_ptr<Analyzer::Expr> fold_expr(const Analyzer::Expr* expr) {
980  if (!expr) {
981  return nullptr;
982  }
983  const auto expr_no_likelihood = strip_likelihood(expr);
984  ConstantFoldingVisitor visitor;
985  auto rewritten_expr = visitor.visit(expr_no_likelihood);
986  if (visitor.get_num_overflows() > 0 && rewritten_expr->get_type_info().is_integer() &&
987  rewritten_expr->get_type_info().get_type() != kBIGINT) {
988  auto rewritten_expr_const =
989  std::dynamic_pointer_cast<const Analyzer::Constant>(rewritten_expr);
990  if (!rewritten_expr_const) {
991  // Integer expression didn't fold completely the first time due to
992  // overflows in smaller type subexpressions, trying again with a cast
993  const auto& ti = SQLTypeInfo(kBIGINT, false);
994  auto bigint_expr_no_likelihood = expr_no_likelihood->deep_copy()->add_cast(ti);
995  auto rewritten_expr_take2 = visitor.visit(bigint_expr_no_likelihood.get());
996  auto rewritten_expr_take2_const =
997  std::dynamic_pointer_cast<Analyzer::Constant>(rewritten_expr_take2);
998  if (rewritten_expr_take2_const) {
999  // Managed to fold, switch to the new constant
1000  rewritten_expr = rewritten_expr_take2_const;
1001  }
1002  }
1003  }
1004  const auto expr_with_likelihood = dynamic_cast<const Analyzer::LikelihoodExpr*>(expr);
1005  if (expr_with_likelihood) {
1006  // Add back likelihood
1007  return std::make_shared<Analyzer::LikelihoodExpr>(
1008  rewritten_expr, expr_with_likelihood->get_likelihood());
1009  }
1010  return rewritten_expr;
1011 }
1012 
1014  const Analyzer::ColumnVar* val_side,
1015  const int max_rte_covered) {
1016  if (key_side->get_table_id() == val_side->get_table_id() &&
1017  key_side->get_rte_idx() == val_side->get_rte_idx() &&
1018  key_side->get_rte_idx() > max_rte_covered) {
1019  return true;
1020  }
1021  return false;
1022 }
1023 
1025  std::unordered_map<int, llvm::Value*>& scan_idx_to_hash_pos) {
1026  int ret = INT32_MIN;
1027  for (auto& kv : scan_idx_to_hash_pos) {
1028  if (kv.first > ret) {
1029  ret = kv.first;
1030  }
1031  }
1032  return ret;
1033 }
int8_t tinyintval
Definition: sqltypes.h:212
int get_table_id() const
Definition: Analyzer.h:194
Defines data structures for the semantic analysis phase of query processing.
Analyzer::ExpressionPtr rewrite_array_elements(Analyzer::Expr const *expr)
std::string to_lower(const std::string &str)
#define CHECK_EQ(x, y)
Definition: Logger.h:217
#define IS_LOGIC(X)
Definition: sqldefs.h:60
std::shared_ptr< Analyzer::InValues > visitLikeExpr(const Analyzer::LikeExpr *) const override
std::shared_ptr< Analyzer::InValues > visitDateaddExpr(const Analyzer::DateaddExpr *) const override
const std::shared_ptr< Analyzer::Expr > get_own_arg() const
Definition: Analyzer.h:831
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:38
std::shared_ptr< Analyzer::WindowFunction > rewrite_avg_window(const Analyzer::Expr *expr)
bool g_strip_join_covered_quals
Definition: Execute.cpp:103
std::shared_ptr< Analyzer::InValues > visitKeyForString(const Analyzer::KeyForStringExpr *) const override
std::shared_ptr< Analyzer::WindowFunction > rewrite_sum_window(const Analyzer::Expr *expr)
std::shared_ptr< Analyzer::InValues > visitBinOper(const Analyzer::BinOper *bin_oper) const override
#define LOG(tag)
Definition: Logger.h:203
const Expr * get_right_operand() const
Definition: Analyzer.h:443
bool is_constructed_point(const Analyzer::Expr *expr)
Definition: Execute.h:1222
SQLOps
Definition: sqldefs.h:29
static const std::unordered_set< std::string > requires_many_to_many
Definition: sqldefs.h:35
int8_t boolval
Definition: sqltypes.h:211
Definition: sqldefs.h:36
Definition: sqldefs.h:38
#define CHECK_GE(x, y)
Definition: Logger.h:222
bool get_contains_agg() const
Definition: Analyzer.h:80
Definition: sqldefs.h:49
Definition: sqldefs.h:30
std::shared_ptr< Analyzer::Expr > ExpressionPtr
Definition: Analyzer.h:180
const Analyzer::Expr * extract_cast_arg(const Analyzer::Expr *expr)
Definition: Execute.h:199
Definition: sqldefs.h:41
std::vector< JoinCondition > JoinQualsPerNestingLevel
T visit(const Analyzer::Expr *expr) const
Analyzer::ExpressionPtr rewrite_expr(const Analyzer::Expr *expr)
static const std::unordered_set< std::string > overlaps_supported_functions
bool isNull() const
Definition: Analyzer.h:1638
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)
std::shared_ptr< Analyzer::Expr > visitBinOper(const Analyzer::BinOper *bin_oper) const override
std::shared_ptr< Analyzer::Expr > RetType
int32_t intval
Definition: sqltypes.h:214
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:439
float floatval
Definition: sqltypes.h:216
std::shared_ptr< Analyzer::Expr > visitUOper(const Analyzer::UOper *uoper) const override
#define INT32_MIN
Classes representing a parse tree.
bool g_enable_hashjoin_many_to_many
Definition: Execute.cpp:100
std::shared_ptr< Analyzer::InValues > visitRegexpExpr(const Analyzer::RegexpExpr *) const override
int64_t bigintval
Definition: sqltypes.h:215
bool g_enable_distance_rangejoin
Definition: Execute.cpp:99
std::shared_ptr< Analyzer::InValues > visitAggExpr(const Analyzer::AggExpr *) const override
bool visitFunctionOper(const Analyzer::FunctionOper *func_oper) const override
Definition: sqldefs.h:37
bool foldOper(SQLOps optype, SQLTypes type, Datum lhs, Datum rhs, Datum &result, SQLTypes &result_type) const
int16_t smallintval
Definition: sqltypes.h:213
bool defaultResult() const override
static std::shared_ptr< Analyzer::Expr > analyzeValue(const std::string &)
Definition: ParserNode.cpp:120
boost::optional< OverlapsJoinConjunction > rewrite_overlaps_conjunction(const std::shared_ptr< Analyzer::Expr > expr)
RetType visitArrayOper(const Analyzer::ArrayExpr *array_expr) const override
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:78
std::shared_ptr< Analyzer::Expr > visitBinOper(const Analyzer::BinOper *bin_oper) const override
size_t getElementCount() const
Definition: Analyzer.h:1636
SQLTypes decimal_to_int_type(const SQLTypeInfo &ti)
Definition: Datum.cpp:451
Definition: sqldefs.h:34
Definition: sqldefs.h:40
std::vector< std::pair< const Analyzer::Expr *, const Analyzer::Expr * > > join_qual_pairs
Definition: sqldefs.h:69
#define TRANSIENT_DICT_ID
Definition: sqltypes.h:259
bool isLocalAlloc() const
Definition: Analyzer.h:1637
const Analyzer::Expr * getArg(const size_t i) const
Definition: Analyzer.h:1505
#define IS_ARITHMETIC(X)
Definition: sqldefs.h:61
int get_rte_idx() const
Definition: Analyzer.h:196
const Expr * get_operand() const
Definition: Analyzer.h:371
Datum get_constval() const
Definition: Analyzer.h:335
Definition: sqldefs.h:32
Expression class for the LOWER (lowercase) string function. The &quot;arg&quot; constructor parameter must be a...
Definition: Analyzer.h:825
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::Expr > visitLower(const Analyzer::LowerExpr *lower_expr) const override
std::shared_ptr< Analyzer::InValues > visitInValues(const Analyzer::InValues *) const override
#define CHECK(condition)
Definition: Logger.h:209
Definition: sqldefs.h:33
char * f
const Expr * get_left_operand() const
Definition: Analyzer.h:442
Common Enum definitions for SQL processing.
std::shared_ptr< Analyzer::InValues > visitCaseExpr(const Analyzer::CaseExpr *) const override
Definition: sqltypes.h:45
JoinCoveredQualVisitor(const JoinQualsPerNestingLevel &join_quals)
const std::shared_ptr< Analyzer::Expr > get_own_right_operand() const
Definition: Analyzer.h:447
std::string getName() const
Definition: Analyzer.h:1501
bool is_decimal() const
Definition: sqltypes.h:507
std::shared_ptr< Analyzer::InValues > visitDatetruncExpr(const Analyzer::DatetruncExpr *) const override
Definition: sqldefs.h:39
const std::shared_ptr< Analyzer::Expr > get_own_left_operand() const
Definition: Analyzer.h:444
SQLOps get_optype() const
Definition: Analyzer.h:370
#define VLOG(n)
Definition: Logger.h:303
const Expr * get_arg() const
Definition: Analyzer.h:829
std::shared_ptr< Analyzer::Expr > fold_expr(const Analyzer::Expr *expr)
#define IS_COMPARISON(X)
Definition: sqldefs.h:57
double doubleval
Definition: sqltypes.h:217
std::shared_ptr< Analyzer::InValues > visitExtractExpr(const Analyzer::ExtractExpr *) const override
const Analyzer::Expr * getElement(const size_t i) const
Definition: Analyzer.h:1640
SQLQualifier get_qualifier() const
Definition: Analyzer.h:441
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