diff --git a/src/planner/PlanNode.h b/src/planner/PlanNode.h
index f958733560045c2ae4b94c8541e369c38339539e..8c7b9cefe8220f5e77b28e691e9b27eda87bba34 100644
--- a/src/planner/PlanNode.h
+++ b/src/planner/PlanNode.h
@@ -228,6 +228,12 @@ public:
 protected:
     static void addDescription(std::string key, std::string value, PlanNodeDescription* desc);
 
+    void clone(const PlanNode &node) {
+        // TODO maybe shall copy cost_ and dependencies_ too
+        inputVars_ = node.inputVars_;
+        outputVars_ = node.outputVars_;
+    }
+
     QueryContext*                            qctx_{nullptr};
     Kind                                     kind_{Kind::kUnknown};
     int64_t                                  id_{-1};
@@ -255,6 +261,10 @@ protected:
         dependencies_.emplace_back(dep);
     }
 
+    void clone(const SingleDependencyNode &node) {
+        PlanNode::clone(node);
+    }
+
     std::unique_ptr<PlanNodeDescription> explain() const override;
 };
 
@@ -292,6 +302,10 @@ public:
     std::unique_ptr<PlanNodeDescription> explain() const override;
 
 protected:
+    void clone(const SingleInputNode &node) {
+        SingleDependencyNode::clone(node);
+    }
+
     SingleInputNode(QueryContext* qctx, Kind kind, const PlanNode* dep)
         : SingleDependencyNode(qctx, kind, dep) {
         if (dep != nullptr) {
diff --git a/src/planner/Query.cpp b/src/planner/Query.cpp
index 6aed83971ac7cb78d33e6305dad68079a1fe3718..a7b75b0d0761ffdddd2367896b9247c34b8b6785 100644
--- a/src/planner/Query.cpp
+++ b/src/planner/Query.cpp
@@ -29,39 +29,7 @@ std::unique_ptr<PlanNodeDescription> Explore::explain() const {
 
 GetNeighbors* GetNeighbors::clone(QueryContext* qctx) const {
     auto newGN = GetNeighbors::make(qctx, nullptr, space_);
-    newGN->setSrc(qctx->objPool()->add(src_->clone().release()));
-    newGN->setEdgeTypes(edgeTypes_);
-    newGN->setEdgeDirection(edgeDirection_);
-    newGN->setDedup(dedup_);
-    newGN->setRandom(random_);
-    newGN->setLimit(limit_);
-    newGN->setOrderBy(orderBy_);
-    newGN->setInputVar(inputVar());
-    newGN->setOutputVar(outputVar());
-
-    if (vertexProps_) {
-        auto vertexProps = *vertexProps_;
-        auto vertexPropsPtr = std::make_unique<decltype(vertexProps)>(vertexProps);
-        newGN->setVertexProps(std::move(vertexPropsPtr));
-    }
-
-    if (edgeProps_) {
-        auto edgeProps = *edgeProps_;
-        auto edgePropsPtr = std::make_unique<decltype(edgeProps)>(std::move(edgeProps));
-        newGN->setEdgeProps(std::move(edgePropsPtr));
-    }
-
-    if (statProps_) {
-        auto statProps = *statProps_;
-        auto statPropsPtr = std::make_unique<decltype(statProps)>(std::move(statProps));
-        newGN->setStatProps(std::move(statPropsPtr));
-    }
-
-    if (exprs_) {
-        auto exprs = *exprs_;
-        auto exprsPtr = std::make_unique<decltype(exprs)>(exprs);
-        newGN->setExprs(std::move(exprsPtr));
-    }
+    newGN->clone(*this);
     return newGN;
 }
 
@@ -83,6 +51,38 @@ std::unique_ptr<PlanNodeDescription> GetNeighbors::explain() const {
     return desc;
 }
 
+void GetNeighbors::clone(const GetNeighbors& g) {
+    Explore::clone(g);
+    setSrc(qctx_->objPool()->add(g.src_->clone().release()));
+    setEdgeTypes(g.edgeTypes_);
+    setEdgeDirection(g.edgeDirection_);
+    setRandom(g.random_);
+    if (g.vertexProps_) {
+        auto vertexProps = *g.vertexProps_;
+        auto vertexPropsPtr = std::make_unique<decltype(vertexProps)>(vertexProps);
+        setVertexProps(std::move(vertexPropsPtr));
+    }
+
+    if (g.edgeProps_) {
+        auto edgeProps = *g.edgeProps_;
+        auto edgePropsPtr = std::make_unique<decltype(edgeProps)>(std::move(edgeProps));
+        setEdgeProps(std::move(edgePropsPtr));
+    }
+
+    if (g.statProps_) {
+        auto statProps = *g.statProps_;
+        auto statPropsPtr = std::make_unique<decltype(statProps)>(std::move(statProps));
+        setStatProps(std::move(statPropsPtr));
+    }
+
+    if (g.exprs_) {
+        auto exprs = *g.exprs_;
+        auto exprsPtr = std::make_unique<decltype(exprs)>(exprs);
+        setExprs(std::move(exprsPtr));
+    }
+}
+
+
 std::unique_ptr<PlanNodeDescription> GetVertices::explain() const {
     auto desc = Explore::explain();
     addDescription("src", src_ ? src_->toString() : "", desc.get());
@@ -103,14 +103,25 @@ std::unique_ptr<PlanNodeDescription> GetEdges::explain() const {
 }
 
 IndexScan* IndexScan::clone(QueryContext* qctx) const {
-    auto ctx = std::make_unique<std::vector<storage::cpp2::IndexQueryContext>>();
-    auto returnCols = std::make_unique<std::vector<std::string>>(*returnColumns());
     auto* scan = IndexScan::make(
-        qctx, nullptr, space(), std::move(ctx), std::move(returnCols), isEdge(), schemaId());
-    scan->setOutputVar(this->outputVar());
+        qctx, nullptr, space(), nullptr, nullptr, isEdge(), schemaId());
+    scan->clone(*this);
     return scan;
 }
 
+void IndexScan::clone(const IndexScan &g) {
+    Explore::clone(g);
+    if (g.contexts_ != nullptr) {
+        contexts_ = std::make_unique<std::vector<storage::cpp2::IndexQueryContext>>(*g.contexts_);
+    }
+    if (g.returnCols_ != nullptr) {
+        returnCols_ = std::make_unique<std::vector<std::string>>(*g.returnCols_);
+    }
+    isEdge_ = g.isEdge_;
+    schemaId_ = g.schemaId_;
+    isEmptyResultSet_ = g.isEmptyResultSet_;
+}
+
 std::unique_ptr<PlanNodeDescription> IndexScan::explain() const {
     auto desc = Explore::explain();
     addDescription("schemaId", util::toJson(schemaId_), desc.get());
@@ -127,17 +138,19 @@ std::unique_ptr<PlanNodeDescription> Filter::explain() const {
 }
 
 Project* Project::clone(QueryContext* qctx) const {
-    auto cols = qctx->objPool()->add(new YieldColumns());
-    for (auto col : columns()->columns()) {
-        cols->addColumn((col->clone()).release());
-    }
-
-    auto newProj = Project::make(qctx, nullptr, cols);
-    newProj->setInputVar(inputVar());
-    newProj->setOutputVar(outputVar());
+    auto newProj = Project::make(qctx, nullptr, nullptr);
+    newProj->clone(*this);
     return newProj;
 }
 
+void Project::clone(const Project &p) {
+    SingleInputNode::clone(p);
+    cols_ = qctx_->objPool()->makeAndAdd<YieldColumns>();
+    for (const auto &col : p.columns()->columns()) {
+        cols_->addColumn(col->clone().release());
+    }
+}
+
 std::unique_ptr<PlanNodeDescription> Project::explain() const {
     auto desc = SingleInputNode::explain();
     addDescription("columns", cols_ ? cols_->toString() : "", desc.get());
@@ -152,11 +165,16 @@ std::unique_ptr<PlanNodeDescription> Sort::explain() const {
 
 Limit* Limit::clone(QueryContext* qctx) const {
     auto newLimit = Limit::make(qctx, nullptr, offset_, count_);
-    newLimit->setInputVar(inputVar());
-    newLimit->setOutputVar(outputVar());
+    newLimit->clone(*this);
     return newLimit;
 }
 
+void Limit::clone(const Limit &l) {
+    SingleInputNode::clone(l);
+    offset_ = l.offset_;
+    count_ = l.count_;
+}
+
 std::unique_ptr<PlanNodeDescription> Limit::explain() const {
     auto desc = SingleInputNode::explain();
     addDescription("offset", folly::to<std::string>(offset_), desc.get());
diff --git a/src/planner/Query.h b/src/planner/Query.h
index 6ac8b06822fa744493429a1144e638e95f6a084e..d6d6ca2a4180524fdd8dd9da42f3bf7b3a8313eb 100644
--- a/src/planner/Query.h
+++ b/src/planner/Query.h
@@ -90,6 +90,15 @@ protected:
         : SingleInputNode(qctx, kind, input), space_(space) {}
 
 protected:
+    void clone(const Explore& e) {
+        SingleInputNode::clone(e);
+        space_ = e.space_;
+        dedup_ = e.dedup_;
+        limit_ = e.limit_;
+        filter_ = e.filter_;
+        orderBy_ = e.orderBy_;
+    }
+
     GraphSpaceID space_;
     bool dedup_{false};
     int64_t limit_{std::numeric_limits<int64_t>::max()};
@@ -215,6 +224,8 @@ private:
         : Explore(qctx, Kind::kGetNeighbors, input, space) {}
 
 private:
+    void clone(const GetNeighbors& g);
+
     Expression*                                  src_{nullptr};
     std::vector<EdgeType>                        edgeTypes_;
     storage::cpp2::EdgeDirection edgeDirection_{storage::cpp2::EdgeDirection::OUT_EDGE};
@@ -502,6 +513,8 @@ private:
         isEmptyResultSet_ = isEmptyResultSet;
     }
 
+    void clone(const IndexScan &g);
+
 private:
     IndexQueryCtx                                 contexts_;
     IndexReturnCols                               returnCols_;
@@ -617,6 +630,8 @@ private:
     Project(QueryContext* qctx, PlanNode* input, YieldColumns* cols)
       : SingleInputNode(qctx, Kind::kProject, input), cols_(cols) { }
 
+    void clone(const Project &p);
+
 private:
     YieldColumns*               cols_{nullptr};
 };
@@ -694,6 +709,8 @@ private:
         count_ = count;
     }
 
+    void clone(const Limit &l);
+
 private:
     int64_t     offset_{-1};
     int64_t     count_{-1};
diff --git a/tests/tck/features/go/GO.IntVid.feature b/tests/tck/features/go/GO.IntVid.feature
index f5462b44a5c7a03c101383937dfe41aaa5a75625..c802d664267733527b6970bb7f456326dfc243fc 100644
--- a/tests/tck/features/go/GO.IntVid.feature
+++ b/tests/tck/features/go/GO.IntVid.feature
@@ -1593,3 +1593,13 @@ Feature: IntegerVid Go  Sentence
     Then the result should be, in any order, with relax comparison:
       | COUNT($-.id) |
       | 4            |
+
+  @skip
+  Scenario: Integer Vid Bugfix filter not pushdown
+    When executing query:
+      """
+      GO FROM hash("Tim Duncan") OVER like WHERE like._dst == hash("Tony Parker") | limit 10;
+      """
+    Then the result should be, in any order, with relax comparison:
+      | like._dst           |
+      | hash("Tony Parker") |
diff --git a/tests/tck/features/go/GO.feature b/tests/tck/features/go/GO.feature
index 61400991ab4fa91c91d5dfc3d139d3a8a7b3e88f..f0ca0849474b658c1be234f5c1fd1137c9db3cee 100644
--- a/tests/tck/features/go/GO.feature
+++ b/tests/tck/features/go/GO.feature
@@ -1593,3 +1593,12 @@ Feature: Go Sentence
     Then the result should be, in any order, with relax comparison:
       | COUNT($-.id) |
       | 4            |
+
+  Scenario: Bugfix filter not pushdown
+    When executing query:
+      """
+      GO FROM "Tim Duncan" OVER like WHERE like._dst == "Tony Parker" | limit 10;
+      """
+    Then the result should be, in any order, with relax comparison:
+      | like._dst     |
+      | "Tony Parker" |