bool PaxSparseFilter::ExecOpNode()

in contrib/pax_storage/src/cpp/storage/filter/pax_sparse_filter.cc [596:885]


bool PaxSparseFilter::ExecOpNode(PaxSparseExecContext *exec_ctx,
                                 const std::shared_ptr<PFTNode> &node) {
  bool no_filter = false;
  PaxSparseExecContext lctx_copy(*exec_ctx), rctx_copy(*exec_ctx);
  std::shared_ptr<OpNode> op_node;
  OperMinMaxFunc lfunc1, lfunc2;
  FmgrInfo finfo;

  Assert(node && IsNode(node, OpType) && node->sub_nodes.size() == 2);
  op_node = std::dynamic_pointer_cast<OpNode>(node);

  no_filter = no_filter || ExecFilterTree(&lctx_copy, node->sub_nodes[0]);
  no_filter = no_filter || ExecFilterTree(&rctx_copy, node->sub_nodes[1]);
  if (no_filter) {
    return no_filter;
  }

  // deal the op(var, var) case
  if (lctx_copy.from_node == VarType && rctx_copy.from_node == VarType) {
    AttrNumber lidx, ridx;
    Form_pg_attribute lattr, rattr;
    Datum matches = true;

    Oid ltypid, rtypid, coll;
    bool ok;

    if (!lctx_copy.var_value.exist_min_max ||
        !rctx_copy.var_value.exist_min_max) {
      // no min max exist
      return true;
    }

    lidx = lctx_copy.var_value.attrno - 1;
    ridx = rctx_copy.var_value.attrno - 1;

    // Bypass when lattrno is same with rattrno
    if (lidx == ridx) {
      switch (op_node->strategy) {
        case BTLessStrategyNumber:
        case BTGreaterStrategyNumber: {
          return false;
        }
        case BTLessEqualStrategyNumber:
        case BTEqualStrategyNumber:
        case BTGreaterEqualStrategyNumber:
        default:
          return true;
      }
    }

    lattr = CheckAndGetAttr(lidx, lctx_copy.provider, lctx_copy.desc,
                            op_node->collation, true);
    rattr = CheckAndGetAttr(ridx, rctx_copy.provider, rctx_copy.desc,
                            op_node->collation, true);

    // no stats or collation not match
    if (!lattr || !rattr) {
      return true;
    }

    coll = OidIsValid(op_node->collation) ? op_node->collation
                                          : lattr->attcollation;
    ltypid = op_node->left_typid;
    rtypid = op_node->right_typid;
    // no need check the l/r.var_value.typid
    // because in PG, some of type can direct do the cast without cast node
    // used l/r.var_value.typid or typid in `op_node` both ok in this case

    auto left_min_with_right_max = [&](StrategyNumber strategynum) {
      Datum m = true;
      if (MinMaxGetStrategyProcinfo(ltypid, rtypid, coll, lfunc1,
                                    strategynum)) {
        Assert(lfunc1);
        m = lfunc1(&lctx_copy.var_value.min, &rctx_copy.var_value.max, coll);
      } else if (allow_fallback_to_pg_) {
        ok = MinMaxGetPgStrategyProcinfo(ltypid, rtypid, &finfo, strategynum);
        if (!ok) return m;
        m = cbdb::FunctionCall2Coll(&finfo, coll, lctx_copy.var_value.min,
                                    rctx_copy.var_value.max);
      }
      return m;
    };

    auto left_max_with_right_min = [&](StrategyNumber strategynum) {
      Datum m = true;
      if (MinMaxGetStrategyProcinfo(ltypid, rtypid, coll, lfunc1,
                                    strategynum)) {
        Assert(lfunc1);
        m = lfunc1(&lctx_copy.var_value.max, &rctx_copy.var_value.min, coll);
      } else if (allow_fallback_to_pg_) {
        ok = MinMaxGetPgStrategyProcinfo(ltypid, rtypid, &finfo, strategynum);
        if (!ok) return m;
        m = cbdb::FunctionCall2Coll(&finfo, coll, lctx_copy.var_value.max,
                                    rctx_copy.var_value.min);
      }
      return m;
    };

    // v1 < v2: min(v1) >= max(v2) -> return false
    // v1 <= v2: min(v1) > max(v2) -> return false
    // v1 = v2: max(v1) <  min(v2) || min(v1) > max(v2) -> return false
    // v1 >= v2: max(v1) < min(v2) -> return false
    // v1 > v2: max(v1) <= min(v2) -> return false
    switch (op_node->strategy) {
      case BTLessStrategyNumber:
        matches = !left_min_with_right_max(BTGreaterEqualStrategyNumber);
        break;
      case BTLessEqualStrategyNumber: {
        matches = !left_min_with_right_max(BTGreaterStrategyNumber);
        break;
      }
      case BTEqualStrategyNumber: {
        matches &= !left_min_with_right_max(BTGreaterStrategyNumber);
        matches &= !left_max_with_right_min(BTLessStrategyNumber);
        break;
      }
      case BTGreaterEqualStrategyNumber: {
        matches = !left_max_with_right_min(BTLessStrategyNumber);
        break;
      }
      case BTGreaterStrategyNumber: {
        matches = !left_max_with_right_min(BTLessEqualStrategyNumber);
        break;
      }
      default:
        // not support others `sk_strategy`
        matches = BoolGetDatum(true);
        break;
    }

    return DatumGetBool(matches);
    // deal the op(var, const)/op(const, var) case
  } else if ((lctx_copy.from_node == VarType &&
              rctx_copy.from_node == ConstType) ||
             (lctx_copy.from_node == ConstType &&
              rctx_copy.from_node == VarType)) {
    Datum matches = true;
    Oid collation, ltypid, rtypid;
    bool ok;
    AttrNumber column_index;
    Form_pg_attribute attr;
    StrategyNumber strategy;
    Datum lmin, lmax, const_val;

    if (lctx_copy.from_node == VarType && rctx_copy.from_node == ConstType) {
      if (!lctx_copy.var_value.exist_min_max) {
        // no min_max stats
        return true;
      }

      lmin = lctx_copy.var_value.min;
      lmax = lctx_copy.var_value.max;
      const_val = rctx_copy.const_value.value;
      column_index = lctx_copy.var_value.attrno - 1;
      attr = CheckAndGetAttr(column_index, lctx_copy.provider, lctx_copy.desc,
                             op_node->collation, true);
      ltypid = op_node->left_typid;
      rtypid = op_node->right_typid;
      strategy = op_node->strategy;
    } else {
      if (!rctx_copy.var_value.exist_min_max) {
        // no min_max stats
        return true;
      }
      lmin = rctx_copy.var_value.min;
      lmax = rctx_copy.var_value.max;
      const_val = lctx_copy.const_value.value;
      column_index = rctx_copy.var_value.attrno - 1;
      attr = CheckAndGetAttr(column_index, rctx_copy.provider, rctx_copy.desc,
                             op_node->collation, true);
      ltypid = op_node->right_typid;
      rtypid = op_node->left_typid;
      strategy = InvertStrategy(op_node->strategy);
    }

    // no stats or collation not match
    if (!attr) return true;

    collation = OidIsValid(op_node->collation) ? op_node->collation
                                               : attr->attcollation;

    // no need check the l/r.var_value.typid
    // because in PG, some of type can direct do the cast without cast node
    // used l/r.var_value.typid or typid in `op_node` both ok in this case

    switch (strategy) {
      case BTLessStrategyNumber:
      case BTLessEqualStrategyNumber: {
        if (MinMaxGetStrategyProcinfo(ltypid, rtypid, collation, lfunc1,
                                      strategy)) {
          Assert(lfunc1);
          matches = lfunc1(&lmin, &const_val, collation);
        } else if (allow_fallback_to_pg_) {
          ok = MinMaxGetPgStrategyProcinfo(ltypid, rtypid, &finfo, strategy);
          if (!ok) break;
          matches = cbdb::FunctionCall2Coll(&finfo, collation, lmin, const_val);
        }
        break;
      }
      case BTEqualStrategyNumber: {
        if (MinMaxGetStrategyProcinfo(ltypid, rtypid, collation, lfunc1,
                                      BTLessEqualStrategyNumber) &&
            MinMaxGetStrategyProcinfo(ltypid, rtypid, collation, lfunc2,
                                      BTGreaterEqualStrategyNumber)) {
          Assert(lfunc1 && lfunc2);
          matches = lfunc1(&lmin, &const_val, collation);
          if (!DatumGetBool(matches))
            // not (min <= value) --> min > value
            break;
          matches = lfunc2(&lmax, &const_val, collation);
        } else if (allow_fallback_to_pg_) {
          ok = MinMaxGetPgStrategyProcinfo(ltypid, rtypid, &finfo,
                                           BTLessEqualStrategyNumber);
          if (!ok) break;
          matches = cbdb::FunctionCall2Coll(&finfo, collation, lmin, const_val);

          if (!DatumGetBool(matches))
            // not (min <= value) --> min > value
            break;
          ok = MinMaxGetPgStrategyProcinfo(ltypid, rtypid, &finfo,
                                           BTGreaterEqualStrategyNumber);
          if (!ok) break;
          matches = cbdb::FunctionCall2Coll(&finfo, collation, lmin, const_val);
        }
        break;
      }
      case BTGreaterEqualStrategyNumber:
      case BTGreaterStrategyNumber: {
        if (MinMaxGetStrategyProcinfo(ltypid, rtypid, collation, lfunc1,
                                      strategy)) {
          Assert(lfunc1);
          matches = lfunc1(&lmax, &const_val, collation);
        } else if (allow_fallback_to_pg_) {
          ok = MinMaxGetPgStrategyProcinfo(ltypid, rtypid, &finfo, strategy);
          if (!ok) break;
          matches = cbdb::FunctionCall2Coll(&finfo, collation, lmax, const_val);
        }

        break;
      }
      default:
        // not support others `sk_strategy`
        matches = BoolGetDatum(true);
        break;
    }

    return DatumGetBool(matches);

    // deal the op(const, const) case
  } else if ((lctx_copy.from_node == ConstType &&
              rctx_copy.from_node == ConstType)) {
    Datum matches = true;
    bool ok;

    if (op_node->strategy == InvalidStrategy) {
      return true;
    }

    // no need check the typid in op_node
    // because in PG, some of type can direct do the cast without cast node
    // used l/r.const_value.const_typid or typid in `op_node` both ok in this
    // case

    if (MinMaxGetStrategyProcinfo(
            lctx_copy.const_value.const_type, rctx_copy.const_value.const_type,
            op_node->collation, lfunc1, op_node->strategy)) {
      Assert(lfunc1);
      matches = lfunc1(&lctx_copy.const_value.value,
                       &rctx_copy.const_value.value, op_node->collation);
      return matches;
    } else if (allow_fallback_to_pg_) {
      ok = MinMaxGetPgStrategyProcinfo(lctx_copy.const_value.const_type,
                                       rctx_copy.const_value.const_type, &finfo,
                                       op_node->strategy);
      if (!ok) return true;
      matches = cbdb::FunctionCall2Coll(&finfo, op_node->collation,
                                        lctx_copy.const_value.const_type,
                                        rctx_copy.const_value.const_type);
    }

    // if not match (ex. 11 > 42), current should return true
    // if match (ex. 11 < 42), current should return true
    return DatumGetBool(matches);
  } else {  // should not more case
    Assert(false);
  }

  // should not be here
  return true;
}