22 #include "../Parser/ParserNode.h"
29 return llvm::ICmpInst::ICMP_EQ;
31 return llvm::ICmpInst::ICMP_NE;
33 return llvm::ICmpInst::ICMP_SLT;
35 return llvm::ICmpInst::ICMP_SGT;
37 return llvm::ICmpInst::ICMP_SLE;
39 return llvm::ICmpInst::ICMP_SGE;
86 return llvm::CmpInst::FCMP_OEQ;
88 return llvm::CmpInst::FCMP_ONE;
90 return llvm::CmpInst::FCMP_OLT;
92 return llvm::CmpInst::FCMP_OGT;
94 return llvm::CmpInst::FCMP_OLE;
96 return llvm::CmpInst::FCMP_OGE;
133 const auto lhs_is_null =
135 const auto rhs_is_null = std::make_shared<Analyzer::UOper>(
137 const auto both_are_null =
145 std::shared_ptr<Analyzer::BinOper>
make_eq(
const std::shared_ptr<Analyzer::Expr>& lhs,
146 const std::shared_ptr<Analyzer::Expr>& rhs,
165 CHECK(left_tuple_expr && right_tuple_expr);
166 const auto& left_tuple = left_tuple_expr->getTuple();
167 const auto& right_tuple = right_tuple_expr->getTuple();
168 CHECK_EQ(left_tuple.size(), right_tuple.size());
169 CHECK_GT(left_tuple.size(), size_t(1));
171 make_eq(left_tuple.front(), right_tuple.front(), multicol_compare->
get_optype());
172 for (
size_t i = 1; i < left_tuple.size(); ++i) {
173 auto crt =
make_eq(left_tuple[i], right_tuple[i], multicol_compare->
get_optype());
174 const bool not_null =
175 acc->get_type_info().get_notnull() && crt->get_type_info().get_notnull();
176 acc = makeExpr<Analyzer::BinOper>(
186 if (lhs_cv && rhs_cv && comp_op) {
187 auto lhs_ti = lhs_cv->get_type_info();
188 auto rhs_ti = rhs_cv->get_type_info();
189 if (lhs_ti.is_array() && rhs_ti.is_array()) {
190 throw std::runtime_error(
191 "Comparing two full array columns is not supported yet. Please consider "
192 "rewriting the full array comparison to a comparison between indexed array "
194 "(i.e., arr1[1] {<, <=, >, >=} arr2[1]).");
206 if (lhs_bin_oper && rhs_bin_oper && theta_comp &&
217 if (lhs_arr_cv && rhs_arr_cv && lhs_arr_idx && rhs_arr_idx &&
218 ((lhs_arr_cv->get_type_info().is_array() &&
220 (rhs_arr_cv->get_type_info().is_string() &&
222 throw std::runtime_error(
223 "Comparison between string array columns is not supported yet.");
236 if (dynamic_cast<const Analyzer::ExpressionTuple*>(lhs)) {
237 CHECK(dynamic_cast<const Analyzer::ExpressionTuple*>(rhs));
239 const auto lowered_lvs =
codegen(lowered.get(),
true, co);
240 CHECK_EQ(
size_t(1), lowered_lvs.size());
241 return lowered_lvs.front();
256 throw std::runtime_error(
"Unnest not supported in comparisons");
259 const auto& lhs_ti = lhs->get_type_info();
260 const auto& rhs_ti = rhs->get_type_info();
262 if (lhs_ti.is_string() && rhs_ti.is_string() &&
274 if (lhs_ti.is_decimal()) {
275 auto cmp_decimal_const =
277 if (cmp_decimal_const) {
278 return cmp_decimal_const;
281 auto lhs_lvs =
codegen(lhs,
true, co);
282 return codegenCmp(optype, qualifier, lhs_lvs, lhs_ti, rhs, co);
288 const std::shared_ptr<Analyzer::Expr> lhs,
289 const std::shared_ptr<Analyzer::Expr> rhs,
292 const auto lhs_ti = lhs->get_type_info();
297 VLOG(1) <<
"Failed to build bounding box intersect hash table, short circuiting "
298 "bounding box intersect operator.";
303 CHECK(lhs_ti.is_geometry());
305 if (lhs_ti.is_geometry()) {
312 auto lhs_column_key = lhs_col->getColumnKey();
313 lhs_column_key.column_id = lhs_column_key.column_id + 1;
317 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
318 geoargs.push_back(makeExpr<Analyzer::ColumnVar>(
319 coords_cd->columnType,
321 lhs_col->get_rte_idx()));
323 Datum input_compression;
324 input_compression.
intval =
325 (lhs_ti.get_compression() ==
kENCODING_GEOINT && lhs_ti.get_comp_param() == 32)
328 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
330 input_srid.
intval = lhs_ti.get_input_srid();
331 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
333 output_srid.
intval = lhs_ti.get_output_srid();
334 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
336 const auto x_ptr_oper = makeExpr<Analyzer::FunctionOper>(
338 const auto y_ptr_oper = makeExpr<Analyzer::FunctionOper>(
341 const auto rhs_ti = rhs->get_type_info();
346 auto rhs_column_key = rhs_col->getColumnKey();
347 rhs_column_key.column_id =
348 rhs_column_key.column_id + rhs_ti.get_physical_coord_cols() + 1;
349 const auto poly_bounds_cd =
351 CHECK(poly_bounds_cd);
353 auto bbox_col_var = makeExpr<Analyzer::ColumnVar>(
354 poly_bounds_cd->columnType,
356 rhs_col->get_rte_idx());
358 const auto bbox_contains_func_oper =
360 "Point_Overlaps_Box",
361 std::vector<std::shared_ptr<Analyzer::Expr>>{
362 bbox_col_var, x_ptr_oper, y_ptr_oper});
367 CHECK(
false) <<
"Unsupported type for bounding box intersect operator: "
368 << lhs_ti.get_type_name();
374 const std::shared_ptr<Analyzer::Expr> lhs,
375 const std::shared_ptr<Analyzer::Expr> rhs,
378 const auto lhs_ti = lhs->get_type_info();
379 const auto rhs_ti = rhs->get_type_info();
381 CHECK(lhs_ti.is_string());
382 CHECK(rhs_ti.is_string());
387 if (lhs_ti.getStringDictKey() == rhs_ti.getStringDictKey()) {
410 if (!u_oper || u_oper->get_optype() !=
kCAST) {
417 const auto operand = u_oper->get_operand();
419 if (operand_ti.is_decimal() && operand_ti.get_scale() < lhs_ti.
get_scale()) {
421 }
else if (operand_ti.is_integer() && 0 < lhs_ti.
get_scale()) {
427 auto scale_diff = lhs_ti.
get_scale() - operand_ti.get_scale() - 1;
428 int64_t bigintval = rhs_constant->get_constval().bigintval;
429 bool negative =
false;
432 bigintval = -bigintval;
434 int64_t truncated_decimal = bigintval /
exp_to_scale(scale_diff);
435 int64_t decimal_tail = bigintval %
exp_to_scale(scale_diff);
436 if (truncated_decimal % 10 == 0 && decimal_tail > 0) {
437 truncated_decimal += 1;
442 operand_ti.get_notnull());
444 truncated_decimal = -truncated_decimal;
448 const auto new_rhs_lit =
449 makeExpr<Analyzer::Constant>(new_ti, rhs_constant->get_is_null(), d);
450 const auto operand_lv =
codegen(operand,
true, co).front();
451 const auto lhs_lv =
codegenCast(operand_lv, operand_ti, new_ti,
false, co);
452 return codegenCmp(optype, qualifier, {lhs_lv}, new_ti, new_rhs_lit.get(), co);
457 if (lvs.size() != 3) {
459 lvs.push_back(cgen_state->
ir_builder_.CreateExtractValue(lvs[0], 0));
460 lvs.push_back(cgen_state->
ir_builder_.CreateExtractValue(lvs[0], 1));
462 lvs.back(), llvm::Type::getInt32Ty(cgen_state->
context_));
469 llvm::StructType* string_view_struct_type,
470 std::vector<llvm::Value*>& lvs) {
471 const auto sdp_ptr =
reinterpret_cast<int64_t
>(executor->getStringDictionaryProxy(
474 "string_decompress", string_view_struct_type, {lvs[0], cgen_state->
llInt(sdp_ptr)});
475 lvs.push_back(cgen_state->
ir_builder_.CreateExtractValue(sv, 0));
476 lvs.push_back(cgen_state->
ir_builder_.CreateExtractValue(sv, 1));
478 lvs.back(), llvm::Type::getInt32Ty(cgen_state->
context_));
484 std::vector<llvm::Value*> lhs_lvs,
491 if (rhs_ti.is_array()) {
494 auto rhs_lvs =
codegen(rhs,
true, co);
498 CHECK(rhs_ti.is_array() ||
499 rhs_ti.is_geometry());
502 (lhs_ti.
is_string() && rhs_ti.is_string()));
508 CHECK(rhs_ti.is_string());
513 bool unpack_strings =
true;
523 unpack_strings =
false;
532 if (unpack_strings) {
534 std::vector<llvm::Value*> str_cmp_args{
535 lhs_lvs[1], lhs_lvs[2], rhs_lvs[1], rhs_lvs[2]};
536 if (!null_check_suffix.empty()) {
537 str_cmp_args.push_back(
541 string_cmp_func(optype) + (null_check_suffix.empty() ?
"" :
"_nullable"),
546 if (lhs_ti.
is_boolean() && rhs_ti.is_boolean()) {
547 auto& lhs_lv = lhs_lvs.front();
548 auto& rhs_lv = rhs_lvs.front();
549 CHECK(lhs_lv->getType()->isIntegerTy());
550 CHECK(rhs_lv->getType()->isIntegerTy());
551 if (lhs_lv->getType()->getIntegerBitWidth() <
552 rhs_lv->getType()->getIntegerBitWidth()) {
561 return null_check_suffix.empty()
573 return null_check_suffix.empty()
591 std::vector<llvm::Value*> lhs_lvs,
597 if (dynamic_cast<const Analyzer::UOper*>(rhs)) {
600 arr_expr = cast_arr->get_operand();
602 const auto& arr_ti = arr_expr->get_type_info();
603 const auto& elem_ti = arr_ti.get_elem_type();
604 auto rhs_lvs =
codegen(arr_expr,
true, co);
606 std::string fname{std::string(
"array_") + (qualifier ==
kANY ?
"any" :
"all") +
"_" +
608 const auto& target_ti = rhs_ti.get_elem_type();
609 const bool is_real_string{target_ti.is_string() &&
611 if (is_real_string) {
613 throw std::runtime_error(
614 "Comparison between a dictionary-encoded and a none-encoded string not "
615 "supported for distributed queries");
619 "Comparison between a dictionary-encoded and a none-encoded string would be "
628 if (elem_ti.is_integer() || elem_ti.is_boolean() || elem_ti.is_string() ||
629 elem_ti.is_decimal()) {
632 CHECK(elem_ti.is_fp());
633 fname += elem_ti.get_type() ==
kDOUBLE ?
"_double" :
"_float";
635 if (is_real_string) {
636 CHECK_EQ(
size_t(3), lhs_lvs.size());
645 elem_ti.getStringDictKey(),
executor()->getRowSetMemoryOwner(),
true))),
648 if (target_ti.is_integer() || target_ti.is_boolean() || target_ti.is_string() ||
649 target_ti.is_decimal()) {
652 CHECK(target_ti.is_fp());
653 fname += target_ti.get_type() ==
kDOUBLE ?
"_double" :
"_float";
655 return cgen_state_->emitExternalCall(
661 elem_ti.is_fp() ?
static_cast<llvm::Value*
>(cgen_state_->inlineFpNull(elem_ti))
662 : static_cast<llvm::Value*>(cgen_state_->inlineIntNull(elem_ti))});
void check_array_comp_cond(const Analyzer::BinOper *bin_oper)
static constexpr int32_t kMaxRepresentableNumericPrecision
llvm::Value * castToTypeIn(llvm::Value *val, const size_t bit_width)
llvm::Value * codegenStrCmp(const SQLOps, const SQLQualifier, const std::shared_ptr< Analyzer::Expr >, const std::shared_ptr< Analyzer::Expr >, const CompilationOptions &)
std::string icmp_name(const SQLOps op_type)
#define IS_EQUIVALENCE(X)
std::shared_ptr< Analyzer::BinOper > lower_multicol_compare(const Analyzer::BinOper *multicol_compare)
HOST DEVICE int get_scale() const
const Expr * get_right_operand() const
llvm::IRBuilder ir_builder_
static std::shared_ptr< Analyzer::Expr > normalize(const SQLOps optype, const SQLQualifier qual, std::shared_ptr< Analyzer::Expr > left_expr, std::shared_ptr< Analyzer::Expr > right_expr, const Executor *executor=nullptr)
llvm::Value * posArg(const Analyzer::Expr *) const
const ColumnDescriptor * get_metadata_for_column(const ::shared::ColumnKey &column_key)
bool get_contains_agg() const
void unpack_dict_encoded_string(CgenState *cgen_state, Executor *executor, SQLTypeInfo const ti, llvm::StructType *string_view_struct_type, std::vector< llvm::Value * > &lvs)
std::shared_ptr< Analyzer::BinOper > lower_bw_eq(const Analyzer::BinOper *bw_eq)
HOST DEVICE SQLTypes get_type() const
llvm::CmpInst::Predicate llvm_fcmp_pred(const SQLOps op_type)
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
std::string icmp_arr_name(const SQLOps op_type)
SQLOps get_optype() const
llvm::LLVMContext & context_
llvm::Value * codegenCmpDecimalConst(const SQLOps, const SQLQualifier, const Analyzer::Expr *, const SQLTypeInfo &, const Analyzer::Expr *, const CompilationOptions &)
llvm::Value * emitExternalCall(const std::string &fname, llvm::Type *ret_type, const std::vector< llvm::Value * > args, const std::vector< llvm::Attribute::AttrKind > &fnattrs={}, const bool has_struct_return=false)
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
bool is_timeinterval() const
llvm::Value * codegenFunctionOper(const Analyzer::FunctionOper *, const CompilationOptions &)
llvm::ConstantFP * llFp(const float v) const
llvm::Value * codegenDictStrCmp(const std::shared_ptr< Analyzer::Expr >, const std::shared_ptr< Analyzer::Expr >, const SQLOps, const CompilationOptions &co)
std::string get_null_check_suffix(const SQLTypeInfo &lhs_ti, const SQLTypeInfo &rhs_ti)
const SQLTypeInfo & get_type_info() const
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
ExecutorDeviceType device_type
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
void unpack_none_encoded_string(CgenState *cgen_state, std::vector< llvm::Value * > &lvs)
HOST DEVICE EncodingType get_compression() const
std::shared_ptr< Analyzer::BinOper > make_eq(const std::shared_ptr< Analyzer::Expr > &lhs, const std::shared_ptr< Analyzer::Expr > &rhs, const SQLOps optype)
llvm::Value * codegenQualifierCmp(const SQLOps, const SQLQualifier, std::vector< llvm::Value * >, const Analyzer::Expr *, const CompilationOptions &)
bool g_enable_bbox_intersect_hashjoin
llvm::StructType * createStringViewStructType()
llvm::Value * codegenBoundingBoxIntersect(const SQLOps, const SQLQualifier, const std::shared_ptr< Analyzer::Expr >, const std::shared_ptr< Analyzer::Expr >, const CompilationOptions &)
llvm::CmpInst::Predicate llvm_icmp_pred(const SQLOps op_type)
llvm::Value * codegenCmp(const Analyzer::BinOper *, const CompilationOptions &)
llvm::ConstantInt * llInt(const T v) const
llvm::Value * codegenLogical(const Analyzer::BinOper *, const CompilationOptions &)
uint64_t exp_to_scale(const unsigned exp)
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
const Expr * get_left_operand() const
llvm::Value * codegenCast(const Analyzer::UOper *, const CompilationOptions &)
std::string numeric_type_name(const SQLTypeInfo &ti)
bool is_unnest(const Analyzer::Expr *expr)
const std::shared_ptr< Analyzer::Expr > get_own_right_operand() const
const std::shared_ptr< Analyzer::Expr > get_own_left_operand() const
std::string string_cmp_func(const SQLOps optype)
SQLQualifier get_qualifier() const
const shared::StringDictKey & getStringDictKey() const
Executor * executor() const