[fix](Nereids) support check authorization for view but skip check in the view (#31289)
move UserAuthentication in BindRelation, support check authorization view but skip check in the view relate pr: #23295
This commit is contained in:
@ -119,6 +119,7 @@ public class CascadesContext implements ScheduleContext {
|
||||
private boolean isLeadingJoin = false;
|
||||
|
||||
private final Map<String, Hint> hintMap = Maps.newLinkedHashMap();
|
||||
private final boolean shouldCheckRelationAuthentication;
|
||||
|
||||
/**
|
||||
* Constructor of OptimizerContext.
|
||||
@ -128,7 +129,7 @@ public class CascadesContext implements ScheduleContext {
|
||||
*/
|
||||
private CascadesContext(Optional<CascadesContext> parent, Optional<CTEId> currentTree,
|
||||
StatementContext statementContext, Plan plan, Memo memo,
|
||||
CTEContext cteContext, PhysicalProperties requireProperties) {
|
||||
CTEContext cteContext, PhysicalProperties requireProperties, boolean shouldCheckRelationAuthentication) {
|
||||
this.parent = Objects.requireNonNull(parent, "parent should not null");
|
||||
this.currentTree = Objects.requireNonNull(currentTree, "currentTree should not null");
|
||||
this.statementContext = Objects.requireNonNull(statementContext, "statementContext should not null");
|
||||
@ -142,6 +143,7 @@ public class CascadesContext implements ScheduleContext {
|
||||
this.subqueryExprIsAnalyzed = new HashMap<>();
|
||||
this.runtimeFilterContext = new RuntimeFilterContext(getConnectContext().getSessionVariable());
|
||||
this.materializationContexts = new ArrayList<>();
|
||||
this.shouldCheckRelationAuthentication = shouldCheckRelationAuthentication;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,7 +152,13 @@ public class CascadesContext implements ScheduleContext {
|
||||
public static CascadesContext initContext(StatementContext statementContext,
|
||||
Plan initPlan, PhysicalProperties requireProperties) {
|
||||
return newContext(Optional.empty(), Optional.empty(), statementContext,
|
||||
initPlan, new CTEContext(), requireProperties);
|
||||
initPlan, new CTEContext(), requireProperties, true);
|
||||
}
|
||||
|
||||
public static CascadesContext initViewContext(StatementContext statementContext,
|
||||
Plan initPlan, PhysicalProperties requireProperties) {
|
||||
return newContext(Optional.empty(), Optional.empty(), statementContext,
|
||||
initPlan, new CTEContext(), requireProperties, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,13 +167,14 @@ public class CascadesContext implements ScheduleContext {
|
||||
public static CascadesContext newContextWithCteContext(CascadesContext cascadesContext,
|
||||
Plan initPlan, CTEContext cteContext) {
|
||||
return newContext(Optional.of(cascadesContext), Optional.empty(),
|
||||
cascadesContext.getStatementContext(), initPlan, cteContext, PhysicalProperties.ANY);
|
||||
cascadesContext.getStatementContext(), initPlan, cteContext, PhysicalProperties.ANY,
|
||||
cascadesContext.shouldCheckRelationAuthentication);
|
||||
}
|
||||
|
||||
public static CascadesContext newCurrentTreeContext(CascadesContext context) {
|
||||
return CascadesContext.newContext(context.getParent(), context.getCurrentTree(), context.getStatementContext(),
|
||||
context.getRewritePlan(), context.getCteContext(),
|
||||
context.getCurrentJobContext().getRequiredProperties());
|
||||
context.getCurrentJobContext().getRequiredProperties(), context.shouldCheckRelationAuthentication);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,13 +183,14 @@ public class CascadesContext implements ScheduleContext {
|
||||
public static CascadesContext newSubtreeContext(Optional<CTEId> subtree, CascadesContext context,
|
||||
Plan plan, PhysicalProperties requireProperties) {
|
||||
return CascadesContext.newContext(Optional.of(context), subtree, context.getStatementContext(),
|
||||
plan, context.getCteContext(), requireProperties);
|
||||
plan, context.getCteContext(), requireProperties, context.shouldCheckRelationAuthentication);
|
||||
}
|
||||
|
||||
private static CascadesContext newContext(Optional<CascadesContext> parent, Optional<CTEId> subtree,
|
||||
StatementContext statementContext, Plan initPlan,
|
||||
CTEContext cteContext, PhysicalProperties requireProperties) {
|
||||
return new CascadesContext(parent, subtree, statementContext, initPlan, null, cteContext, requireProperties);
|
||||
StatementContext statementContext, Plan initPlan, CTEContext cteContext,
|
||||
PhysicalProperties requireProperties, boolean shouldCheckRelationAuthentication) {
|
||||
return new CascadesContext(parent, subtree, statementContext, initPlan, null,
|
||||
cteContext, requireProperties, shouldCheckRelationAuthentication);
|
||||
}
|
||||
|
||||
public CascadesContext getRoot() {
|
||||
@ -636,6 +646,10 @@ public class CascadesContext implements ScheduleContext {
|
||||
isLeadingJoin = leadingJoin;
|
||||
}
|
||||
|
||||
public boolean shouldCheckRelationAuthentication() {
|
||||
return shouldCheckRelationAuthentication;
|
||||
}
|
||||
|
||||
public Map<String, Hint> getHintMap() {
|
||||
return hintMap;
|
||||
}
|
||||
|
||||
@ -44,7 +44,6 @@ import org.apache.doris.nereids.rules.analysis.ProjectWithDistinctToAggregate;
|
||||
import org.apache.doris.nereids.rules.analysis.ReplaceExpressionByChildOutput;
|
||||
import org.apache.doris.nereids.rules.analysis.ResolveOrdinalInOrderByAndGroupBy;
|
||||
import org.apache.doris.nereids.rules.analysis.SubqueryToApply;
|
||||
import org.apache.doris.nereids.rules.analysis.UserAuthentication;
|
||||
import org.apache.doris.nereids.rules.rewrite.MergeProjects;
|
||||
import org.apache.doris.nereids.rules.rewrite.SemiJoinCommute;
|
||||
|
||||
@ -119,8 +118,7 @@ public class Analyzer extends AbstractBatchJobExecutor {
|
||||
topDown(new EliminateLogicalSelectHint()),
|
||||
bottomUp(
|
||||
new BindRelation(customTableResolver),
|
||||
new CheckPolicy(),
|
||||
new UserAuthentication()
|
||||
new CheckPolicy()
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -132,8 +130,7 @@ public class Analyzer extends AbstractBatchJobExecutor {
|
||||
topDown(new EliminateLogicalSelectHint()),
|
||||
bottomUp(
|
||||
new BindRelation(customTableResolver),
|
||||
new CheckPolicy(),
|
||||
new UserAuthentication()
|
||||
new CheckPolicy()
|
||||
),
|
||||
bottomUp(new BindExpression()),
|
||||
bottomUp(new BindSlotWithPaths()),
|
||||
|
||||
@ -157,7 +157,7 @@ public class BindRelation extends OneAnalysisRuleFactory {
|
||||
}
|
||||
|
||||
// TODO: should generate different Scan sub class according to table's type
|
||||
LogicalPlan scan = getLogicalPlan(table, unboundRelation, tableQualifier, cascadesContext);
|
||||
LogicalPlan scan = getAndCheckLogicalPlan(table, unboundRelation, tableQualifier, cascadesContext);
|
||||
if (cascadesContext.isLeadingJoin()) {
|
||||
LeadingHint leading = (LeadingHint) cascadesContext.getHintMap().get("Leading");
|
||||
leading.putRelationIdAndTableName(Pair.of(unboundRelation.getRelationId(), tableName));
|
||||
@ -178,7 +178,7 @@ public class BindRelation extends OneAnalysisRuleFactory {
|
||||
if (table == null) {
|
||||
table = RelationUtil.getTable(tableQualifier, cascadesContext.getConnectContext().getEnv());
|
||||
}
|
||||
return getLogicalPlan(table, unboundRelation, tableQualifier, cascadesContext);
|
||||
return getAndCheckLogicalPlan(table, unboundRelation, tableQualifier, cascadesContext);
|
||||
}
|
||||
|
||||
private LogicalPlan makeOlapScan(TableIf table, UnboundRelation unboundRelation, List<String> tableQualifier) {
|
||||
@ -234,7 +234,17 @@ public class BindRelation extends OneAnalysisRuleFactory {
|
||||
return scan;
|
||||
}
|
||||
|
||||
private LogicalPlan getLogicalPlan(TableIf table, UnboundRelation unboundRelation, List<String> tableQualifier,
|
||||
private LogicalPlan getAndCheckLogicalPlan(TableIf table, UnboundRelation unboundRelation,
|
||||
List<String> tableQualifier, CascadesContext cascadesContext) {
|
||||
// if current context is in the view, we can skip check authentication because
|
||||
// the view already checked authentication
|
||||
if (cascadesContext.shouldCheckRelationAuthentication()) {
|
||||
UserAuthentication.checkPermission(table, cascadesContext.getConnectContext());
|
||||
}
|
||||
return doGetLogicalPlan(table, unboundRelation, tableQualifier, cascadesContext);
|
||||
}
|
||||
|
||||
private LogicalPlan doGetLogicalPlan(TableIf table, UnboundRelation unboundRelation, List<String> tableQualifier,
|
||||
CascadesContext cascadesContext) {
|
||||
switch (table.getType()) {
|
||||
case OLAP:
|
||||
@ -289,7 +299,7 @@ public class BindRelation extends OneAnalysisRuleFactory {
|
||||
if (parsedViewPlan instanceof UnboundResultSink) {
|
||||
parsedViewPlan = (LogicalPlan) ((UnboundResultSink<?>) parsedViewPlan).child();
|
||||
}
|
||||
CascadesContext viewContext = CascadesContext.initContext(
|
||||
CascadesContext viewContext = CascadesContext.initViewContext(
|
||||
parentContext.getStatementContext(), parsedViewPlan, PhysicalProperties.ANY);
|
||||
viewContext.newAnalyzer(true, customTableResolver).analyze();
|
||||
// we should remove all group expression of the plan which in other memo, so the groupId would not conflict
|
||||
|
||||
@ -23,44 +23,31 @@ import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.datasource.CatalogIf;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
import org.apache.doris.nereids.exceptions.AnalysisException;
|
||||
import org.apache.doris.nereids.rules.Rule;
|
||||
import org.apache.doris.nereids.rules.RuleType;
|
||||
import org.apache.doris.nereids.trees.plans.Plan;
|
||||
import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
/**
|
||||
* Check whether a user is permitted to scan specific tables.
|
||||
*/
|
||||
public class UserAuthentication extends OneAnalysisRuleFactory {
|
||||
|
||||
@Override
|
||||
public Rule build() {
|
||||
return logicalRelation()
|
||||
.when(CatalogRelation.class::isInstance)
|
||||
.thenApply(ctx -> checkPermission((CatalogRelation) ctx.root, ctx.connectContext))
|
||||
.toRule(RuleType.RELATION_AUTHENTICATION);
|
||||
}
|
||||
|
||||
private Plan checkPermission(CatalogRelation relation, ConnectContext connectContext) {
|
||||
public class UserAuthentication {
|
||||
/** checkPermission. */
|
||||
public static void checkPermission(TableIf table, ConnectContext connectContext) {
|
||||
if (table == null) {
|
||||
return;
|
||||
}
|
||||
// do not check priv when replaying dump file
|
||||
if (connectContext.getSessionVariable().isPlayNereidsDump()) {
|
||||
return null;
|
||||
}
|
||||
TableIf table = relation.getTable();
|
||||
if (table == null) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
String tableName = table.getName();
|
||||
DatabaseIf db = table.getDatabase();
|
||||
// when table inatanceof FunctionGenTable,db will be null
|
||||
if (db == null) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
String dbName = db.getFullName();
|
||||
CatalogIf catalog = db.getCatalog();
|
||||
if (catalog == null) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
String ctlName = catalog.getName();
|
||||
// TODO: 2023/7/19 checkColumnsPriv
|
||||
@ -71,7 +58,5 @@ public class UserAuthentication extends OneAnalysisRuleFactory {
|
||||
ctlName + ": " + dbName + ": " + tableName);
|
||||
throw new AnalysisException(message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user