Hi!
I'm new to Calcite and I'd like to use it to transform incoming SQL queries
to conform to some generic policy rules, like wrapping all table-scans with
a row-level filter. I hope this is the right place to ask questions like
this. Here's an example of what I'm trying to acheive:
-- admin says: ALTER TABLE orders SET TBLPROPERTIES (policy.filter =
'country IN user_countries')
SELECT * FROM orders -- <-- from user
SELECT * FROM (SELECT * FROM orders WHERE country IN user_countries()) --
<-- to backend
This is fairly simple to acheive when you have a static filter expression.
Here's what I've got working:
public static RelNode policyFilter(RelNode root, RelBuilder builder) {
return root.accept(new RelShuttleImpl() {
@Override
public RelNode visit(TableScan scan) {
RelNode n = super.visit(scan);
RexNode x = builder.in(builder.field("country"),
builder.literal("se"),
builder.literal("nl"),
builder.literal("dk"));
return builder
.push(n)
.filter(x)
.build();
}
});
}
This works, provided all my tables have a "country" column. What I'd like
to do, however, is allow user-defined filter expressions: make "RexNode x"
from a per-table String. I'd like this to be evaluated in the context of
the current table (so you can reference column names) and session (so
current_user(), for example, is available). I've looked at the Planner, but
it doesn't seem it's exposing enough of its internals (I don't have access
to its validator.validateExpression, for example).
Note that I'm new to Calcite, so I could be going around this completely
wrong. Looking at other uses of Calcite, I'm getting the impression that I
should be extending RelNodes and adding some Rules. I've also assumed that
I should be doing this with RelNodes instead of SqlNodes.
For the record, Kyuubi does something very similar using Spark here:
https://github.com/apache/kyuubi/blob/master/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/rule/rowfilter/RuleApplyRowFilter.scala#L42
Thanks for your feedback,
- Kris