-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix expression rewrite #3614
Fix expression rewrite #3614
Changes from 12 commits
93ea748
ad81c55
cbf6f74
5d4081b
9ca2b03
cdcfea1
34771df
7389fff
7286943
15142ea
2a9e88f
a801264
4ed1065
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,8 +7,10 @@ | |
|
||
#include <memory> | ||
#include <queue> | ||
#include <unordered_set> | ||
|
||
#include "common/base/ObjectPool.h" | ||
#include "common/expression/ArithmeticExpression.h" | ||
#include "common/expression/Expression.h" | ||
#include "common/expression/PropertyExpression.h" | ||
#include "common/function/AggFunctionManager.h" | ||
|
@@ -415,30 +417,69 @@ Expression *ExpressionUtils::reduceUnaryNotExpr(const Expression *expr) { | |
|
||
Expression *ExpressionUtils::rewriteRelExpr(const Expression *expr) { | ||
ObjectPool *pool = expr->getObjPool(); | ||
// Match relational expressions containing at least one arithmetic expr | ||
auto matcher = [](const Expression *e) -> bool { | ||
if (e->isRelExpr()) { | ||
auto relExpr = static_cast<const RelationalExpression *>(e); | ||
if (isEvaluableExpr(relExpr->right())) { | ||
return true; | ||
QueryExpressionContext ctx(nullptr); | ||
|
||
auto checkArithmExpr = [&ctx](const ArithmeticExpression *arithmExpr) -> bool { | ||
auto lExpr = const_cast<Expression *>(arithmExpr->left()); | ||
auto rExpr = const_cast<Expression *>(arithmExpr->right()); | ||
Comment on lines
+423
to
+424
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For constant expression, you could call its method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we are still not sure about the type of |
||
|
||
// If the arithExpr has constant expr as member that is a string, do not rewrite | ||
if (lExpr->kind() == Expression::Kind::kConstant) { | ||
Aiee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (lExpr->eval(ctx).isStr()) { | ||
return false; | ||
} | ||
// TODO: To match arithmetic expression on both side | ||
auto lExpr = relExpr->left(); | ||
if (lExpr->isArithmeticExpr()) { | ||
auto arithmExpr = static_cast<const ArithmeticExpression *>(lExpr); | ||
return isEvaluableExpr(arithmExpr->left()) || isEvaluableExpr(arithmExpr->right()); | ||
} | ||
if (rExpr->kind() == Expression::Kind::kConstant) { | ||
Aiee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (rExpr->eval(ctx).isStr()) { | ||
return false; | ||
} | ||
} | ||
return false; | ||
return isEvaluableExpr(arithmExpr->left()) || isEvaluableExpr(arithmExpr->right()); | ||
}; | ||
|
||
// Match relational expressions following these rules: | ||
// 1. the right operand of rel expr should be evaluable | ||
// 2. the left operand of rel expr should be: | ||
// 2.a an arithmetic expr that does not contains string and has at least one operand that is | ||
// evaluable | ||
// OR | ||
// 2.b an relational expr so that it might could be simplified: | ||
// ((v.age > 40 == true) => (v.age > 40)) | ||
auto matcher = [&checkArithmExpr](const Expression *e) -> bool { | ||
if (!e->isRelExpr()) { | ||
return false; | ||
} | ||
|
||
auto relExpr = static_cast<const RelationalExpression *>(e); | ||
// Check right operand | ||
bool checkRightOperand = isEvaluableExpr(relExpr->right()); | ||
if (!checkRightOperand) { | ||
return false; | ||
} | ||
|
||
// Check left operand | ||
bool checkLeftOperand = false; | ||
auto lExpr = relExpr->left(); | ||
// Left operand is arithmetical expr | ||
if (lExpr->isArithmeticExpr()) { | ||
auto arithmExpr = static_cast<const ArithmeticExpression *>(lExpr); | ||
checkLeftOperand = checkArithmExpr(arithmExpr); | ||
} else if (lExpr->isRelExpr() || | ||
lExpr->kind() == Expression::Kind::kLabelAttribute) { // for expressions that | ||
// contain boolean literals | ||
// such as (v.age <= null) | ||
checkLeftOperand = true; | ||
Aiee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
return checkLeftOperand; | ||
}; | ||
|
||
// Simplify relational expressions involving boolean literals | ||
auto simplifyBoolOperand = | ||
[pool](RelationalExpression *relExpr, Expression *lExpr, Expression *rExpr) -> Expression * { | ||
QueryExpressionContext ctx(nullptr); | ||
auto simplifyBoolOperand = [pool, &ctx](RelationalExpression *relExpr, | ||
Expression *lExpr, | ||
Expression *rExpr) -> Expression * { | ||
if (rExpr->kind() == Expression::Kind::kConstant) { | ||
auto conExpr = static_cast<ConstantExpression *>(rExpr); | ||
auto val = conExpr->eval(ctx(nullptr)); | ||
auto val = conExpr->eval(ctx); | ||
auto valType = val.type(); | ||
// Rewrite to null if the expression contains any operand that is null | ||
if (valType == Value::Type::NULLVALUE) { | ||
|
@@ -521,21 +562,43 @@ Expression *ExpressionUtils::rewriteRelExprHelper(const Expression *expr, | |
// case Expression::Kind::kMultiply: | ||
// case Expression::Kind::kDivision: | ||
default: | ||
LOG(FATAL) << "Unsupported expression kind: " << static_cast<uint8_t>(kind); | ||
DLOG(ERROR) << "Unsupported expression kind: " << static_cast<uint8_t>(kind); | ||
break; | ||
} | ||
|
||
return rewriteRelExprHelper(root, relRightOperandExpr); | ||
} | ||
|
||
StatusOr<Expression *> ExpressionUtils::filterTransform(const Expression *filter) { | ||
auto rewrittenExpr = const_cast<Expression *>(filter); | ||
// If the filter contains more than one different LabelAttribute expr, this filter cannot be | ||
// pushed down | ||
auto propExprs = ExpressionUtils::collectAll(filter, {Expression::Kind::kLabelTagProperty}); | ||
// Deduplicate the list | ||
std::unordered_set<std::string> dedupPropExprSet; | ||
for (auto &iter : propExprs) { | ||
dedupPropExprSet.emplace(iter->toString()); | ||
} | ||
if (dedupPropExprSet.size() > 1) { | ||
return const_cast<Expression *>(filter); | ||
} | ||
|
||
// Check if any overflow happen before filter tranform | ||
auto initialConstFold = foldConstantExpr(filter); | ||
NG_RETURN_IF_ERROR(initialConstFold); | ||
|
||
// Rewrite relational expression | ||
auto rewrittenExpr = initialConstFold.value(); | ||
rewrittenExpr = rewriteRelExpr(rewrittenExpr); | ||
Aiee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Fold constant expression | ||
auto constantFoldRes = foldConstantExpr(rewrittenExpr); | ||
NG_RETURN_IF_ERROR(constantFoldRes); | ||
// If errors like overflow happened during the constant fold, stop transferming and return the | ||
// original expression | ||
if (!constantFoldRes.ok()) { | ||
return const_cast<Expression *>(filter); | ||
} | ||
rewrittenExpr = constantFoldRes.value(); | ||
|
||
// Reduce Unary expression | ||
rewrittenExpr = reduceUnaryNotExpr(rewrittenExpr); | ||
return rewrittenExpr; | ||
|
@@ -880,8 +943,9 @@ Expression::Kind ExpressionUtils::getNegatedArithmeticType(const Expression::Kin | |
return Expression::Kind::kDivision; | ||
case Expression::Kind::kDivision: | ||
return Expression::Kind::kMultiply; | ||
// There is no oppsite operation to Mod, return itself | ||
case Expression::Kind::kMod: | ||
LOG(FATAL) << "Unsupported expression kind: " << static_cast<uint8_t>(kind); | ||
return Expression::Kind::kMod; | ||
break; | ||
default: | ||
LOG(FATAL) << "Invalid arithmetic expression kind: " << static_cast<uint8_t>(kind); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to do it in separate PR, don't modify unrelated code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emm, just a format change