[Improvement](Nereids) Avoid unsafe cast. (#12603)
This PR changed some interfaces to avoid unsafe cast. - Modify `Plan.getExpressions()`'s return type from `List<Expression>` to `List<? extends Expression>` Return projects (type is a list of named expression) in `getExpressions` can avoid unsafe cast. See `LogicalProject.getExpression()` as an example. - Modify `EmptyRelation.getProjects()`'s return type from `List<NamedExpression>` to `List<? extends NamedExpression>` Creating empty relation with a list of slots can avoid unsafe cast. See the `EliminateLimit` rule for example.
This commit is contained in:
@ -17,8 +17,13 @@
|
||||
|
||||
package org.apache.doris.nereids.analyzer;
|
||||
|
||||
import org.apache.doris.nereids.trees.expressions.Slot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Relation base interface
|
||||
*/
|
||||
public interface Relation {
|
||||
List<Slot> getOutput();
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ public class UnboundOneRowRelation extends LogicalLeaf implements Unbound, OneRo
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
throw new UnsupportedOperationException(this.getClass().getSimpleName() + " don't support getExpression()");
|
||||
}
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ public class UnboundRelation extends LogicalLeaf implements Relation, Unbound {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
throw new UnsupportedOperationException(this.getClass().getSimpleName() + " don't support getExpression()");
|
||||
}
|
||||
|
||||
|
||||
@ -100,7 +100,7 @@ public class BindFunction implements AnalysisRuleFactory {
|
||||
);
|
||||
}
|
||||
|
||||
private <E extends Expression> List<E> bind(List<E> exprList, Env env) {
|
||||
private <E extends Expression> List<E> bind(List<? extends E> exprList, Env env) {
|
||||
return exprList.stream()
|
||||
.map(expr -> FunctionBinder.INSTANCE.bind(expr, env))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@ -23,8 +23,6 @@ import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Eliminate filter false.
|
||||
*/
|
||||
@ -33,7 +31,7 @@ public class EliminateFilter extends OneRewriteRuleFactory {
|
||||
public Rule build() {
|
||||
return logicalFilter()
|
||||
.when(filter -> filter.getPredicates() == BooleanLiteral.FALSE)
|
||||
.then(filter -> new LogicalEmptyRelation((List) filter.getOutput()))
|
||||
.then(filter -> new LogicalEmptyRelation(filter.getOutput()))
|
||||
.toRule(RuleType.ELIMINATE_FILTER);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,8 +22,6 @@ import org.apache.doris.nereids.rules.RuleType;
|
||||
import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Eliminate limit = 0.
|
||||
*/
|
||||
@ -32,7 +30,7 @@ public class EliminateLimit extends OneRewriteRuleFactory {
|
||||
public Rule build() {
|
||||
return logicalLimit()
|
||||
.when(limit -> limit.getLimit() == 0)
|
||||
.then(limit -> new LogicalEmptyRelation((List) limit.getOutput()))
|
||||
.then(limit -> new LogicalEmptyRelation(limit.getOutput()))
|
||||
.toRule(RuleType.ELIMINATE_LIMIT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ public class GroupPlan extends LogicalLeaf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ public interface Plan extends TreeNode<Plan> {
|
||||
|
||||
<R, C> R accept(PlanVisitor<R, C> visitor, C context);
|
||||
|
||||
List<Expression> getExpressions();
|
||||
List<? extends Expression> getExpressions();
|
||||
|
||||
LogicalProperties getLogicalProperties();
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.nereids.trees.plans.algebra;
|
||||
|
||||
import org.apache.doris.nereids.analyzer.Relation;
|
||||
import org.apache.doris.nereids.trees.expressions.NamedExpression;
|
||||
|
||||
import java.util.List;
|
||||
@ -27,6 +28,6 @@ import java.util.List;
|
||||
* e.g.
|
||||
* select * from tbl limit 0
|
||||
*/
|
||||
public interface EmptyRelation {
|
||||
List<NamedExpression> getProjects();
|
||||
public interface EmptyRelation extends Relation {
|
||||
List<? extends NamedExpression> getProjects();
|
||||
}
|
||||
|
||||
@ -19,21 +19,10 @@ package org.apache.doris.nereids.trees.plans.algebra;
|
||||
|
||||
import org.apache.doris.catalog.Table;
|
||||
import org.apache.doris.nereids.analyzer.Relation;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.Slot;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Common interface for logical/physical scan.
|
||||
*/
|
||||
public interface Scan extends Relation {
|
||||
List<Expression> getExpressions();
|
||||
|
||||
Table getTable();
|
||||
|
||||
default List<Slot> getOutput() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ public interface Command extends LogicalPlan {
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Expression> getExpressions() {
|
||||
default List<? extends Expression> getExpressions() {
|
||||
throw new RuntimeException("Command do not implement getExpressions");
|
||||
}
|
||||
|
||||
|
||||
@ -134,7 +134,7 @@ public class LogicalAggregate<CHILD_TYPE extends Plan> extends LogicalUnary<CHIL
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return new ImmutableList.Builder<Expression>()
|
||||
.addAll(groupByExpressions)
|
||||
.addAll(outputExpressions)
|
||||
|
||||
@ -140,7 +140,7 @@ public class LogicalApply<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
if (correlationFilter.isPresent()) {
|
||||
return new ImmutableList.Builder<Expression>()
|
||||
.addAll(correlationSlot)
|
||||
|
||||
@ -87,7 +87,7 @@ public class LogicalAssertNumRows<CHILD_TYPE extends Plan> extends LogicalUnary<
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of(assertNumRowsElement);
|
||||
}
|
||||
|
||||
|
||||
@ -40,13 +40,13 @@ import java.util.Optional;
|
||||
* select * from tbl limit 0
|
||||
*/
|
||||
public class LogicalEmptyRelation extends LogicalLeaf implements EmptyRelation {
|
||||
private final List<NamedExpression> projects;
|
||||
private final List<? extends NamedExpression> projects;
|
||||
|
||||
public LogicalEmptyRelation(List<NamedExpression> projects) {
|
||||
public LogicalEmptyRelation(List<? extends NamedExpression> projects) {
|
||||
this(projects, Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
public LogicalEmptyRelation(List<NamedExpression> projects, Optional<GroupExpression> groupExpression,
|
||||
public LogicalEmptyRelation(List<? extends NamedExpression> projects, Optional<GroupExpression> groupExpression,
|
||||
Optional<LogicalProperties> logicalProperties) {
|
||||
super(PlanType.LOGICAL_ONE_ROW_RELATION, groupExpression, logicalProperties);
|
||||
this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null"));
|
||||
@ -58,12 +58,12 @@ public class LogicalEmptyRelation extends LogicalLeaf implements EmptyRelation {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NamedExpression> getProjects() {
|
||||
public List<? extends NamedExpression> getProjects() {
|
||||
return projects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
@ -89,7 +89,7 @@ public class LogicalFilter<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_T
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of(predicates);
|
||||
}
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ public class LogicalHaving<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_T
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of(predicates);
|
||||
}
|
||||
|
||||
|
||||
@ -211,7 +211,7 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
Builder<Expression> builder = new Builder<Expression>()
|
||||
.addAll(hashJoinConjuncts);
|
||||
otherJoinCondition.ifPresent(builder::add);
|
||||
|
||||
@ -101,7 +101,7 @@ public class LogicalLimit<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TY
|
||||
return visitor.visitLogicalLimit(this, context);
|
||||
}
|
||||
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
@ -65,8 +65,8 @@ public class LogicalOneRowRelation extends LogicalLeaf implements OneRowRelation
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
return (List) projects;
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return projects;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -83,12 +83,12 @@ public class LogicalProject<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_
|
||||
|
||||
@Override
|
||||
public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
|
||||
return visitor.visitLogicalProject((LogicalProject<Plan>) this, context);
|
||||
return visitor.visitLogicalProject(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
return new ImmutableList.Builder<Expression>().addAll(projects).build();
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return projects;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -110,7 +110,7 @@ public abstract class LogicalRelation extends LogicalLeaf implements Scan {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ public class LogicalSelectHint<CHILD_TYPE extends Plan> extends LogicalUnary<CHI
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ public class LogicalSort<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYP
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return orderKeys.stream()
|
||||
.map(OrderKey::getExpr)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
|
||||
@ -29,7 +29,6 @@ import org.apache.doris.nereids.util.Utils;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@ -100,8 +99,8 @@ public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> extends LogicalUnary<
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
return Collections.emptyList();
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -108,7 +108,7 @@ public class LogicalTopN<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYP
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return orderKeys.stream()
|
||||
.map(OrderKey::getExpr)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
|
||||
@ -91,7 +91,7 @@ public abstract class AbstractPhysicalJoin<
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
Builder<Expression> builder = new Builder<Expression>()
|
||||
.addAll(hashJoinConjuncts);
|
||||
otherJoinCondition.ifPresent(builder::add);
|
||||
|
||||
@ -81,7 +81,7 @@ public abstract class AbstractPhysicalSort<CHILD_TYPE extends Plan> extends Phys
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return orderKeys.stream()
|
||||
.map(OrderKey::getExpr)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
|
||||
@ -126,7 +126,7 @@ public class PhysicalAggregate<CHILD_TYPE extends Plan> extends PhysicalUnary<CH
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
// TODO: partitionExprList maybe null.
|
||||
return new ImmutableList.Builder<Expression>().addAll(groupByExpressions).addAll(outputExpressions)
|
||||
.addAll(partitionExpressions).build();
|
||||
|
||||
@ -89,7 +89,7 @@ public class PhysicalAssertNumRows<CHILD_TYPE extends Plan> extends PhysicalUnar
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of(assertNumRowsElement);
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@ public class PhysicalDistribute<CHILD_TYPE extends Plan> extends PhysicalUnary<C
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
@ -41,13 +41,13 @@ import java.util.Optional;
|
||||
* select * from tbl limit 0
|
||||
*/
|
||||
public class PhysicalEmptyRelation extends PhysicalLeaf implements EmptyRelation {
|
||||
private final List<NamedExpression> projects;
|
||||
private final List<? extends NamedExpression> projects;
|
||||
|
||||
public PhysicalEmptyRelation(List<NamedExpression> projects, LogicalProperties logicalProperties) {
|
||||
public PhysicalEmptyRelation(List<? extends NamedExpression> projects, LogicalProperties logicalProperties) {
|
||||
this(projects, Optional.empty(), logicalProperties, null);
|
||||
}
|
||||
|
||||
public PhysicalEmptyRelation(List<NamedExpression> projects, Optional<GroupExpression> groupExpression,
|
||||
public PhysicalEmptyRelation(List<? extends NamedExpression> projects, Optional<GroupExpression> groupExpression,
|
||||
LogicalProperties logicalProperties, PhysicalProperties physicalProperties) {
|
||||
super(PlanType.PHYSICAL_EMPTY_RELATION, groupExpression, logicalProperties, physicalProperties);
|
||||
this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null"));
|
||||
@ -59,7 +59,7 @@ public class PhysicalEmptyRelation extends PhysicalLeaf implements EmptyRelation
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ public class PhysicalEmptyRelation extends PhysicalLeaf implements EmptyRelation
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NamedExpression> getProjects() {
|
||||
public List<? extends NamedExpression> getProjects() {
|
||||
return projects;
|
||||
}
|
||||
|
||||
|
||||
@ -86,7 +86,7 @@ public class PhysicalFilter<CHILD_TYPE extends Plan> extends PhysicalUnary<CHILD
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of(predicates);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ import org.apache.doris.nereids.memo.GroupExpression;
|
||||
import org.apache.doris.nereids.properties.LogicalProperties;
|
||||
import org.apache.doris.nereids.properties.PhysicalProperties;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
|
||||
import org.apache.doris.nereids.trees.plans.Plan;
|
||||
import org.apache.doris.nereids.trees.plans.PlanType;
|
||||
import org.apache.doris.nereids.trees.plans.algebra.Limit;
|
||||
@ -29,7 +28,7 @@ import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
|
||||
import org.apache.doris.nereids.util.Utils;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -93,11 +92,8 @@ public class PhysicalLimit<CHILD_TYPE extends Plan> extends PhysicalUnary<CHILD_
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
return Lists.newArrayList(
|
||||
new IntegerLiteral((int) limit),
|
||||
new IntegerLiteral((int) offset)
|
||||
);
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -65,8 +65,8 @@ public class PhysicalOneRowRelation extends PhysicalLeaf implements OneRowRelati
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
return (List) projects;
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return projects;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -91,8 +91,8 @@ public class PhysicalProject<CHILD_TYPE extends Plan> extends PhysicalUnary<CHIL
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
return (List) projects;
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return projects;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -89,7 +89,7 @@ public abstract class PhysicalRelation extends PhysicalLeaf implements Scan {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
public List<? extends Expression> getExpressions() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ import org.apache.doris.nereids.memo.GroupExpression;
|
||||
import org.apache.doris.nereids.properties.LogicalProperties;
|
||||
import org.apache.doris.nereids.properties.OrderKey;
|
||||
import org.apache.doris.nereids.properties.PhysicalProperties;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.plans.Plan;
|
||||
import org.apache.doris.nereids.trees.plans.PlanType;
|
||||
import org.apache.doris.nereids.trees.plans.algebra.TopN;
|
||||
@ -29,7 +28,6 @@ import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
|
||||
import org.apache.doris.nereids.util.Utils;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -105,13 +103,6 @@ public class PhysicalTopN<CHILD_TYPE extends Plan> extends AbstractPhysicalSort<
|
||||
return visitor.visitPhysicalTopN((PhysicalTopN<Plan>) this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Expression> getExpressions() {
|
||||
return orderKeys.stream()
|
||||
.map(OrderKey::getExpr)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PhysicalTopN<Plan> withChildren(List<Plan> children) {
|
||||
Preconditions.checkArgument(children.size() == 1);
|
||||
|
||||
@ -48,7 +48,7 @@ public abstract class AnalyzeCheckTestBase extends TestWithFeService {
|
||||
}
|
||||
}
|
||||
|
||||
List<Expression> expressions = plan.getExpressions();
|
||||
List<? extends Expression> expressions = plan.getExpressions();
|
||||
return expressions.stream().allMatch(this::checkExpressionBound);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user