31 #define DEF_OPERATOR(fname, op) \
32 ExpressionRange fname(const ExpressionRange& other) const { \
33 if (type_ == ExpressionRangeType::Invalid || \
34 other.type_ == ExpressionRangeType::Invalid) { \
35 return ExpressionRange::makeInvalidRange(); \
37 CHECK(type_ == other.type_); \
39 case ExpressionRangeType::Integer: \
40 return binOp<int64_t>(other, [](const int64_t x, const int64_t y) { \
41 return int64_t(checked_int64_t(x) op y); \
43 case ExpressionRangeType::Float: \
44 return binOp<float>(other, [](const float x, const float y) { \
45 std::feclearexcept(FE_OVERFLOW); \
46 std::feclearexcept(FE_UNDERFLOW); \
47 auto result = x op y; \
48 if (std::fetestexcept(FE_OVERFLOW) || std::fetestexcept(FE_UNDERFLOW)) { \
49 throw std::runtime_error("overflow / underflow"); \
53 case ExpressionRangeType::Double: \
54 return binOp<double>(other, [](const double x, const double y) { \
55 std::feclearexcept(FE_OVERFLOW); \
56 std::feclearexcept(FE_UNDERFLOW); \
57 auto result = x op y; \
58 if (std::fetestexcept(FE_OVERFLOW) || std::fetestexcept(FE_UNDERFLOW)) { \
59 throw std::runtime_error("overflow / underflow"); \
67 return ExpressionRange::makeInvalidRange(); \
78 double const_val = get_value_from_datum<double>(const_datum, const_type);
82 qual_range.setFpMin(std::max(qual_range.getFpMin(), const_val));
86 qual_range.setFpMax(std::min(qual_range.getFpMax(), const_val));
89 qual_range.setFpMin(std::max(qual_range.getFpMin(), const_val));
90 qual_range.setFpMax(std::min(qual_range.getFpMax(), const_val));
101 int64_t const_val = get_value_from_datum<int64_t>(const_datum, const_type);
126 const int32_t const_dimen,
127 const int32_t col_dimen,
130 CHECK(const_dimen != col_dimen);
132 if (const_dimen > col_dimen) {
134 get_value_from_datum<int64_t>(const_datum, const_type) /
138 get_value_from_datum<int64_t>(const_datum, const_type) *
147 const boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
152 for (
auto const& itr : simple_quals.get()) {
154 if (!qual_bin_oper) {
157 const Analyzer::Expr* left_operand = qual_bin_oper->get_left_operand();
172 if (qual_col->get_table_id() != col_expr->
get_table_id() ||
176 const Analyzer::Expr* right_operand = qual_bin_oper->get_right_operand();
184 qual_const->get_type_info().get_type(),
185 qual_bin_oper->get_optype(),
187 }
else if ((qual_col->get_type_info().is_timestamp() ||
188 qual_const->get_type_info().is_timestamp()) &&
189 (qual_col->get_type_info().get_dimension() !=
190 qual_const->get_type_info().get_dimension())) {
192 qual_const->get_type_info().get_type(),
193 qual_const->get_type_info().get_dimension(),
194 qual_col->get_type_info().get_dimension(),
195 qual_bin_oper->get_optype(),
199 qual_const->get_type_info().get_type(),
200 qual_bin_oper->get_optype(),
218 auto div_range = binOp<int64_t>(other, [](
const int64_t x,
const int64_t y) {
222 div_range.setHasNulls();
290 const std::vector<InputTableInfo>& query_infos,
292 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
298 const std::vector<InputTableInfo>& query_infos,
299 const Executor* executor,
300 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
303 const Executor* executor);
308 const std::vector<InputTableInfo>& query_infos,
313 const std::vector<InputTableInfo>& query_infos,
315 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
319 const std::vector<InputTableInfo>& query_infos,
321 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
325 const std::vector<InputTableInfo>& query_infos,
326 const Executor* executor,
327 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
331 const std::vector<InputTableInfo>& query_infos,
332 const Executor* executor,
333 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
337 const std::vector<InputTableInfo>& query_infos,
338 const Executor* executor,
339 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
342 }
else if (
auto bin_oper_expr = dynamic_cast<const Analyzer::BinOper*>(expr)) {
344 }
else if (
auto constant_expr = dynamic_cast<const Analyzer::Constant*>(expr)) {
346 }
else if (
auto column_var_expr = dynamic_cast<const Analyzer::ColumnVar*>(expr)) {
348 }
else if (
auto string_oper_expr = dynamic_cast<const Analyzer::StringOper*>(expr)) {
350 }
else if (
auto like_expr = dynamic_cast<const Analyzer::LikeExpr*>(expr)) {
352 }
else if (
auto case_expr = dynamic_cast<const Analyzer::CaseExpr*>(expr)) {
354 }
else if (
auto u_expr = dynamic_cast<const Analyzer::UOper*>(expr)) {
356 }
else if (
auto extract_expr = dynamic_cast<const Analyzer::ExtractExpr*>(expr)) {
358 }
else if (
auto datetrunc_expr = dynamic_cast<const Analyzer::DatetruncExpr*>(expr)) {
360 }
else if (
auto width_expr = dynamic_cast<const Analyzer::WidthBucketExpr*>(expr)) {
376 const std::vector<InputTableInfo>& query_infos,
377 const Executor* executor,
378 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
399 return adjusted_lhs / rhs;
415 switch (constant_type) {
417 const int64_t v = datum.tinyintval;
421 const int64_t v = datum.smallintval;
425 const int64_t v = datum.intval;
431 const int64_t v = datum.bigintval;
437 const int64_t v = datum.bigintval;
452 #define FIND_STAT_FRAG(stat_name) \
453 const auto stat_name##_frag_index = std::stat_name##_element( \
454 nonempty_fragment_indices.begin(), \
455 nonempty_fragment_indices.end(), \
456 [&fragments, &has_nulls, col_id, col_ti](const size_t lhs_idx, \
457 const size_t rhs_idx) { \
458 const auto& lhs = fragments[lhs_idx]; \
459 const auto& rhs = fragments[rhs_idx]; \
460 auto lhs_meta_it = lhs.getChunkMetadataMap().find(col_id); \
461 if (lhs_meta_it == lhs.getChunkMetadataMap().end()) { \
464 auto rhs_meta_it = rhs.getChunkMetadataMap().find(col_id); \
465 CHECK(rhs_meta_it != rhs.getChunkMetadataMap().end()); \
466 if (lhs_meta_it->second->chunkStats.has_nulls || \
467 rhs_meta_it->second->chunkStats.has_nulls) { \
470 if (col_ti.is_fp()) { \
471 return extract_##stat_name##_stat_fp_type(lhs_meta_it->second->chunkStats, \
473 extract_##stat_name##_stat_fp_type(rhs_meta_it->second->chunkStats, \
476 return extract_##stat_name##_stat_int_type(lhs_meta_it->second->chunkStats, \
478 extract_##stat_name##_stat_int_type(rhs_meta_it->second->chunkStats, \
481 if (stat_name##_frag_index == nonempty_fragment_indices.end()) { \
482 return ExpressionRange::makeInvalidRange(); \
488 const int64_t day_seconds{24 * 3600};
489 const int64_t year_days{365};
490 switch (datetrunc_field) {
492 return year_days * day_seconds;
494 return 90 * day_seconds;
496 return 28 * day_seconds;
504 return 1000 * year_days * day_seconds;
506 return 100 * year_days * day_seconds;
508 return 10 * year_days * day_seconds;
512 return 7 * day_seconds;
523 const std::vector<InputTableInfo>& query_infos,
524 const Executor* executor,
525 const bool is_outer_join_proj) {
526 bool has_nulls = is_outer_join_proj;
532 switch (col_ti.get_type()) {
549 std::optional<size_t> ti_idx;
550 for (
size_t i = 0; i < query_infos.size(); ++i) {
551 if (col_expr->
get_table_id() == query_infos[i].table_id) {
557 const auto& query_info = query_infos[*ti_idx].info;
558 const auto& fragments = query_info.fragments;
559 const auto cd = executor->getColumnDescriptor(col_expr);
560 if (cd && cd->isVirtualCol) {
561 CHECK(cd->columnName ==
"rowid");
563 const int64_t num_tuples = query_info.getNumTuples();
565 0, std::max(num_tuples - 1, int64_t(0)), 0, has_nulls);
567 if (query_info.getNumTuples() == 0) {
569 if (col_ti.is_fp()) {
570 return col_ti.get_type() ==
kFLOAT
576 std::vector<size_t> nonempty_fragment_indices;
577 for (
size_t i = 0; i < fragments.size(); ++i) {
578 const auto& fragment = fragments[i];
579 if (!fragment.isEmptyPhysicalFragment()) {
580 nonempty_fragment_indices.push_back(i);
585 const auto& min_frag = fragments[*min_frag_index];
586 const auto min_it = min_frag.getChunkMetadataMap().find(col_id);
587 if (min_it == min_frag.getChunkMetadataMap().end()) {
590 const auto& max_frag = fragments[*max_frag_index];
591 const auto max_it = max_frag.getChunkMetadataMap().find(col_id);
592 CHECK(max_it != max_frag.getChunkMetadataMap().end());
593 for (
const auto& fragment : fragments) {
594 const auto it = fragment.getChunkMetadataMap().find(col_id);
595 if (it != fragment.getChunkMetadataMap().end()) {
596 if (it->second->chunkStats.has_nulls) {
605 if (min_it->second->isPlaceholder() || max_it->second->isPlaceholder()) {
609 if (col_ti.is_fp()) {
612 return col_ti.get_type() ==
kFLOAT
618 if (max_val < min_val) {
623 const int64_t bucket =
633 #undef FIND_STAT_FRAG
637 const std::vector<InputTableInfo>& query_infos,
638 const Executor* executor,
639 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
642 CHECK_LT(static_cast<size_t>(rte_idx), query_infos.size());
643 bool is_outer_join_proj = rte_idx > 0 && executor->containsLeftDeepOuterJoin();
645 auto col_range = executor->getColRange(
647 if (is_outer_join_proj) {
648 col_range.setHasNulls();
656 const Executor* executor) {
658 if (chained_string_op_exprs.empty()) {
659 throw std::runtime_error(
660 "StringOper getExpressionRange() Expected folded string operator but found "
661 "operator unfolded.");
664 std::vector<StringOps_Namespace::StringOpInfo> string_op_infos;
665 for (
const auto& chained_string_op_expr : chained_string_op_exprs) {
666 auto chained_string_op =
668 CHECK(chained_string_op);
670 chained_string_op->getLiteralArgs());
671 string_op_infos.emplace_back(string_op_info);
675 CHECK(string_oper_col_var_expr);
676 const auto string_oper_col_var =
678 CHECK(string_oper_col_var);
679 const auto string_oper_col_var_ti = string_oper_col_var->get_type_info();
680 if (string_oper_col_var_ti.is_none_encoded_string()) {
686 CHECK(string_oper_col_var_ti.is_dict_encoded_string());
689 CHECK(expr_ti.is_string());
690 const auto dict_id = expr_ti.get_comp_param();
692 const auto translation_map = executor->getStringProxyTranslationMap(
697 executor->getRowSetMemoryOwner(),
702 translation_map->rangeEnd() - 1,
709 CHECK(ti.is_boolean());
716 const std::vector<InputTableInfo>& query_infos,
717 const Executor* executor) {
720 bool has_nulls =
false;
721 for (
const auto& expr_pair : expr_pair_list) {
723 const auto crt_range =
733 ? expr_range || crt_range
737 expr_range.setHasNulls();
742 if (else_null_expr && else_null_expr->get_is_null()) {
743 expr_range.setHasNulls();
757 static_cast<float>(arg_range.
getIntMin()) / scale,
758 static_cast<float>(arg_range.
getIntMax()) / scale,
762 static_cast<double>(arg_range.
getIntMin()) / scale,
763 static_cast<double>(arg_range.
getIntMax()) / scale,
772 const int64_t scale =
795 CHECK(oper_dimen != ti_dimen);
796 const int64_t min_ts =
797 ti_dimen > oper_dimen
800 abs(oper_dimen - ti_dimen))
804 abs(oper_dimen - ti_dimen));
805 const int64_t max_ts =
806 ti_dimen > oper_dimen
809 abs(oper_dimen - ti_dimen))
813 abs(oper_dimen - ti_dimen));
822 const std::vector<InputTableInfo>& query_infos,
823 const Executor* executor,
824 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
833 const auto sdp = executor->getStringDictionaryProxy(
834 ti.get_comp_param(), executor->getRowSetMemoryOwner(),
true);
836 const auto colvar_operand =
838 if (colvar_operand) {
840 if (!(colvar_ti.is_none_encoded_string() &&
843 <<
"Unable to determine expression range for dictionary encoded expression "
848 CHECK_EQ(sdp->storageEntryCount(), 0UL);
849 const int64_t transient_entries =
static_cast<int64_t
>(sdp->transientEntryCount());
850 int64_t
const tuples_upper_bound =
static_cast<int64_t
>(
854 [](
auto max,
auto const& query_info) {
855 return std::max(max, query_info.info.getNumTuples());
857 const int64_t conservative_range_min = -1L - transient_entries - tuples_upper_bound;
860 const auto const_operand =
862 if (!const_operand) {
866 VLOG(1) <<
"Unable to determine expression range for dictionary encoded expression "
871 if (const_operand->get_is_null()) {
874 CHECK(const_operand->get_constval().stringval);
875 const int64_t v = sdp->getIdOfString(*const_operand->get_constval().stringval);
878 const auto arg_range =
882 if ((ti.is_timestamp() && (arg_ti.get_dimension() != ti.get_dimension())) ||
883 ((arg_ti.is_timestamp() && ti.is_any(
kDATE,
kTIME)))) {
886 switch (arg_range.getType()) {
890 return ti.get_type() ==
kDOUBLE
892 arg_range.getFpMin(), arg_range.getFpMax(), arg_range.hasNulls())
894 arg_range.getFpMax(),
895 arg_range.hasNulls());
897 if (ti.is_integer()) {
899 std::ceil(arg_range.getFpMax()),
901 arg_range.hasNulls());
906 if (ti.is_decimal()) {
907 CHECK_EQ(int64_t(0), arg_range.getBucket());
908 const int64_t scale =
exp_to_scale(ti.get_scale() - arg_ti.get_scale());
910 arg_range.getIntMax() * scale,
912 arg_range.hasNulls());
914 if (arg_ti.is_decimal()) {
915 CHECK_EQ(int64_t(0), arg_range.getBucket());
917 const int64_t scale_half = scale / 2;
922 (arg_range.getIntMax() + scale_half) / scale,
924 arg_range.hasNulls());
926 if (ti.is_integer() || ti.is_time()) {
929 if (ti.get_type() ==
kFLOAT) {
931 arg_range.getIntMin(), arg_range.getIntMax(), arg_range.hasNulls());
933 if (ti.get_type() ==
kDOUBLE) {
935 arg_range.getIntMin(), arg_range.getIntMax(), arg_range.hasNulls());
949 const std::vector<InputTableInfo>& query_infos,
950 const Executor* executor,
951 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
952 const int32_t extract_field{extract_expr->
get_field()};
954 extract_expr->
get_from_expr(), query_infos, executor, simple_quals);
955 const bool has_nulls =
958 switch (extract_field) {
964 const int64_t year_range_min =
965 extract_expr_ti.is_high_precision_timestamp()
968 arg_range.getIntMin() /
971 const int64_t year_range_max =
972 extract_expr_ti.is_high_precision_timestamp()
975 arg_range.getIntMax() /
979 year_range_min, year_range_max, 0, arg_range.hasNulls());
1021 const std::vector<InputTableInfo>& query_infos,
1022 const Executor* executor,
1023 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
1025 datetrunc_expr->
get_from_expr(), query_infos, executor, simple_quals);
1031 arg_range.getIntMin(), datetrunc_expr->
get_field(), datetrunc_expr_ti);
1033 arg_range.getIntMax(), datetrunc_expr->
get_field(), datetrunc_expr_ti);
1034 const int64_t bucket =
1035 datetrunc_expr_ti.is_high_precision_timestamp()
1038 datetrunc_expr_ti.get_dimension())
1046 const std::vector<InputTableInfo>& query_infos,
1047 const Executor* executor,
1048 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
1050 auto target_value_range =
getExpressionRange(target_value_expr, query_infos, executor);
1051 auto target_ti = target_value_expr->get_type_info();
1054 auto const_target_value =
dynamic_cast<const Analyzer::Constant*
>(target_value_expr);
1055 if (const_target_value) {
1056 if (const_target_value->get_is_null()) {
1061 CHECK(target_value_range.getFpMax() == target_value_range.getFpMin());
1062 auto target_value_bucket =
1063 width_bucket_expr->
compute_bucket(target_value_range.getFpMax(), target_ti);
1065 target_value_bucket, target_value_bucket, 0, target_value_range.hasNulls());
1070 const auto target_value_range_with_qual =
1075 auto lower_bound_bucket =
1077 auto upper_bound_bucket =
1080 lower_bound_bucket, upper_bound_bucket, 0, target_range.
hasNulls());
1082 auto res_range = compute_bucket_range(target_value_range_with_qual, target_ti);
1086 if (target_value_range.getFpMin() < target_value_range_with_qual.getFpMin() ||
1087 target_value_range.getFpMax() > target_value_range_with_qual.getFpMax()) {
1088 res_range.setNulls(
false);
1094 target_value_range.hasNulls();
1098 switch (partition_expr_range.getType()) {
1100 res.setIntMax(partition_expr_range.getIntMax() + 1);
1105 res.setIntMax(static_cast<int64_t>(partition_expr_range.getFpMax()) + 1);
int64_t getIntMin() const
#define FIND_STAT_FRAG(stat_name)
const Expr * get_partition_count() const
bool is_constant_expr() const
const Expr * get_else_expr() const
static ExpressionRange makeNullRange()
std::shared_ptr< Analyzer::Expr > remove_cast(const std::shared_ptr< Analyzer::Expr > &expr)
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
bool is_any(Types...types) const
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)
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)
DEVICE auto accumulate(ARGS &&...args)
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)
virtual std::string toString() const =0
Expression class for string functions The "arg" constructor parameter must be an expression that reso...
const Expr * get_from_expr() const
#define TRANSIENT_DICT_ID
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
int32_t get_partition_count_val() const
void setIntMax(const int64_t int_max)
const Expr * get_target_value() const
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)
int32_t compute_bucket(T target_const_val, SQLTypeInfo &ti) const
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
std::vector< std::shared_ptr< Analyzer::Expr > > getChainedStringOpExprs() const
ExpressionRange getDateTimePrecisionCastRange(const ExpressionRange &arg_range, const SQLTypeInfo &oper_ti, const SQLTypeInfo &target_ti)
const Expr * getArg(const size_t i) const
SQLOps get_optype() const
const std::list< std::pair< std::shared_ptr< Analyzer::Expr >, std::shared_ptr< Analyzer::Expr > > > & get_expr_pair_list() const
ExpressionRange fpRangeFromDecimal(const ExpressionRange &arg_range, const int64_t scale, const SQLTypeInfo &target_ti)
RUNTIME_EXPORT ALWAYS_INLINE DEVICE int32_t width_bucket_expr(const double target_value, const bool reversed, const double lower_bound, const double upper_bound, const int32_t partition_count)