diff --git a/src/executor/query/FilterExecutor.cpp b/src/executor/query/FilterExecutor.cpp index c01aa3d5ea619bf41fc2c117ee965dcee7998b22..8b7f73d2dc3c004bceaa14337f6ee0acf0ef0c34 100644 --- a/src/executor/query/FilterExecutor.cpp +++ b/src/executor/query/FilterExecutor.cpp @@ -38,7 +38,11 @@ folly::Future<Status> FilterExecutor::execute() { "the type should be NULL,EMPTY or BOOL"); } if (val.empty() || val.isNull() || !val.getBool()) { - iter->unstableErase(); + if (UNLIKELY(filter->needStableFilter())) { + iter->erase(); + } else { + iter->unstableErase(); + } } else { iter->next(); } diff --git a/src/planner/Query.h b/src/planner/Query.h index a553ce81e3052a7d8ff5931af65f62b2151cb233..f1d212fc3815dfb7ef90cff3db547c3f93a08e49 100644 --- a/src/planner/Query.h +++ b/src/planner/Query.h @@ -532,25 +532,32 @@ class Filter final : public SingleInputNode { public: static Filter* make(QueryContext* qctx, PlanNode* input, - Expression* condition) { - return qctx->objPool()->add(new Filter(qctx, input, condition)); + Expression* condition, + bool needStableFilter = false) { + return qctx->objPool()->add(new Filter(qctx, input, condition, needStableFilter)); } Expression* condition() const { return condition_; } + bool needStableFilter() const { + return needStableFilter_; + } + std::unique_ptr<PlanNodeDescription> explain() const override; private: - Filter(QueryContext* qctx, PlanNode* input, Expression* condition) + Filter(QueryContext* qctx, PlanNode* input, Expression* condition, bool needStableFilter) : SingleInputNode(qctx, Kind::kFilter, input) { condition_ = condition; + needStableFilter_ = needStableFilter; } private: // Remain result when true Expression* condition_{nullptr}; + bool needStableFilter_; }; /** diff --git a/src/planner/match/WhereClausePlanner.cpp b/src/planner/match/WhereClausePlanner.cpp index 7c7cb1fad364e22ef4373312d869ccf091dd35cd..d0cbcda0f0acb5f1b4b3a35020aa8fbe1552d3e2 100644 --- a/src/planner/match/WhereClausePlanner.cpp +++ b/src/planner/match/WhereClausePlanner.cpp @@ -43,7 +43,7 @@ Status WhereClausePlanner::buildFilter(WhereClauseContext* wctx, SubPlan& subpla } auto* cond = wctx->qctx->objPool()->add(newFilter.release()); - subplan.root = Filter::make(wctx->qctx, nullptr, cond); + subplan.root = Filter::make(wctx->qctx, nullptr, cond, true); subplan.tail = subplan.root; return Status::OK(); } diff --git a/tests/tck/features/match/WithUnwind.feature b/tests/tck/features/match/WithUnwind.feature index 7b7734a5f78e1fb3d82c946637e12af06684c798..f1f15378435589eb160aa8b784239420321ab834 100644 --- a/tests/tck/features/match/WithUnwind.feature +++ b/tests/tck/features/match/WithUnwind.feature @@ -234,3 +234,36 @@ Feature: With clause and Unwind clause | "hello" | 1 | 1 | | "hello" | 2 | 2 | | "hello" | 3 | 3 | + + Scenario: match with return + When executing query: + """ + MATCH (v:player) + WITH v.age AS age, v AS v, v.name AS name + ORDER BY age DESCENDING, name ASCENDING + LIMIT 20 + WHERE age > 30 + RETURN v, age + """ + Then the result should be, in order, with relax comparison: + | v | age | + | ("Shaquile O'Neal" :player{age: 47, name: "Shaquile O'Neal"}) | 47 | + | ("Grant Hill" :player{age: 46, name: "Grant Hill"}) | 46 | + | ("Jason Kidd" :player{age: 45, name: "Jason Kidd"}) | 45 | + | ("Steve Nash" :player{age: 45, name: "Steve Nash"}) | 45 | + | ("Ray Allen" :player{age: 43, name: "Ray Allen"}) | 43 | + | ("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"}) | 42 | + | ("Vince Carter" :player{age: 42, name: "Vince Carter"}) | 42 | + | ("Manu Ginobili" :player{age: 41, name: "Manu Ginobili"}) | 41 | + | ("Dirk Nowitzki" :player{age: 40, name: "Dirk Nowitzki"}) | 40 | + | ("Kobe Bryant" :player{age: 40, name: "Kobe Bryant"}) | 40 | + | ("Tracy McGrady" :player{age: 39, name: "Tracy McGrady"}) | 39 | + | ("David West" :player{age: 38, name: "David West"}) | 38 | + | ("Paul Gasol" :player{age: 38, name: "Paul Gasol"}) | 38 | + | ("Yao Ming" :player{age: 38, name: "Yao Ming"}) | 38 | + | ("Dwyane Wade" :player{age: 37, name: "Dwyane Wade"}) | 37 | + | ("Amar'e Stoudemire" :player{age: 36, name: "Amar'e Stoudemire"}) | 36 | + | ("Boris Diaw" :player{age: 36, name: "Boris Diaw"}) | 36 | + | ("Tony Parker" :player{age: 36, name: "Tony Parker"}) | 36 | + | ("Carmelo Anthony" :player{age: 34, name: "Carmelo Anthony"}) | 34 | + | ("LeBron James" :player{age: 34, name: "LeBron James"}) | 34 |