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()) {
412 if (!u_oper || u_oper->get_optype() !=
kCAST) {
419 const auto operand = u_oper->get_operand();
421 if (operand_ti.is_decimal() && operand_ti.get_scale() < lhs_ti.
get_scale()) {
423 }
else if (operand_ti.is_integer() && 0 < lhs_ti.
get_scale()) {
429 auto scale_diff = lhs_ti.
get_scale() - operand_ti.get_scale() - 1;
430 int64_t bigintval = rhs_constant->get_constval().bigintval;
431 bool negative =
false;
434 bigintval = -bigintval;
436 int64_t truncated_decimal = bigintval /
exp_to_scale(scale_diff);
437 int64_t decimal_tail = bigintval %
exp_to_scale(scale_diff);
438 if (truncated_decimal % 10 == 0 && decimal_tail > 0) {
439 truncated_decimal += 1;
444 operand_ti.get_notnull());
446 truncated_decimal = -truncated_decimal;
450 const auto new_rhs_lit =
451 makeExpr<Analyzer::Constant>(new_ti, rhs_constant->get_is_null(), d);
452 const auto operand_lv =
codegen(operand,
true, co).front();
453 const auto lhs_lv =
codegenCast(operand_lv, operand_ti, new_ti,
false, co);
454 return codegenCmp(optype, qualifier, {lhs_lv}, new_ti, new_rhs_lit.get(), co);
459 std::vector<llvm::Value*> lhs_lvs,
466 if (rhs_ti.is_array()) {
469 auto rhs_lvs =
codegen(rhs,
true, co);
473 CHECK(rhs_ti.is_array() ||
474 rhs_ti.is_geometry());
477 (lhs_ti.
is_string() && rhs_ti.is_string()));
483 CHECK(rhs_ti.is_string());
487 if (lhs_lvs.size() != 3) {
488 CHECK_EQ(
size_t(1), lhs_lvs.size());
494 if (rhs_lvs.size() != 3) {
495 CHECK_EQ(
size_t(1), rhs_lvs.size());
501 std::vector<llvm::Value*> str_cmp_args{
502 lhs_lvs[1], lhs_lvs[2], rhs_lvs[1], rhs_lvs[2]};
503 if (!null_check_suffix.empty()) {
504 str_cmp_args.push_back(
508 string_cmp_func(optype) + (null_check_suffix.empty() ?
"" :
"_nullable"),
515 if (lhs_ti.
is_boolean() && rhs_ti.is_boolean()) {
516 auto& lhs_lv = lhs_lvs.front();
517 auto& rhs_lv = rhs_lvs.front();
518 CHECK(lhs_lv->getType()->isIntegerTy());
519 CHECK(rhs_lv->getType()->isIntegerTy());
520 if (lhs_lv->getType()->getIntegerBitWidth() <
521 rhs_lv->getType()->getIntegerBitWidth()) {
530 return null_check_suffix.empty()
542 return null_check_suffix.empty()
560 std::vector<llvm::Value*> lhs_lvs,
566 if (dynamic_cast<const Analyzer::UOper*>(rhs)) {
569 arr_expr = cast_arr->get_operand();
571 const auto& arr_ti = arr_expr->get_type_info();
572 const auto& elem_ti = arr_ti.get_elem_type();
573 auto rhs_lvs =
codegen(arr_expr,
true, co);
575 std::string fname{std::string(
"array_") + (qualifier ==
kANY ?
"any" :
"all") +
"_" +
577 const auto& target_ti = rhs_ti.get_elem_type();
578 const bool is_real_string{target_ti.is_string() &&
580 if (is_real_string) {
582 throw std::runtime_error(
583 "Comparison between a dictionary-encoded and a none-encoded string not "
584 "supported for distributed queries");
588 "Comparison between a dictionary-encoded and a none-encoded string would be "
597 if (elem_ti.is_integer() || elem_ti.is_boolean() || elem_ti.is_string() ||
598 elem_ti.is_decimal()) {
601 CHECK(elem_ti.is_fp());
602 fname += elem_ti.get_type() ==
kDOUBLE ?
"_double" :
"_float";
604 if (is_real_string) {
605 CHECK_EQ(
size_t(3), lhs_lvs.size());
614 elem_ti.getStringDictKey(),
executor()->getRowSetMemoryOwner(),
true))),
617 if (target_ti.is_integer() || target_ti.is_boolean() || target_ti.is_string() ||
618 target_ti.is_decimal()) {
621 CHECK(target_ti.is_fp());
622 fname += target_ti.get_type() ==
kDOUBLE ?
"_double" :
"_float";
624 return cgen_state_->emitExternalCall(
630 elem_ti.is_fp() ?
static_cast<llvm::Value*
>(cgen_state_->inlineFpNull(elem_ti))
631 : 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
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 &)
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::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
Executor * executor() const