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->getColumnKey() != col_expr->
getColumnKey()) {
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);
302 const Executor* executor);
307 const std::vector<InputTableInfo>& query_infos,
312 const std::vector<InputTableInfo>& query_infos,
314 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
318 const std::vector<InputTableInfo>& query_infos,
320 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
324 const std::vector<InputTableInfo>& query_infos,
325 const Executor* executor,
326 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
330 const std::vector<InputTableInfo>& query_infos,
331 const Executor* executor,
332 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals);
336 const std::vector<InputTableInfo>& query_infos,
337 const Executor* executor,
338 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
341 }
else if (
auto bin_oper_expr = dynamic_cast<const Analyzer::BinOper*>(expr)) {
343 }
else if (
auto constant_expr = dynamic_cast<const Analyzer::Constant*>(expr)) {
345 }
else if (
auto column_var_expr = dynamic_cast<const Analyzer::ColumnVar*>(expr)) {
347 }
else if (
auto string_oper_expr = dynamic_cast<const Analyzer::StringOper*>(expr)) {
349 }
else if (
auto like_expr = dynamic_cast<const Analyzer::LikeExpr*>(expr)) {
351 }
else if (
auto case_expr = dynamic_cast<const Analyzer::CaseExpr*>(expr)) {
353 }
else if (
auto u_expr = dynamic_cast<const Analyzer::UOper*>(expr)) {
355 }
else if (
auto extract_expr = dynamic_cast<const Analyzer::ExtractExpr*>(expr)) {
357 }
else if (
auto datetrunc_expr = dynamic_cast<const Analyzer::DatetruncExpr*>(expr)) {
359 }
else if (
auto width_expr = dynamic_cast<const Analyzer::WidthBucketExpr*>(expr)) {
375 const std::vector<InputTableInfo>& query_infos,
376 const Executor* executor,
377 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
398 return adjusted_lhs / rhs;
414 switch (constant_type) {
416 const int64_t v = datum.tinyintval;
420 const int64_t v = datum.smallintval;
424 const int64_t v = datum.intval;
430 const int64_t v = datum.bigintval;
436 const int64_t v = datum.bigintval;
451 #define FIND_STAT_FRAG(stat_name) \
452 const auto stat_name##_frag_index = std::stat_name##_element( \
453 nonempty_fragment_indices.begin(), \
454 nonempty_fragment_indices.end(), \
455 [&fragments, &has_nulls, col_id, col_ti](const size_t lhs_idx, \
456 const size_t rhs_idx) { \
457 const auto& lhs = fragments[lhs_idx]; \
458 const auto& rhs = fragments[rhs_idx]; \
459 auto lhs_meta_it = lhs.getChunkMetadataMap().find(col_id); \
460 if (lhs_meta_it == lhs.getChunkMetadataMap().end()) { \
463 auto rhs_meta_it = rhs.getChunkMetadataMap().find(col_id); \
464 CHECK(rhs_meta_it != rhs.getChunkMetadataMap().end()); \
465 if (lhs_meta_it->second->chunkStats.has_nulls || \
466 rhs_meta_it->second->chunkStats.has_nulls) { \
469 if (col_ti.is_fp()) { \
470 return extract_##stat_name##_stat_fp_type(lhs_meta_it->second->chunkStats, \
472 extract_##stat_name##_stat_fp_type(rhs_meta_it->second->chunkStats, \
475 return extract_##stat_name##_stat_int_type(lhs_meta_it->second->chunkStats, \
477 extract_##stat_name##_stat_int_type(rhs_meta_it->second->chunkStats, \
480 if (stat_name##_frag_index == nonempty_fragment_indices.end()) { \
481 return ExpressionRange::makeInvalidRange(); \
487 const int64_t day_seconds{24 * 3600};
488 const int64_t year_days{365};
489 switch (datetrunc_field) {
491 return year_days * day_seconds;
493 return 90 * day_seconds;
495 return 28 * day_seconds;
503 return 1000 * year_days * day_seconds;
505 return 100 * year_days * day_seconds;
507 return 10 * year_days * day_seconds;
511 return 7 * day_seconds;
522 const std::vector<InputTableInfo>& query_infos,
523 const Executor* executor,
524 const bool is_outer_join_proj) {
525 bool has_nulls = is_outer_join_proj;
531 switch (col_ti.get_type()) {
548 std::optional<size_t> ti_idx;
549 for (
size_t i = 0; i < query_infos.size(); ++i) {
550 if (col_expr->
getTableKey() == query_infos[i].table_key) {
556 const auto& query_info = query_infos[*ti_idx].info;
557 const auto& fragments = query_info.fragments;
558 const auto cd = executor->getColumnDescriptor(col_expr);
559 if (cd && cd->isVirtualCol) {
560 CHECK(cd->columnName ==
"rowid");
562 const int64_t num_tuples = query_info.getNumTuples();
564 0, std::max(num_tuples - 1, int64_t(0)), 0, has_nulls);
566 if (query_info.getNumTuples() == 0) {
568 if (col_ti.is_fp()) {
569 return col_ti.get_type() ==
kFLOAT
575 std::vector<size_t> nonempty_fragment_indices;
576 for (
size_t i = 0; i < fragments.size(); ++i) {
577 const auto& fragment = fragments[i];
578 if (!fragment.isEmptyPhysicalFragment()) {
579 nonempty_fragment_indices.push_back(i);
584 const auto& min_frag = fragments[*min_frag_index];
585 const auto min_it = min_frag.getChunkMetadataMap().find(col_id);
586 if (min_it == min_frag.getChunkMetadataMap().end()) {
589 const auto& max_frag = fragments[*max_frag_index];
590 const auto max_it = max_frag.getChunkMetadataMap().find(col_id);
591 CHECK(max_it != max_frag.getChunkMetadataMap().end());
592 for (
const auto& fragment : fragments) {
593 const auto it = fragment.getChunkMetadataMap().find(col_id);
594 if (it != fragment.getChunkMetadataMap().end()) {
595 if (it->second->chunkStats.has_nulls) {
604 if (min_it->second->isPlaceholder() || max_it->second->isPlaceholder()) {
608 if (col_ti.is_fp()) {
611 return col_ti.get_type() ==
kFLOAT
617 if (max_val < min_val) {
622 const int64_t bucket =
632 #undef FIND_STAT_FRAG
636 const std::vector<InputTableInfo>& query_infos,
637 const Executor* executor,
638 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
641 CHECK_LT(static_cast<size_t>(rte_idx), query_infos.size());
642 bool is_outer_join_proj = rte_idx > 0 && executor->containsLeftDeepOuterJoin();
644 if (column_key.table_id > 0) {
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->get_type_info(),
671 chained_string_op->getLiteralArgs());
672 string_op_infos.emplace_back(string_op_info);
680 CHECK(expr_ti.is_dict_encoded_string());
682 const auto& dict_key = expr_ti.getStringDictKey();
684 const auto translation_map = executor->getStringProxyTranslationMap(
689 executor->getRowSetMemoryOwner(),
694 translation_map->rangeEnd() - 1,
708 CHECK(ti.is_boolean());
715 const std::vector<InputTableInfo>& query_infos,
716 const Executor* executor) {
719 bool has_nulls =
false;
720 for (
const auto& expr_pair : expr_pair_list) {
722 const auto crt_range =
732 ? expr_range || crt_range
736 expr_range.setHasNulls();
741 if (else_null_expr && else_null_expr->get_is_null()) {
742 expr_range.setHasNulls();
756 static_cast<float>(arg_range.
getIntMin()) / scale,
757 static_cast<float>(arg_range.
getIntMax()) / scale,
761 static_cast<double>(arg_range.
getIntMin()) / scale,
762 static_cast<double>(arg_range.
getIntMax()) / scale,
771 const int64_t scale =
794 CHECK(oper_dimen != ti_dimen);
795 const int64_t min_ts =
796 ti_dimen > oper_dimen
799 abs(oper_dimen - ti_dimen))
803 abs(oper_dimen - ti_dimen));
804 const int64_t max_ts =
805 ti_dimen > oper_dimen
808 abs(oper_dimen - ti_dimen))
812 abs(oper_dimen - ti_dimen));
821 const std::vector<InputTableInfo>& query_infos,
822 const Executor* executor,
823 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
832 const auto sdp = executor->getStringDictionaryProxy(
833 ti.getStringDictKey(), executor->getRowSetMemoryOwner(),
true);
835 const auto colvar_operand =
837 if (colvar_operand) {
839 if (!(colvar_ti.is_none_encoded_string() &&
840 ti.getStringDictKey().isTransientDict())) {
842 <<
"Unable to determine expression range for dictionary encoded expression "
847 CHECK_EQ(sdp->storageEntryCount(), 0UL);
848 const int64_t transient_entries =
static_cast<int64_t
>(sdp->transientEntryCount());
849 int64_t
const tuples_upper_bound =
static_cast<int64_t
>(
853 [](
auto max,
auto const& query_info) {
854 return std::max(max, query_info.info.getNumTuples());
856 const int64_t conservative_range_min = -1L - transient_entries - tuples_upper_bound;
859 const auto const_operand =
861 if (!const_operand) {
865 VLOG(1) <<
"Unable to determine expression range for dictionary encoded expression "
870 if (const_operand->get_is_null()) {
873 CHECK(const_operand->get_constval().stringval);
874 const int64_t v = sdp->getIdOfString(*const_operand->get_constval().stringval);
877 const auto arg_range =
881 if ((ti.is_timestamp() && (arg_ti.get_dimension() != ti.get_dimension())) ||
882 ((arg_ti.is_timestamp() && ti.is_any<
kDATE,
kTIME>()))) {
885 switch (arg_range.getType()) {
889 return ti.get_type() ==
kDOUBLE
891 arg_range.getFpMin(), arg_range.getFpMax(), arg_range.hasNulls())
893 arg_range.getFpMax(),
894 arg_range.hasNulls());
896 if (ti.is_integer()) {
898 std::ceil(arg_range.getFpMax()),
900 arg_range.hasNulls());
905 if (ti.is_decimal()) {
906 CHECK_EQ(int64_t(0), arg_range.getBucket());
907 const int64_t scale =
exp_to_scale(ti.get_scale() - arg_ti.get_scale());
909 arg_range.getIntMax() * scale,
911 arg_range.hasNulls());
913 if (arg_ti.is_decimal()) {
914 CHECK_EQ(int64_t(0), arg_range.getBucket());
916 const int64_t scale_half = scale / 2;
921 (arg_range.getIntMax() + scale_half) / scale,
923 arg_range.hasNulls());
925 if (ti.is_integer() || ti.is_time()) {
928 if (ti.get_type() ==
kFLOAT) {
930 arg_range.getIntMin(), arg_range.getIntMax(), arg_range.hasNulls());
932 if (ti.get_type() ==
kDOUBLE) {
934 arg_range.getIntMin(), arg_range.getIntMax(), arg_range.hasNulls());
948 const std::vector<InputTableInfo>& query_infos,
949 const Executor* executor,
950 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
951 const int32_t extract_field{extract_expr->
get_field()};
953 extract_expr->
get_from_expr(), query_infos, executor, simple_quals);
954 const bool has_nulls =
957 switch (extract_field) {
963 const int64_t year_range_min =
964 extract_expr_ti.is_high_precision_timestamp()
967 arg_range.getIntMin() /
970 const int64_t year_range_max =
971 extract_expr_ti.is_high_precision_timestamp()
974 arg_range.getIntMax() /
978 year_range_min, year_range_max, 0, arg_range.hasNulls());
1020 const std::vector<InputTableInfo>& query_infos,
1021 const Executor* executor,
1022 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
1024 datetrunc_expr->
get_from_expr(), query_infos, executor, simple_quals);
1030 arg_range.getIntMin(), datetrunc_expr->
get_field(), datetrunc_expr_ti);
1032 arg_range.getIntMax(), datetrunc_expr->
get_field(), datetrunc_expr_ti);
1033 const int64_t bucket =
1034 datetrunc_expr_ti.is_high_precision_timestamp()
1037 datetrunc_expr_ti.get_dimension())
1045 const std::vector<InputTableInfo>& query_infos,
1046 const Executor* executor,
1047 boost::optional<std::list<std::shared_ptr<Analyzer::Expr>>> simple_quals) {
1049 auto target_value_range =
getExpressionRange(target_value_expr, query_infos, executor);
1050 auto target_ti = target_value_expr->get_type_info();
1053 auto const_target_value =
dynamic_cast<const Analyzer::Constant*
>(target_value_expr);
1054 if (const_target_value) {
1055 if (const_target_value->get_is_null()) {
1060 CHECK(target_value_range.getFpMax() == target_value_range.getFpMin());
1061 auto target_value_bucket =
1062 width_bucket_expr->
compute_bucket(target_value_range.getFpMax());
1064 target_value_bucket, target_value_bucket, 0, target_value_range.hasNulls());
1069 const auto target_value_range_with_qual =
1074 auto lower_bound_bucket =
1076 auto upper_bound_bucket =
1079 lower_bound_bucket, upper_bound_bucket, 0, target_range.
hasNulls());
1081 auto res_range = compute_bucket_range(target_value_range_with_qual, target_ti);
1085 if (target_value_range.getFpMin() < target_value_range_with_qual.getFpMin() ||
1086 target_value_range.getFpMax() > target_value_range_with_qual.getFpMax()) {
1087 res_range.setNulls(
false);
1093 target_value_range.hasNulls();
1097 switch (partition_expr_range.getType()) {
1099 res.setIntMax(partition_expr_range.getIntMax() + 1);
1104 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()
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)
HOST DEVICE int get_scale() const
const Expr * get_right_operand() const
DEVICE int64_t DateTruncate(DatetruncField field, const int64_t timeval)
#define DEF_OPERATOR(fname, op)
SQLTypeInfo get_logical_type_info(const SQLTypeInfo &type_info)
DatetruncField get_field() const
bool requiresPerRowTranslation() 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)
#define TRANSIENT_DICT_ID
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)
int32_t compute_bucket(double target_const_val) const
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
const shared::ColumnKey & getColumnKey() 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
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)
const Expr * get_left_operand() const
static bool typeSupportsRange(const SQLTypeInfo &ti)
static ExpressionRange makeInvalidRange()
static int64_t getDateTruncConstantValue(const int64_t &timeval, const DatetruncField &field, const SQLTypeInfo &ti)
int32_t get_rte_idx() const
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)
SQLOps get_optype() const
const std::list< std::pair< std::shared_ptr< Analyzer::Expr >, std::shared_ptr< Analyzer::Expr > > > & get_expr_pair_list() const
shared::TableKey getTableKey() 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)