17 package org.apache.calcite.rel.rules;
19 import org.apache.calcite.plan.RelOptRuleCall;
20 import org.apache.calcite.plan.RelOptTable;
21 import org.apache.calcite.plan.RelRule;
22 import org.apache.calcite.rel.RelNode;
23 import org.apache.calcite.rel.logical.LogicalTableScan;
24 import org.apache.calcite.rel.type.RelDataTypeField;
25 import org.apache.calcite.rex.RexBuilder;
26 import org.apache.calcite.rex.RexNode;
27 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
28 import org.apache.calcite.sql.type.SqlTypeName;
29 import org.apache.calcite.tools.RelBuilder;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 import java.util.ArrayList;
34 import java.util.HashSet;
35 import java.util.List;
42 final static Logger
HEAVYDBLOGGER = LoggerFactory.getLogger(InjectFilterRule.class);
56 public void onMatch(RelOptRuleCall call) {
57 LogicalTableScan childScanNode = call.rel(0);
58 String scanNodeString = childScanNode.toString();
62 visitedMemo.add(scanNodeString);
64 RelOptTable table = childScanNode.getTable();
65 List<String> qname = table.getQualifiedName();
67 String query_database = null;
68 String query_table = null;
69 if (qname.size() == 2) {
70 query_database = qname.get(0);
71 query_table = qname.get(1);
73 if (query_database == null || query_database.isEmpty() || query_table == null
74 || query_table.isEmpty()) {
75 throw new RuntimeException(
76 "Restrictions: Expected qualified name as [database, table] but got: "
80 ArrayList<RexNode> orList =
new ArrayList<RexNode>();
81 RelBuilder builder = call.builder();
82 RexBuilder rBuilder = builder.getRexBuilder();
83 builder = builder.push(childScanNode);
84 boolean found =
false;
87 String rest_database = restriction.getRestrictionDatabase();
88 if (rest_database != null && !rest_database.isEmpty()
89 && !rest_database.equals(query_database)) {
91 HEAVYDBLOGGER.debug(
"RLS row-level security restriction for database "
92 + rest_database +
" ignored because this query is on database "
98 String rest_table = restriction.getRestrictionTable();
99 if (rest_table != null && !rest_table.isEmpty()
100 && !rest_table.equals(query_table)) {
102 HEAVYDBLOGGER.debug(
"RLS row-level security restriction for table " + rest_table
103 +
" ignored because this query is on table " + query_table);
108 RelDataTypeField
field = table.getRowType().getField(
109 restriction.getRestrictionColumn(),
false,
false);
111 HEAVYDBLOGGER.debug(
"RLS row-level security restriction for column "
112 + restriction.getRestrictionColumn()
113 +
" ignored because column not present in query table " + query_table);
120 "Scan is " + childScanNode.toString() +
" TABLE is " + table.toString());
121 HEAVYDBLOGGER.debug(
"Column " + restriction.getRestrictionColumn()
122 +
" exists in table " + table.getQualifiedName());
124 for (String val : restriction.getRestrictionValues()) {
125 HEAVYDBLOGGER.debug(
"Column is " + restriction.getRestrictionColumn()
126 +
" literal is '" + val +
"'");
128 if (SqlTypeName.NUMERIC_TYPES.indexOf(field.getType().getSqlTypeName()) == -1) {
129 if (val.length() < 2 || val.charAt(0) !=
'\''
130 || val.charAt(val.length() - 1) !=
'\'') {
131 throw new RuntimeException(
132 "Restrictions: Expected a CREATE POLICY VALUES string with single quotes.");
134 lit = rBuilder.makeLiteral(
135 val.substring(1, val.length() - 1), field.getType(),
false);
137 lit = rBuilder.makeLiteral(Integer.parseInt(val), field.getType(),
false);
139 RexNode rn = builder.call(SqlStdOperatorTable.EQUALS,
140 builder.field(restriction.getRestrictionColumn()),
147 RexNode relOr = builder.call(SqlStdOperatorTable.OR, orList);
148 final RelNode newNode = builder.filter(relOr).build();
149 call.transformTo(newNode);
156 EMPTY.withOperandSupplier(b0 -> b0.operand(LogicalTableScan.class).noInputs())
static final Logger HEAVYDBLOGGER
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
static Set< String > visitedMemo
void onMatch(RelOptRuleCall call)
default InjectFilterRule toRule()
default InjectFilterRule toRule(List< Restriction > rests)
InjectFilterRule(Config config, List< Restriction > restrictions)
final List< Restriction > restrictions