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);
287 const std::shared_ptr<Analyzer::Expr> lhs,
288 const std::shared_ptr<Analyzer::Expr> rhs,
291 const auto lhs_ti = lhs->get_type_info();
296 VLOG(1) <<
"Failed to build overlaps hash table, short circuiting overlaps operator.";
301 CHECK(lhs_ti.is_geometry());
303 if (lhs_ti.is_geometry()) {
310 auto lhs_column_key = lhs_col->getColumnKey();
311 lhs_column_key.column_id = lhs_column_key.column_id + 1;
315 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
316 geoargs.push_back(makeExpr<Analyzer::ColumnVar>(
317 coords_cd->columnType,
319 lhs_col->get_rte_idx()));
321 Datum input_compression;
322 input_compression.
intval =
323 (lhs_ti.get_compression() ==
kENCODING_GEOINT && lhs_ti.get_comp_param() == 32)
326 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
328 input_srid.
intval = lhs_ti.get_input_srid();
329 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
331 output_srid.
intval = lhs_ti.get_output_srid();
332 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
334 const auto x_ptr_oper = makeExpr<Analyzer::FunctionOper>(
336 const auto y_ptr_oper = makeExpr<Analyzer::FunctionOper>(
339 const auto rhs_ti = rhs->get_type_info();
344 auto rhs_column_key = rhs_col->getColumnKey();
345 rhs_column_key.column_id =
346 rhs_column_key.column_id + rhs_ti.get_physical_coord_cols() + 1;
347 const auto poly_bounds_cd =
349 CHECK(poly_bounds_cd);
351 auto bbox_col_var = makeExpr<Analyzer::ColumnVar>(
352 poly_bounds_cd->columnType,
354 rhs_col->get_rte_idx());
356 const auto bbox_contains_func_oper =
358 "Point_Overlaps_Box",
359 std::vector<std::shared_ptr<Analyzer::Expr>>{
360 bbox_col_var, x_ptr_oper, y_ptr_oper});
365 CHECK(
false) <<
"Unsupported type for overlaps operator: " << lhs_ti.get_type_name();
371 const std::shared_ptr<Analyzer::Expr> lhs,
372 const std::shared_ptr<Analyzer::Expr> rhs,
375 const auto lhs_ti = lhs->get_type_info();
376 const auto rhs_ti = rhs->get_type_info();
378 CHECK(lhs_ti.is_string());
379 CHECK(rhs_ti.is_string());
384 if (lhs_ti.getStringDictKey() == rhs_ti.getStringDictKey()) {
409 if (!u_oper || u_oper->get_optype() !=
kCAST) {
416 const auto operand = u_oper->get_operand();
418 if (operand_ti.is_decimal() && operand_ti.get_scale() < lhs_ti.
get_scale()) {
420 }
else if (operand_ti.is_integer() && 0 < lhs_ti.
get_scale()) {
426 auto scale_diff = lhs_ti.
get_scale() - operand_ti.get_scale() - 1;
427 int64_t bigintval = rhs_constant->get_constval().bigintval;
428 bool negative =
false;
431 bigintval = -bigintval;
433 int64_t truncated_decimal = bigintval /
exp_to_scale(scale_diff);
434 int64_t decimal_tail = bigintval %
exp_to_scale(scale_diff);
435 if (truncated_decimal % 10 == 0 && decimal_tail > 0) {
436 truncated_decimal += 1;
441 operand_ti.get_notnull());
443 truncated_decimal = -truncated_decimal;
447 const auto new_rhs_lit =
448 makeExpr<Analyzer::Constant>(new_ti, rhs_constant->get_is_null(), d);
449 const auto operand_lv =
codegen(operand,
true, co).front();
450 const auto lhs_lv =
codegenCast(operand_lv, operand_ti, new_ti,
false, co);
451 return codegenCmp(optype, qualifier, {lhs_lv}, new_ti, new_rhs_lit.get(), co);
456 std::vector<llvm::Value*> lhs_lvs,
463 if (rhs_ti.is_array()) {
466 auto rhs_lvs =
codegen(rhs,
true, co);
470 CHECK(rhs_ti.is_array() ||
471 rhs_ti.is_geometry());
474 (lhs_ti.
is_string() && rhs_ti.is_string()));
480 CHECK(rhs_ti.is_string());
484 if (lhs_lvs.size() != 3) {
485 CHECK_EQ(
size_t(1), lhs_lvs.size());
491 if (rhs_lvs.size() != 3) {
492 CHECK_EQ(
size_t(1), rhs_lvs.size());
498 std::vector<llvm::Value*> str_cmp_args{
499 lhs_lvs[1], lhs_lvs[2], rhs_lvs[1], rhs_lvs[2]};
500 if (!null_check_suffix.empty()) {
501 str_cmp_args.push_back(
505 string_cmp_func(optype) + (null_check_suffix.empty() ?
"" :
"_nullable"),
512 if (lhs_ti.
is_boolean() && rhs_ti.is_boolean()) {
513 auto& lhs_lv = lhs_lvs.front();
514 auto& rhs_lv = rhs_lvs.front();
515 CHECK(lhs_lv->getType()->isIntegerTy());
516 CHECK(rhs_lv->getType()->isIntegerTy());
517 if (lhs_lv->getType()->getIntegerBitWidth() <
518 rhs_lv->getType()->getIntegerBitWidth()) {
527 return null_check_suffix.empty()
539 return null_check_suffix.empty()
557 std::vector<llvm::Value*> lhs_lvs,
563 if (dynamic_cast<const Analyzer::UOper*>(rhs)) {
566 arr_expr = cast_arr->get_operand();
568 const auto& arr_ti = arr_expr->get_type_info();
569 const auto& elem_ti = arr_ti.get_elem_type();
570 auto rhs_lvs =
codegen(arr_expr,
true, co);
572 std::string fname{std::string(
"array_") + (qualifier ==
kANY ?
"any" :
"all") +
"_" +
574 const auto& target_ti = rhs_ti.get_elem_type();
575 const bool is_real_string{target_ti.is_string() &&
577 if (is_real_string) {
579 throw std::runtime_error(
580 "Comparison between a dictionary-encoded and a none-encoded string not "
581 "supported for distributed queries");
585 "Comparison between a dictionary-encoded and a none-encoded string would be "
594 if (elem_ti.is_integer() || elem_ti.is_boolean() || elem_ti.is_string() ||
595 elem_ti.is_decimal()) {
598 CHECK(elem_ti.is_fp());
599 fname += elem_ti.get_type() ==
kDOUBLE ?
"_double" :
"_float";
601 if (is_real_string) {
602 CHECK_EQ(
size_t(3), lhs_lvs.size());
611 elem_ti.getStringDictKey(),
executor()->getRowSetMemoryOwner(),
true))),
614 if (target_ti.is_integer() || target_ti.is_boolean() || target_ti.is_string() ||
615 target_ti.is_decimal()) {
618 CHECK(target_ti.is_fp());
619 fname += target_ti.get_type() ==
kDOUBLE ?
"_double" :
"_float";
621 return cgen_state_->emitExternalCall(
627 elem_ti.is_fp() ?
static_cast<llvm::Value*
>(cgen_state_->inlineFpNull(elem_ti))
628 : 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)
bool g_enable_overlaps_hashjoin
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::Value * codegenOverlaps(const SQLOps, const SQLQualifier, const std::shared_ptr< Analyzer::Expr >, const std::shared_ptr< Analyzer::Expr >, 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 &)
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