[fix](planner) conjuncts of the outer query block didn't work when it's on the results expr of inline view (#17036)

Here is a cases:

select id, name
from (select '123' as id, '1234' as name, age from test_insert ) a
where name != '1234';
This commit is contained in:
AKIRA
2023-02-24 16:27:34 +09:00
committed by GitHub
parent c39914c0a0
commit cf5bc9594b
15 changed files with 84 additions and 23 deletions

View File

@ -1206,7 +1206,8 @@ public class Analyzer {
}
}
public void registerMigrateFailedConjuncts(InlineViewRef ref, Expr e) {
public void registerMigrateFailedConjuncts(InlineViewRef ref, Expr e) throws AnalysisException {
markConstantConjunct(e, false);
Set<Expr> exprSet = globalState.migrateFailedConjuncts.computeIfAbsent(ref, (k) -> new HashSet<>());
exprSet.add(e);
}
@ -1371,7 +1372,8 @@ public class Analyzer {
&& !e.isAuxExpr()
&& !globalState.assignedConjuncts.contains(e.getId())
&& ((inclOjConjuncts && !e.isConstant())
|| !globalState.ojClauseByConjunct.containsKey(e.getId()))) {
|| (!globalState.ojClauseByConjunct.containsKey(e.getId())
&& !globalState.sjClauseByConjunct.containsKey(e.getId())))) {
result.add(e);
}
}
@ -1848,7 +1850,8 @@ public class Analyzer {
// aliases and having it analyzed is needed for the following EvalPredicate() call
conjunct.analyze(this);
}
final Expr newConjunct = conjunct.getResultValue();
Expr newConjunct = conjunct.getResultValue(true);
newConjunct = FoldConstantsRule.INSTANCE.apply(newConjunct, this, null);
if (newConjunct instanceof BoolLiteral || newConjunct instanceof NullLiteral) {
boolean evalResult = true;
if (newConjunct instanceof BoolLiteral) {
@ -2414,7 +2417,7 @@ public class Analyzer {
if (tids.size() > 1 || globalState.ojClauseByConjunct.containsKey(e.getId())
|| globalState.outerJoinedTupleIds.containsKey(e.getId()) && whereClauseConjuncts.contains(e.getId())
|| globalState.conjunctsByOjClause.containsKey(e.getId())) {
|| globalState.conjunctsByOjClause.containsKey(e.getId())) {
return true;
}

View File

@ -675,8 +675,8 @@ public class BinaryPredicate extends Predicate implements Writable {
}
@Override
public Expr getResultValue() throws AnalysisException {
recursiveResetChildrenResult();
public Expr getResultValue(boolean inView) throws AnalysisException {
recursiveResetChildrenResult(inView);
final Expr leftChildValue = getChild(0);
final Expr rightChildValue = getChild(1);
if (!(leftChildValue instanceof LiteralExpr)

View File

@ -412,8 +412,8 @@ public class CastExpr extends Expr {
}
@Override
public Expr getResultValue() throws AnalysisException {
recursiveResetChildrenResult();
public Expr getResultValue(boolean inView) throws AnalysisException {
recursiveResetChildrenResult(inView);
final Expr value = children.get(0);
if (!(value instanceof LiteralExpr)) {
return this;

View File

@ -230,8 +230,8 @@ public class CompoundPredicate extends Predicate {
}
@Override
public Expr getResultValue() throws AnalysisException {
recursiveResetChildrenResult();
public Expr getResultValue(boolean inView) throws AnalysisException {
recursiveResetChildrenResult(inView);
boolean compoundResult = false;
if (op == Operator.NOT) {
final Expr childValue = getChild(0);

View File

@ -1945,10 +1945,10 @@ public abstract class Expr extends TreeNode<Expr> implements ParseNode, Cloneabl
}
protected void recursiveResetChildrenResult() throws AnalysisException {
protected void recursiveResetChildrenResult(boolean inView) throws AnalysisException {
for (int i = 0; i < children.size(); i++) {
final Expr child = children.get(i);
final Expr newChild = child.getResultValue();
final Expr newChild = child.getResultValue(inView);
if (newChild != child) {
setChild(i, newChild);
}
@ -1960,8 +1960,8 @@ public abstract class Expr extends TreeNode<Expr> implements ParseNode, Cloneabl
* @return value returned can't be null, if this and it's children are't constant expr, return this.
* @throws AnalysisException
*/
public Expr getResultValue() throws AnalysisException {
recursiveResetChildrenResult();
public Expr getResultValue(boolean forPushDownPredicatesToView) throws AnalysisException {
recursiveResetChildrenResult(forPushDownPredicatesToView);
final Expr newExpr = ExpressionFunctions.INSTANCE.evalExpr(this);
return newExpr != null ? newExpr : this;
}

View File

@ -1409,7 +1409,7 @@ public class FunctionCallExpr extends Expr {
* Return type is DATETIME
*/
if (fn.getFunctionName().getFunction().equals("str_to_date")) {
Expr child1Result = getChild(1).getResultValue();
Expr child1Result = getChild(1).getResultValue(false);
if (child1Result instanceof StringLiteral) {
if (DateLiteral.hasTimePart(child1Result.getStringValue())) {
this.type = Type.DATETIME;

View File

@ -291,8 +291,8 @@ public class InPredicate extends Predicate {
}
@Override
public Expr getResultValue() throws AnalysisException {
recursiveResetChildrenResult();
public Expr getResultValue(boolean inView) throws AnalysisException {
recursiveResetChildrenResult(inView);
final Expr leftChildValue = getChild(0);
if (!(leftChildValue instanceof LiteralExpr) || !isLiteralChildren()) {
return this;

View File

@ -154,8 +154,8 @@ public class IsNullPredicate extends Predicate {
* fix issue 6390
*/
@Override
public Expr getResultValue() throws AnalysisException {
recursiveResetChildrenResult();
public Expr getResultValue(boolean inView) throws AnalysisException {
recursiveResetChildrenResult(inView);
final Expr childValue = getChild(0);
if (!(childValue instanceof LiteralExpr)) {
return this;

View File

@ -109,7 +109,7 @@ public class SetVar {
throw new AnalysisException("Set statement does't support non-constant expr.");
}
final Expr literalExpr = value.getResultValue();
final Expr literalExpr = value.getResultValue(false);
if (!(literalExpr instanceof LiteralExpr)) {
throw new AnalysisException("Set statement does't support computing expr:" + literalExpr.toSql());
}

View File

@ -576,4 +576,26 @@ public class SlotRef extends Expr {
}
return !CreateMaterializedViewStmt.isMVColumn(name) && exprs.isEmpty();
}
@Override
public Expr getResultValue(boolean foldSlot) throws AnalysisException {
if (!foldSlot) {
return this;
}
if (!isConstant() || desc == null) {
return this;
}
List<Expr> exprs = desc.getSourceExprs();
if (CollectionUtils.isEmpty(exprs)) {
return this;
}
Expr expr = exprs.get(0);
if (expr instanceof SlotRef) {
return expr.getResultValue(foldSlot);
}
if (expr.isConstant()) {
return expr;
}
return this;
}
}

View File

@ -116,7 +116,7 @@ public class SysVariableDesc extends Expr {
}
@Override
public Expr getResultValue() throws AnalysisException {
public Expr getResultValue(boolean inView) throws AnalysisException {
if (!Strings.isNullOrEmpty(name) && VariableVarConverters.hasConverter(name)) {
// Return the string type here so that it can correctly match the subsequent function signature.
// And we also set `beConverted` to session variable name in StringLiteral, so that it can be cast back
@ -129,7 +129,7 @@ public class SysVariableDesc extends Expr {
throw new AnalysisException(e.getMessage());
}
}
return super.getResultValue();
return super.getResultValue(false);
}
@Override

View File

@ -40,6 +40,9 @@ import java.util.List;
public class SelectNode extends PlanNode {
private static final Logger LOG = LogManager.getLogger(SelectNode.class);
/**
* Used by nereids only.
*/
public SelectNode(PlanNodeId id, PlanNode child) {
super(id, child.getTupleIds(), "SELECT", StatisticalType.SELECT_NODE);
addChild(child);

View File

@ -122,7 +122,7 @@ public class FoldConstantsRule implements ExprRewriteRule {
return expr;
}
}
return expr.getResultValue();
return expr.getResultValue(false);
}
/**

View File

@ -1,3 +1,5 @@
-- This file is automatically generated. You should know what you did if you want to edit this
-- !sql --
-- !sql1 --

View File

@ -85,4 +85,35 @@ suite("literal_view_test") {
FROM test_v
WHERE substring('2022-12',6,2)='01';
"""
sql """DROP TABLE IF EXISTS `test_insert`"""
sql """
CREATE TABLE `test_insert` (
`id` varchar(11) NULL COMMENT '唯一标识',
`name` varchar(10) NULL COMMENT '采集时间',
`age` int(11) NULL
) ENGINE=OLAP
UNIQUE KEY(`id`)
COMMENT 'test'
DISTRIBUTED BY HASH(`id`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);
"""
sql """
insert into test_insert values (1,'doris',10),(2,'spark',2),(3,'flink',20);
"""
qt_sql1 """
select id, name
from (
select '123' as id,
'1234' as name,
age
from test_insert
) a
where name != '1234';
"""
}