30 #define DEF_OPERATOR(fname, op) \
31 ExpressionRange fname(const ExpressionRange& other) const { \
32 if (type_ == ExpressionRangeType::Invalid || \
33 other.type_ == ExpressionRangeType::Invalid) { \
34 return ExpressionRange::makeInvalidRange(); \
36 CHECK(type_ == other.type_); \
38 case ExpressionRangeType::Integer: \
39 return binOp<int64_t>(other, [](const int64_t x, const int64_t y) { \
40 return int64_t(checked_int64_t(x) op y); \
42 case ExpressionRangeType::Float: \
43 return binOp<float>(other, [](const float x, const float y) { \
44 std::feclearexcept(FE_OVERFLOW); \
45 std::feclearexcept(FE_UNDERFLOW); \
46 auto result = x op y; \
47 if (std::fetestexcept(FE_OVERFLOW) || std::fetestexcept(FE_UNDERFLOW)) { \
48 throw std::runtime_error("overflow / underflow"); \
52 case ExpressionRangeType::Double: \
53 return binOp<double>(other, [](const double x, const double y) { \
54 std::feclearexcept(FE_OVERFLOW); \
55 std::feclearexcept(FE_UNDERFLOW); \
56 auto result = x op y; \
57 if (std::fetestexcept(FE_OVERFLOW) || std::fetestexcept(FE_UNDERFLOW)) { \
58 throw std::runtime_error("overflow / underflow"); \
66 return ExpressionRange::makeInvalidRange(); \
77 double const_val = get_value_from_datum<double>(const_datum, const_type);
81 qual_range.setFpMin(std::max(qual_range.getFpMin(), const_val));
85 qual_range.setFpMax(std::min(qual_range.getFpMax(), const_val));
88 qual_range.setFpMin(std::max(qual_range.getFpMin(), const_val));
89 qual_range.setFpMax(std::min(qual_range.getFpMax(), const_val));
100 int64_t const_val = get_value_from_datum<int64_t>(const_datum, const_type);
125 const int32_t const_dimen,
126 const int32_t col_dimen,
129 CHECK(const_dimen != col_dimen);
131 if (const_dimen > col_dimen) {
133 get_value_from_datum<int64_t>(const_datum, const_type) /
137 get_value_from_datum<int64_t>(const_datum, const_type) *
146 const boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
151 for (
auto const& itr : simple_quals.get()) {
153 if (!qual_bin_oper) {
156 const Analyzer::Expr* left_operand = qual_bin_oper->get_left_operand();
171 if (qual_col->get_table_id() != col_expr->
get_table_id() ||
175 const Analyzer::Expr* right_operand = qual_bin_oper->get_right_operand();
183 qual_const->get_type_info().get_type(),
184 qual_bin_oper->get_optype(),
186 }
else if ((qual_col->get_type_info().is_timestamp() ||
187 qual_const->get_type_info().is_timestamp()) &&
188 (qual_col->get_type_info().get_dimension() !=
189 qual_const->get_type_info().get_dimension())) {
191 qual_const->get_type_info().get_type(),
192 qual_const->get_type_info().get_dimension(),
193 qual_col->get_type_info().get_dimension(),
194 qual_bin_oper->get_optype(),
198 qual_const->get_type_info().get_type(),
199 qual_bin_oper->get_optype(),
217 auto div_range = binOp<int64_t>(other, [](
const int64_t x,
const int64_t y) {
221 div_range.setHasNulls();
289 const std::vector<InputTableInfo>& query_infos,
291 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
297 const std::vector<InputTableInfo>& query_infos,
298 const Executor* executor,
299 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
304 const std::vector<InputTableInfo>& query_infos,
309 const std::vector<InputTableInfo>& query_infos,
311 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
315 const std::vector<InputTableInfo>& query_infos,
317 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
321 const std::vector<InputTableInfo>& query_infos,
322 const Executor* executor,
323 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
327 const std::vector<InputTableInfo>& query_infos,
328 const Executor* executor,
329 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
343 if (column_var_expr) {
363 if (datetrunc_expr) {
379 const std::vector<InputTableInfo>& query_infos,
380 const Executor* executor,
381 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
402 return adjusted_lhs / rhs;
418 switch (constant_type) {
420 const int64_t v = datum.tinyintval;
424 const int64_t v = datum.smallintval;
428 const int64_t v = datum.intval;
434 const int64_t v = datum.bigintval;
440 const int64_t v = datum.bigintval;
455 #define FIND_STAT_FRAG(stat_name) \
456 const auto stat_name##_frag_index = std::stat_name##_element( \
457 nonempty_fragment_indices.begin(), \
458 nonempty_fragment_indices.end(), \
459 [&fragments, &has_nulls, col_id, col_ti](const size_t lhs_idx, \
460 const size_t rhs_idx) { \
461 const auto& lhs = fragments[lhs_idx]; \
462 const auto& rhs = fragments[rhs_idx]; \
463 auto lhs_meta_it = lhs.getChunkMetadataMap().find(col_id); \
464 if (lhs_meta_it == lhs.getChunkMetadataMap().end()) { \
467 auto rhs_meta_it = rhs.getChunkMetadataMap().find(col_id); \
468 CHECK(rhs_meta_it != rhs.getChunkMetadataMap().end()); \
469 if (lhs_meta_it->second->chunkStats.has_nulls || \
470 rhs_meta_it->second->chunkStats.has_nulls) { \
473 if (col_ti.is_fp()) { \
474 return extract_##stat_name##_stat_double(lhs_meta_it->second->chunkStats, \
476 extract_##stat_name##_stat_double(rhs_meta_it->second->chunkStats, \
479 return extract_##stat_name##_stat(lhs_meta_it->second->chunkStats, col_ti) < \
480 extract_##stat_name##_stat(rhs_meta_it->second->chunkStats, col_ti); \
482 if (stat_name##_frag_index == nonempty_fragment_indices.end()) { \
483 return ExpressionRange::makeInvalidRange(); \
497 const int64_t day_seconds{24 * 3600};
498 const int64_t year_days{365};
499 switch (datetrunc_field) {
501 return year_days * day_seconds;
503 return 90 * day_seconds;
505 return 28 * day_seconds;
513 return 1000 * year_days * day_seconds;
515 return 100 * year_days * day_seconds;
517 return 10 * year_days * day_seconds;
521 return 7 * day_seconds;
532 const std::vector<InputTableInfo>& query_infos,
533 const Executor* executor,
534 const bool is_outer_join_proj) {
535 bool has_nulls = is_outer_join_proj;
541 switch (col_ti.get_type()) {
558 std::optional<size_t> ti_idx;
559 for (
size_t i = 0;
i < query_infos.size(); ++
i) {
566 const auto& query_info = query_infos[*ti_idx].info;
567 const auto& fragments = query_info.fragments;
568 const auto cd = executor->getColumnDescriptor(col_expr);
569 if (cd && cd->isVirtualCol) {
570 CHECK(cd->columnName ==
"rowid");
572 const int64_t num_tuples = query_info.getNumTuples();
574 0, std::max(num_tuples - 1, int64_t(0)), 0, has_nulls);
576 if (query_info.getNumTuples() == 0) {
578 if (col_ti.is_fp()) {
579 return col_ti.get_type() ==
kFLOAT
585 std::vector<size_t> nonempty_fragment_indices;
586 for (
size_t i = 0;
i < fragments.size(); ++
i) {
587 const auto& fragment = fragments[
i];
588 if (!fragment.isEmptyPhysicalFragment()) {
589 nonempty_fragment_indices.push_back(
i);
594 const auto& min_frag = fragments[*min_frag_index];
595 const auto min_it = min_frag.getChunkMetadataMap().find(col_id);
596 if (min_it == min_frag.getChunkMetadataMap().end()) {
599 const auto& max_frag = fragments[*max_frag_index];
600 const auto max_it = max_frag.getChunkMetadataMap().find(col_id);
601 CHECK(max_it != max_frag.getChunkMetadataMap().end());
602 for (
const auto& fragment : fragments) {
603 const auto it = fragment.getChunkMetadataMap().find(col_id);
604 if (it != fragment.getChunkMetadataMap().end()) {
605 if (it->second->chunkStats.has_nulls) {
611 if (col_ti.is_fp()) {
614 return col_ti.get_type() ==
kFLOAT
620 if (max_val < min_val) {
625 const int64_t bucket =
635 #undef FIND_STAT_FRAG
639 const std::vector<InputTableInfo>& query_infos,
640 const Executor* executor,
641 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
644 CHECK_LT(static_cast<size_t>(rte_idx), query_infos.size());
645 bool is_outer_join_proj = rte_idx > 0 && executor->containsLeftDeepOuterJoin();
647 auto col_range = executor->getColRange(
649 if (is_outer_join_proj) {
650 col_range.setHasNulls();
659 CHECK(ti.is_boolean());
666 const std::vector<InputTableInfo>& query_infos,
667 const Executor* executor) {
670 bool has_nulls =
false;
671 for (
const auto& expr_pair : expr_pair_list) {
673 const auto crt_range =
683 ? expr_range || crt_range
687 expr_range.setHasNulls();
692 if (else_null_expr && else_null_expr->get_is_null()) {
693 expr_range.setHasNulls();
707 static_cast<float>(arg_range.
getIntMin()) / scale,
708 static_cast<float>(arg_range.
getIntMax()) / scale,
712 static_cast<double>(arg_range.
getIntMin()) / scale,
713 static_cast<double>(arg_range.
getIntMax()) / scale,
722 const int64_t scale =
739 CHECK(oper_dimen != ti_dimen);
740 const int64_t min_ts =
741 ti_dimen > oper_dimen
744 abs(oper_dimen - ti_dimen))
748 abs(oper_dimen - ti_dimen));
749 const int64_t max_ts =
750 ti_dimen > oper_dimen
753 abs(oper_dimen - ti_dimen))
757 abs(oper_dimen - ti_dimen));
766 const std::vector<InputTableInfo>& query_infos,
767 const Executor* executor,
768 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
777 const auto sdp = executor->getStringDictionaryProxy(
778 ti.get_comp_param(), executor->getRowSetMemoryOwner(),
true);
780 const auto const_operand =
782 CHECK(const_operand);
784 if (const_operand->get_is_null()) {
787 CHECK(const_operand->get_constval().stringval);
788 const int64_t v = sdp->getIdOfString(*const_operand->get_constval().stringval);
791 const auto arg_range =
795 if ((ti.is_timestamp() && (arg_ti.get_dimension() != ti.get_dimension())) ||
796 ((arg_ti.is_timestamp() && ti.is_date()))) {
799 switch (arg_range.getType()) {
803 return ti.get_type() ==
kDOUBLE
805 arg_range.getFpMin(), arg_range.getFpMax(), arg_range.hasNulls())
807 arg_range.getFpMax(),
808 arg_range.hasNulls());
810 if (ti.is_integer()) {
812 arg_range.getFpMin(), arg_range.getFpMax(), 0, arg_range.hasNulls());
817 if (ti.is_decimal()) {
818 CHECK_EQ(int64_t(0), arg_range.getBucket());
819 const int64_t scale =
exp_to_scale(ti.get_scale() - arg_ti.get_scale());
821 arg_range.getIntMax() * scale,
823 arg_range.hasNulls());
825 if (arg_ti.is_decimal()) {
826 CHECK_EQ(int64_t(0), arg_range.getBucket());
828 const int64_t scale_half = scale / 2;
833 (arg_range.getIntMax() + scale_half) / scale,
835 arg_range.hasNulls());
837 if (ti.is_integer() || ti.is_time()) {
840 if (ti.get_type() ==
kFLOAT) {
842 arg_range.getIntMin(), arg_range.getIntMax(), arg_range.hasNulls());
844 if (ti.get_type() ==
kDOUBLE) {
846 arg_range.getIntMin(), arg_range.getIntMax(), arg_range.hasNulls());
860 const std::vector<InputTableInfo>& query_infos,
861 const Executor* executor,
862 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
863 const int32_t extract_field{extract_expr->
get_field()};
865 extract_expr->
get_from_expr(), query_infos, executor, simple_quals);
866 const bool has_nulls =
869 switch (extract_field) {
875 const int64_t year_range_min =
876 extract_expr_ti.is_high_precision_timestamp()
879 arg_range.getIntMin() /
882 const int64_t year_range_max =
883 extract_expr_ti.is_high_precision_timestamp()
886 arg_range.getIntMax() /
890 year_range_min, year_range_max, 0, arg_range.hasNulls());
932 const std::vector<InputTableInfo>& query_infos,
933 const Executor* executor,
934 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
936 datetrunc_expr->
get_from_expr(), query_infos, executor, simple_quals);
942 arg_range.getIntMin(), datetrunc_expr->
get_field(), datetrunc_expr_ti);
944 arg_range.getIntMax(), datetrunc_expr->
get_field(), datetrunc_expr_ti);
945 const int64_t bucket =
946 datetrunc_expr_ti.is_high_precision_timestamp()
949 datetrunc_expr_ti.get_dimension())
int64_t getIntMin() const
#define FIND_STAT_FRAG(stat_name)
const Expr * get_else_expr() const
static ExpressionRange makeNullRange()
int64_t DateTruncate(DatetruncField field, const int64_t timeval)
bool is_timestamp() const
bool operator==(const ExpressionRange &other) const
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 64, 64, boost::multiprecision::signed_magnitude, boost::multiprecision::checked, void >> checked_int64_t
void apply_hpt_qual(const Datum const_datum, const SQLTypes const_type, const int32_t const_dimen, const int32_t col_dimen, const SQLOps sql_op, ExpressionRange &qual_range)
void apply_int_qual(const Datum const_datum, const SQLTypes const_type, const SQLOps sql_op, ExpressionRange &qual_range)
double extract_min_stat_double(const ChunkStats &stats, const SQLTypeInfo &col_ti)
HOST DEVICE int get_scale() const
const Expr * get_right_operand() const
#define DEF_OPERATOR(fname, op)
SQLTypeInfo get_logical_type_info(const SQLTypeInfo &type_info)
DatetruncField get_field() const
int64_t scale_up_interval_endpoint(const int64_t endpoint, const SQLTypeInfo &ti)
HOST DEVICE SQLTypes get_type() const
void setIntMin(const int64_t int_min)
constexpr int64_t get_datetime_scaled_epoch(const ScalingType direction, const int64_t epoch, const int32_t dimen)
const Expr * get_arg() const
static ExpressionRange makeFloatRange(const float fp_min, const float fp_max, const bool has_nulls)
ExpressionRange apply_simple_quals(const Analyzer::ColumnVar *col_expr, const ExpressionRange &col_range, const boost::optional< std::list< std::shared_ptr< Analyzer::Expr >>> simple_quals)
SQLOps get_optype() const
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
ExpressionRangeType type_
ExpressionRange operator||(const ExpressionRange &other) const
int64_t get_conservative_datetrunc_bucket(const DatetruncField datetrunc_field)
void apply_fp_qual(const Datum const_datum, const SQLTypes const_type, const SQLOps sql_op, ExpressionRange &qual_range)
ExpressionRange getLeafColumnRange(const Analyzer::ColumnVar *col_expr, const std::vector< InputTableInfo > &query_infos, const Executor *executor, const bool is_outer_join_proj)
ExpressionRange getExpressionRange(const Analyzer::BinOper *expr, const std::vector< InputTableInfo > &query_infos, const Executor *, boost::optional< std::list< std::shared_ptr< Analyzer::Expr >>> simple_quals)
const SQLTypeInfo & get_type_info() const
static ExpressionRange makeIntRange(const int64_t int_min, const int64_t int_max, const int64_t bucket, const bool has_nulls)
static ExpressionRange makeDoubleRange(const double fp_min, const double fp_max, const bool has_nulls)
const Expr * get_from_expr() const
HOST DEVICE EncodingType get_compression() const
const Expr * get_operand() const
Datum get_constval() const
HOST DEVICE int get_dimension() const
ExpressionRange operator/(const ExpressionRange &other) const
void setIntMax(const int64_t int_max)
int64_t extract_min_stat(const ChunkStats &stats, const SQLTypeInfo &ti)
ExpressionRangeType getType() const
int64_t getIntMax() const
constexpr int64_t get_timestamp_precision_scale(const int32_t dimen)
bool is_high_precision_timestamp() const
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
static bool typeSupportsRange(const SQLTypeInfo &ti)
int get_column_id() const
static ExpressionRange makeInvalidRange()
static int64_t getDateTruncConstantValue(const int64_t &timeval, const DatetruncField &field, const SQLTypeInfo &ti)
SQLTypeInfo get_elem_type() const
ExpressionRange getDateTimePrecisionCastRange(const ExpressionRange &arg_range, const SQLTypeInfo &oper_ti, const SQLTypeInfo &target_ti)
SQLOps get_optype() const
const std::list< std::pair< std::shared_ptr< Analyzer::Expr >, std::shared_ptr< Analyzer::Expr > > > & get_expr_pair_list() const
double extract_max_stat_double(const ChunkStats &stats, const SQLTypeInfo &col_ti)
int64_t extract_max_stat(const ChunkStats &stats, const SQLTypeInfo &ti)
ExpressionRange fpRangeFromDecimal(const ExpressionRange &arg_range, const int64_t scale, const SQLTypeInfo &target_ti)