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;
}