OmniSciDB  085a039ca4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TransientStringLiteralsVisitor.h
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 
17 #pragma once
18 
19 #include "Logger/Logger.h"
21 #include "StringOps/StringOps.h"
22 
24  public:
26  : sdp_(sdp), executor_(executor) {
27  CHECK(sdp);
28  }
29 
30  void* visitConstant(const Analyzer::Constant* constant) const override {
31  if (constant->get_type_info().is_string() && !constant->get_is_null()) {
32  CHECK(constant->get_constval().stringval);
34  }
35  return defaultResult();
36  }
37 
38  // visitUOper is for handling casts between dictionary encoded text
39  // columns that do not share string dictionaries. For these
40  // we need to run the translation again on the aggregator
41  // so that we know how to interpret the transient literals added
42  // by the leaves via string-to-string casts
43 
44  // Todo(todd): It is inefficient to do the same translation on
45  // the aggregator and each of the leaves, explore storing these
46  // translations/literals on the remote dictionary server instead
47  // so the translation happens once and only once
48 
49  void* visitUOper(const Analyzer::UOper* uoper) const override {
50  const auto& uoper_ti = uoper->get_type_info();
51  const auto& operand_ti = uoper->get_operand()->get_type_info();
52  if (!(uoper->get_optype() == kCAST && uoper_ti.is_dict_encoded_string())) {
53  return defaultResult();
54  }
55  const bool outputs_target_sdp = uoper_ti.get_comp_param() == sdp_->getDictId();
56 
57  if (!parent_feeds_sdp_ && !outputs_target_sdp) {
58  // If we are not casting to our dictionary (sdp_)
59  return defaultResult();
60  }
61  if (uoper_ti.is_dict_intersection()) {
62  // Intersection translations don't add transients to the dest proxy,
63  // and hence can be ignored for the purposes of populating transients
64  return defaultResult();
65  }
66  const bool parent_feeds_sdp_already_set = parent_feeds_sdp_;
67  parent_feeds_sdp_ = true;
68 
69  visit(uoper->get_operand());
70 
71  if (!parent_feeds_sdp_already_set) {
72  parent_feeds_sdp_ = false;
73  }
74 
75  if (operand_ti.is_dict_encoded_string() &&
76  uoper_ti.get_comp_param() != operand_ti.get_comp_param()) {
78  operand_ti.get_comp_param(),
79  uoper_ti.get_comp_param(),
81  {},
83  true); // with_generation
84  }
85  return defaultResult();
86  }
87 
88  void* visitStringOper(const Analyzer::StringOper* string_oper) const override {
89  CHECK_GE(string_oper->getArity(), 1UL);
90  const auto str_operand = string_oper->getArg(0);
91  const auto& string_oper_ti = string_oper->get_type_info();
92  const auto& str_operand_ti = str_operand->get_type_info();
93  const auto string_oper_kind = string_oper->get_kind();
94  if (!string_oper_ti.is_string() || !str_operand_ti.is_string()) {
95  return defaultResult();
96  }
97  const bool parent_feeds_sdp_already_set = parent_feeds_sdp_;
98  const bool outputs_target_sdp = string_oper_ti.get_comp_param() == sdp_->getDictId();
99  if (string_oper_ti.is_dict_encoded_string() &&
100  str_operand_ti.is_dict_encoded_string() &&
101  (parent_feeds_sdp_ || outputs_target_sdp)) {
102  parent_feeds_sdp_ = true;
103  visit(str_operand);
104  if (!parent_feeds_sdp_already_set) {
105  parent_feeds_sdp_ = false;
106  }
107  // Todo(todd): Dedup the code to get string_op_infos from the same
108  // in StringOpsIR.cpp (needs thought as Analyzer and StringOps
109  // deliberately are oblivious to each other)
110 
111  std::vector<StringOps_Namespace::StringOpInfo> string_op_infos;
112  const auto chained_string_op_exprs = string_oper->getChainedStringOpExprs();
113  for (const auto& chained_string_op_expr : chained_string_op_exprs) {
114  auto chained_string_op =
115  dynamic_cast<const Analyzer::StringOper*>(chained_string_op_expr.get());
116  CHECK(chained_string_op);
117  StringOps_Namespace::StringOpInfo string_op_info(
118  chained_string_op->get_kind(), chained_string_op->getLiteralArgs());
119  string_op_infos.emplace_back(string_op_info);
120  }
121 
123  str_operand_ti.get_comp_param(),
124  string_oper_ti.get_comp_param(),
126  string_op_infos,
128  true); // with_generation
129  } else if ((parent_feeds_sdp_ || outputs_target_sdp) &&
130  (string_oper->getLiteralsArity() == string_oper->getArity())) {
131  // This is likely dead code due to ExpressionRewrite of all-literal string ops
132  // (meaning when this visitor gets to a string op with all literal args it
133  // (would have already been rewritten as a literal string)
134  // Todo(todd): Verify and remove if so
135  const StringOps_Namespace::StringOpInfo string_op_info(
136  string_oper_kind, string_oper->getLiteralArgs());
137  CHECK_EQ(string_op_info.numLiterals(), string_oper->getArity());
138  const auto str_result_and_null_status =
140  if (!str_result_and_null_status.second &&
141  !str_result_and_null_status.first
142  .empty()) { // Todo(todd): Is there a central/non-magic function/constant
143  // to determine if a none-encoded string is null
144  sdp_->getOrAddTransient(str_result_and_null_status.first);
145  }
146  }
147  return defaultResult();
148  }
149 
150  protected:
151  void* defaultResult() const override { return nullptr; }
152 
153  private:
155  mutable Executor* executor_;
156  mutable bool parent_feeds_sdp_{false};
157 };
158 
160  public:
161  int visitUOper(const Analyzer::UOper* uoper) const override {
162  const auto& expr_ti = uoper->get_type_info();
163  if (uoper->get_optype() == kCAST && expr_ti.is_string() &&
164  expr_ti.get_compression() == kENCODING_DICT) {
165  return expr_ti.get_comp_param();
166  }
167  return defaultResult();
168  }
169 
170  int visitCaseExpr(const Analyzer::CaseExpr* case_expr) const override {
171  const auto& expr_ti = case_expr->get_type_info();
172  if (expr_ti.is_string() && expr_ti.get_compression() == kENCODING_DICT) {
173  return expr_ti.get_comp_param();
174  }
175  return defaultResult();
176  }
177 
178  int visitStringOper(const Analyzer::StringOper* string_oper) const override {
179  const auto& expr_ti = string_oper->get_type_info();
180  if (expr_ti.is_string() && expr_ti.get_compression() == kENCODING_DICT) {
181  return expr_ti.get_comp_param();
182  }
183  return defaultResult();
184  }
185 
186  protected:
187  int defaultResult() const override { return -1; }
188 };
#define CHECK_EQ(x, y)
Definition: Logger.h:231
const std::shared_ptr< RowSetMemoryOwner > getRowSetMemoryOwner() const
Definition: Execute.cpp:666
void * visitStringOper(const Analyzer::StringOper *string_oper) const override
void * visitUOper(const Analyzer::UOper *uoper) const override
int visitCaseExpr(const Analyzer::CaseExpr *case_expr) const override
bool get_is_null() const
Definition: Analyzer.h:341
#define CHECK_GE(x, y)
Definition: Logger.h:236
int visitUOper(const Analyzer::UOper *uoper) const override
Definition: sqldefs.h:49
void * visitConstant(const Analyzer::Constant *constant) const override
size_t getArity() const
Definition: Analyzer.h:1506
void * visit(const Analyzer::Expr *expr) const
size_t getLiteralsArity() const
Definition: Analyzer.h:1508
const StringDictionaryProxy::IdMap * getStringProxyTranslationMap(const int source_dict_id, const int dest_dict_id, const RowSetMemoryOwner::StringTranslationType translation_type, const std::vector< StringOps_Namespace::StringOpInfo > &string_op_infos, std::shared_ptr< RowSetMemoryOwner > row_set_mem_owner, const bool with_generation) const
Definition: Execute.cpp:573
LiteralArgMap getLiteralArgs() const
Definition: Analyzer.cpp:3902
TransientStringLiteralsVisitor(StringDictionaryProxy *sdp, Executor *executor)
std::pair< std::string, bool > apply_string_op_to_literals(const StringOpInfo &string_op_info)
Definition: StringOps.cpp:617
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:81
std::string * stringval
Definition: sqltypes.h:220
Expression class for string functions The &quot;arg&quot; constructor parameter must be an expression that reso...
Definition: Analyzer.h:1463
SqlStringOpKind get_kind() const
Definition: Analyzer.h:1504
const Expr * get_operand() const
Definition: Analyzer.h:378
Datum get_constval() const
Definition: Analyzer.h:342
int visitStringOper(const Analyzer::StringOper *string_oper) const override
HOST DEVICE int get_comp_param() const
Definition: sqltypes.h:338
int32_t getDictId() const noexcept
#define CHECK(condition)
Definition: Logger.h:223
int32_t getOrAddTransient(const std::string &str)
bool is_string() const
Definition: sqltypes.h:510
std::vector< std::shared_ptr< Analyzer::Expr > > getChainedStringOpExprs() const
Definition: Analyzer.h:1530
const Expr * getArg(const size_t i) const
Definition: Analyzer.h:1518
SQLOps get_optype() const
Definition: Analyzer.h:377