diff --git a/src/context/QueryExpressionContext.h b/src/context/QueryExpressionContext.h
index fb7721ddfcf1198a18bccf874fca08a5cdf27ecb..afc062bcb4cb55cbe25f998a6f6338419df648d7 100644
--- a/src/context/QueryExpressionContext.h
+++ b/src/context/QueryExpressionContext.h
@@ -17,9 +17,8 @@ namespace graph {
 
 class QueryExpressionContext final : public ExpressionContext {
 public:
-    explicit QueryExpressionContext(ExecutionContext* ectx, Iterator* iter = nullptr) {
+    explicit QueryExpressionContext(ExecutionContext* ectx = nullptr) {
         ectx_ = ectx;
-        iter_ = iter;
     }
 
     // Get the latest version value for the given variable name, such as $a, $b
@@ -60,13 +59,17 @@ public:
 
     void setVar(const std::string&, Value val) override;
 
-    void setIter(Iterator* iter) {
+    QueryExpressionContext& operator()(Iterator* iter) {
         iter_ = iter;
+        return *this;
     }
 
 private:
-    ExecutionContext*                 ectx_;
-    Iterator*                         iter_;
+    // ExecutionContext and Iterator are used for getting runtime results,
+    // and nullptr is acceptable for these two members if the expressions
+    // could be evaluated as constant value.
+    ExecutionContext*                 ectx_{nullptr};
+    Iterator*                         iter_{nullptr};
 };
 
 }  // namespace graph
diff --git a/src/context/test/ExpressionContextTest.cpp b/src/context/test/ExpressionContextTest.cpp
index 698f7c98ca49e7f24380f9462973b1400e039c0c..2c1d9fcc2a266c20782327420db4b76e8d6dd3c3 100644
--- a/src/context/test/ExpressionContextTest.cpp
+++ b/src/context/test/ExpressionContextTest.cpp
@@ -11,20 +11,20 @@
 namespace nebula {
 namespace graph {
 TEST(ExpressionContextTest, GetVar) {
-    ExecutionContext qctx;
-    qctx.setValue("v1", 10);
-    qctx.setValue("v2", "Hello world");
+    ExecutionContext ectx;
+    ectx.setValue("v1", 10);
+    ectx.setValue("v2", "Hello world");
 
-    graph::QueryExpressionContext ectx(&qctx, nullptr);
-    EXPECT_EQ(Value(10), ectx.getVar("v1"));
-    EXPECT_EQ(Value("Hello world"), ectx.getVar("v2"));
+    graph::QueryExpressionContext qECtx(&ectx);
+    EXPECT_EQ(Value(10), qECtx(nullptr).getVar("v1"));
+    EXPECT_EQ(Value("Hello world"), qECtx(nullptr).getVar("v2"));
 
-    qctx.setValue("v1", "Hello world");
-    qctx.setValue("v1", 3.14);
-    qctx.setValue("v1", true);
-    EXPECT_EQ(Value(true), ectx.getVersionedVar("v1", 0));
-    EXPECT_EQ(Value(3.14), ectx.getVersionedVar("v1", -1));
-    EXPECT_EQ(Value(10), ectx.getVersionedVar("v1", 1));
+    ectx.setValue("v1", "Hello world");
+    ectx.setValue("v1", 3.14);
+    ectx.setValue("v1", true);
+    EXPECT_EQ(Value(true), qECtx(nullptr).getVersionedVar("v1", 0));
+    EXPECT_EQ(Value(3.14), qECtx(nullptr).getVersionedVar("v1", -1));
+    EXPECT_EQ(Value(10), qECtx(nullptr).getVersionedVar("v1", 1));
 }
 }  // namespace graph
 }  // namespace nebula
diff --git a/src/executor/logic/LoopExecutor.cpp b/src/executor/logic/LoopExecutor.cpp
index 3d8bdb480274df255de0372e7301e4aedb054f8f..1a9ba532f450976deb987edb651904821caab681 100644
--- a/src/executor/logic/LoopExecutor.cpp
+++ b/src/executor/logic/LoopExecutor.cpp
@@ -27,7 +27,7 @@ folly::Future<Status> LoopExecutor::execute() {
 
     auto *loopNode = asNode<Loop>(node());
     Expression *expr = loopNode->condition();
-    QueryExpressionContext ctx(ectx_, nullptr);
+    QueryExpressionContext ctx(ectx_);
     auto value = expr->eval(ctx);
     VLOG(1) << "Loop condition: " << value;
     DCHECK(value.isBool());
diff --git a/src/executor/logic/SelectExecutor.cpp b/src/executor/logic/SelectExecutor.cpp
index 522f06130e29f9514f42049ed79949cc7ef8392f..9a3f92887d82d94cd8f7c71b3d62e02bea256191 100644
--- a/src/executor/logic/SelectExecutor.cpp
+++ b/src/executor/logic/SelectExecutor.cpp
@@ -27,7 +27,7 @@ folly::Future<Status> SelectExecutor::execute() {
 
     auto* select = asNode<Select>(node());
     auto* expr = select->condition();
-    QueryExpressionContext ctx(ectx_, nullptr);
+    QueryExpressionContext ctx(ectx_);
     auto value = expr->eval(ctx);
     DCHECK(value.isBool());
     return finish(ResultBuilder().value(std::move(value)).iter(Iterator::Kind::kDefault).finish());
diff --git a/src/executor/mutate/DeleteExecutor.cpp b/src/executor/mutate/DeleteExecutor.cpp
index 510c43ba1499d4725cdc4dc3c04eaaf46612011d..9c10bf435f34ed0f128f5c95367b9afc07e7eba1 100644
--- a/src/executor/mutate/DeleteExecutor.cpp
+++ b/src/executor/mutate/DeleteExecutor.cpp
@@ -38,9 +38,9 @@ folly::Future<Status> DeleteVerticesExecutor::deleteVertices() {
         auto& inputResult = ectx_->getResult(inputVar);
         auto iter = inputResult.iter();
         vertices.reserve(iter->size());
-        QueryExpressionContext ctx(ectx_, iter.get());
+        QueryExpressionContext ctx(ectx_);
         for (; iter->valid(); iter->next()) {
-            auto val = Expression::eval(vidRef, ctx);
+            auto val = Expression::eval(vidRef, ctx(iter.get()));
             if (val.isNull() || val.empty()) {
                 VLOG(3) << "NULL or EMPTY vid";
                 continue;
@@ -90,11 +90,11 @@ folly::Future<Status> DeleteEdgesExecutor::deleteEdges() {
             return Status::OK();
         }
         edgeKeys.reserve(iter->size());
-        QueryExpressionContext ctx(ectx_, iter.get());
+        QueryExpressionContext ctx(ectx_);
         for (; iter->valid(); iter->next()) {
             for (auto &edgeKeyRef : edgeKeyRefs) {
                 storage::cpp2::EdgeKey edgeKey;
-                auto srcId = Expression::eval(edgeKeyRef->srcid(), ctx);
+                auto srcId = Expression::eval(edgeKeyRef->srcid(), ctx(iter.get()));
                 if (srcId.isNull() || srcId.empty()) {
                     VLOG(3) << "NULL or EMPTY vid";
                     continue;
@@ -105,14 +105,14 @@ folly::Future<Status> DeleteEdgesExecutor::deleteEdges() {
                        << "`, value `" << srcId.toString() << "'";
                     return Status::Error(ss.str());
                 }
-                auto dstId = Expression::eval(edgeKeyRef->dstid(), ctx);
+                auto dstId = Expression::eval(edgeKeyRef->dstid(), ctx(iter.get()));
                 if (!dstId.isStr()) {
                     std::stringstream ss;
                     ss << "Wrong dstId type `" << dstId.type()
                        << "', value `" << dstId.toString() << "'";
                     return Status::Error(ss.str());
                 }
-                auto rank = Expression::eval(edgeKeyRef->rank(), ctx);
+                auto rank = Expression::eval(edgeKeyRef->rank(), ctx(iter.get()));
                 if (!rank.isInt()) {
                     std::stringstream ss;
                     ss << "Wrong rank type `" << rank.type()
@@ -120,7 +120,7 @@ folly::Future<Status> DeleteEdgesExecutor::deleteEdges() {
                     return Status::Error(ss.str());
                 }
                 DCHECK(edgeKeyRef->type());
-                auto type = Expression::eval(edgeKeyRef->type(), ctx);
+                auto type = Expression::eval(edgeKeyRef->type(), ctx(iter.get()));
                 if (!type.isInt()) {
                     std::stringstream ss;
                     ss << "Wrong edge type `" << type.type()
diff --git a/src/executor/query/AggregateExecutor.cpp b/src/executor/query/AggregateExecutor.cpp
index 201ab01976ffcd67e5a89d9f1d3e3c91b1ce07ee..d1e8316e0990f0f2c65b6a8ebce7caf37a32d3e9 100644
--- a/src/executor/query/AggregateExecutor.cpp
+++ b/src/executor/query/AggregateExecutor.cpp
@@ -24,14 +24,13 @@ folly::Future<Status> AggregateExecutor::execute() {
     auto groupItems = agg->groupItems();
     auto iter = ectx_->getResult(agg->inputVar()).iter();
     DCHECK(!!iter);
-    QueryExpressionContext ctx(ectx_, iter.get());
+    QueryExpressionContext ctx(ectx_);
 
     std::unordered_map<List, std::vector<std::unique_ptr<AggFun>>> result;
     for (; iter->valid(); iter->next()) {
         List list;
         for (auto& key : groupKeys) {
-            ctx.setIter(iter.get());
-            list.values.emplace_back(key->eval(ctx));
+            list.values.emplace_back(key->eval(ctx(iter.get())));
         }
 
         auto it = result.find(list);
@@ -39,7 +38,7 @@ folly::Future<Status> AggregateExecutor::execute() {
             std::vector<std::unique_ptr<AggFun>> funs;
             for (auto& item : groupItems) {
                 auto fun = AggFun::aggFunMap_[item.func](item.distinct);
-                auto& v = item.expr->eval(ctx);
+                auto& v = item.expr->eval(ctx(iter.get()));
                 fun->apply(v);
                 funs.emplace_back(std::move(fun));
             }
@@ -47,7 +46,7 @@ folly::Future<Status> AggregateExecutor::execute() {
         } else {
             DCHECK_EQ(it->second.size(), groupItems.size());
             for (size_t i = 0; i < groupItems.size(); ++i) {
-                auto& v = groupItems[i].expr->eval(ctx);
+                auto& v = groupItems[i].expr->eval(ctx(iter.get()));
                 it->second[i]->apply(v);
             }
         }
diff --git a/src/executor/query/DataJoinExecutor.cpp b/src/executor/query/DataJoinExecutor.cpp
index 6b68342c205843d3377251a19f368bc8bd022556..873211c277c94062949d5fd5b536109f06543e5f 100644
--- a/src/executor/query/DataJoinExecutor.cpp
+++ b/src/executor/query/DataJoinExecutor.cpp
@@ -73,12 +73,12 @@ folly::Future<Status> DataJoinExecutor::doInnerJoin() {
 
 void DataJoinExecutor::buildHashTable(const std::vector<Expression*>& hashKeys,
                                       Iterator* iter) {
-    QueryExpressionContext ctx(ectx_, iter);
+    QueryExpressionContext ctx(ectx_);
     for (; iter->valid(); iter->next()) {
         List list;
         list.values.reserve(hashKeys.size());
         for (auto& col : hashKeys) {
-            Value val = col->eval(ctx);
+            Value val = col->eval(ctx(iter));
             list.values.emplace_back(std::move(val));
         }
 
@@ -89,12 +89,12 @@ void DataJoinExecutor::buildHashTable(const std::vector<Expression*>& hashKeys,
 
 void DataJoinExecutor::probe(const std::vector<Expression*>& probeKeys,
                              Iterator* probeIter, JoinIter* resultIter) {
-    QueryExpressionContext ctx(ectx_, probeIter);
+    QueryExpressionContext ctx(ectx_);
     for (; probeIter->valid(); probeIter->next()) {
         List list;
         list.values.reserve(probeKeys.size());
         for (auto& col : probeKeys) {
-            Value val = col->eval(ctx);
+            Value val = col->eval(ctx(probeIter));
             list.values.emplace_back(std::move(val));
         }
 
diff --git a/src/executor/query/DedupExecutor.cpp b/src/executor/query/DedupExecutor.cpp
index 5251b65e68abfc8f71e4a3b208e644598aeb080b..9952b8357d634deddfb244a7372fdf09b8ecc402 100644
--- a/src/executor/query/DedupExecutor.cpp
+++ b/src/executor/query/DedupExecutor.cpp
@@ -28,7 +28,6 @@ folly::Future<Status> DedupExecutor::execute() {
     }
     ResultBuilder builder;
     builder.value(iter->valuePtr());
-    QueryExpressionContext ctx(ectx_, iter.get());
     std::unordered_set<const LogicalRow*> unique;
     while (iter->valid()) {
         if (unique.find(iter->row()) != unique.end()) {
diff --git a/src/executor/query/FilterExecutor.cpp b/src/executor/query/FilterExecutor.cpp
index 8ed9280fbfa5a9a2b8bfe01de769fc26e067ea9c..dfe78a6f19a773f51db557d7126fe23f0ac056de 100644
--- a/src/executor/query/FilterExecutor.cpp
+++ b/src/executor/query/FilterExecutor.cpp
@@ -25,10 +25,10 @@ folly::Future<Status> FilterExecutor::execute() {
     }
     ResultBuilder builder;
     builder.value(iter->valuePtr());
-    QueryExpressionContext ctx(ectx_, iter.get());
+    QueryExpressionContext ctx(ectx_);
     auto condition = filter->condition();
     while (iter->valid()) {
-        auto val = condition->eval(ctx);
+        auto val = condition->eval(ctx(iter.get()));
         if (!val.isBool() && !val.isNull()) {
             return Status::Error("Internal Error: Wrong type result, "
                                  "should be NULL type or BOOL type");
diff --git a/src/executor/query/GetEdgesExecutor.cpp b/src/executor/query/GetEdgesExecutor.cpp
index 922ba93a55f2809d74a8acdd6404c6e5a4440cad..a8000c5cd653b35a1951e1497a71f8d64852426f 100644
--- a/src/executor/query/GetEdgesExecutor.cpp
+++ b/src/executor/query/GetEdgesExecutor.cpp
@@ -33,12 +33,12 @@ folly::Future<Status> GetEdgesExecutor::getEdges() {
         ge->dst() != nullptr) {
         // Accept Table such as | $a | $b | $c | $d |... which indicate src, ranking or dst
         auto valueIter = ectx_->getResult(ge->inputVar()).iter();
-        auto expCtx = QueryExpressionContext(qctx()->ectx(), valueIter.get());
+        auto expCtx = QueryExpressionContext(qctx()->ectx());
         for (; valueIter->valid(); valueIter->next()) {
-            auto src = ge->src()->eval(expCtx);
-            auto type = ge->type()->eval(expCtx);
-            auto ranking = ge->ranking()->eval(expCtx);
-            auto dst = ge->dst()->eval(expCtx);
+            auto src = ge->src()->eval(expCtx(valueIter.get()));
+            auto type = ge->type()->eval(expCtx(valueIter.get()));
+            auto ranking = ge->ranking()->eval(expCtx(valueIter.get()));
+            auto dst = ge->dst()->eval(expCtx(valueIter.get()));
             if (!src.isStr() || !type.isInt() || !ranking.isInt() || !dst.isStr()) {
                 LOG(WARNING) << "Mismatched edge key type";
                 continue;
diff --git a/src/executor/query/GetNeighborsExecutor.cpp b/src/executor/query/GetNeighborsExecutor.cpp
index f1e595a4dd24a765f9c2a9982db1243eea89b137..e1082e5d6b0bed9e5c688c4c458dd2841cf3bdc0 100644
--- a/src/executor/query/GetNeighborsExecutor.cpp
+++ b/src/executor/query/GetNeighborsExecutor.cpp
@@ -41,14 +41,14 @@ Status GetNeighborsExecutor::buildRequestDataSet() {
     VLOG(1) << node()->varName() << " : " << inputVar;
     auto& inputResult = ectx_->getResult(inputVar);
     auto iter = inputResult.iter();
-    QueryExpressionContext ctx(ectx_, iter.get());
+    QueryExpressionContext ctx(ectx_);
     DataSet input;
     reqDs_.colNames = {kVid};
     reqDs_.rows.reserve(iter->size());
     auto* src = gn_->src();
     std::unordered_set<Value> uniqueVid;
     for (; iter->valid(); iter->next()) {
-        auto val = Expression::eval(src, ctx);
+        auto val = Expression::eval(src, ctx(iter.get()));
         if (!val.isStr()) {
             continue;
         }
diff --git a/src/executor/query/GetVerticesExecutor.cpp b/src/executor/query/GetVerticesExecutor.cpp
index 5469d5f81617b58e36dec0759e53761266894fa7..89ef0a3192b0d830de64ea53e22fcf08ca6ac9bd 100644
--- a/src/executor/query/GetVerticesExecutor.cpp
+++ b/src/executor/query/GetVerticesExecutor.cpp
@@ -31,9 +31,9 @@ folly::Future<Status> GetVerticesExecutor::getVertices() {
         // Accept Table such as | $a | $b | $c |... as input which one column indicate src
         auto valueIter = ectx_->getResult(gv->inputVar()).iter();
         VLOG(1) << "GV input var: " << gv->inputVar() << " iter kind: " << valueIter->kind();
-        auto expCtx = QueryExpressionContext(qctx()->ectx(), valueIter.get());
+        auto expCtx = QueryExpressionContext(qctx()->ectx());
         for (; valueIter->valid(); valueIter->next()) {
-            auto src = gv->src()->eval(expCtx);
+            auto src = gv->src()->eval(expCtx(valueIter.get()));
             VLOG(1) << "src vid: " << src;
             if (!src.isStr()) {
                 LOG(WARNING) << "Mismatched vid type: " << src.type();
diff --git a/src/executor/query/LimitExecutor.cpp b/src/executor/query/LimitExecutor.cpp
index 880523d3949e84b469d9aee4d43e1d78b8535a1a..04979b2a3ddcbeaec6a3262882338dfca6795bc8 100644
--- a/src/executor/query/LimitExecutor.cpp
+++ b/src/executor/query/LimitExecutor.cpp
@@ -5,7 +5,6 @@
  */
 
 #include "executor/query/LimitExecutor.h"
-#include "context/QueryExpressionContext.h"
 #include "planner/Query.h"
 #include "util/ScopedTimer.h"
 
@@ -19,7 +18,6 @@ folly::Future<Status> LimitExecutor::execute() {
     auto iter = ectx_->getResult(limit->inputVar()).iter();
     ResultBuilder builder;
     builder.value(iter->valuePtr());
-    QueryExpressionContext ctx(ectx_, iter.get());
     auto offset = limit->offset();
     auto count = limit->count();
     auto size = iter->size();
diff --git a/src/executor/query/ProjectExecutor.cpp b/src/executor/query/ProjectExecutor.cpp
index 2cb872d3c92b8f9144204e7c155cad28644bce1a..f68709adfbb34098dc60a7b5b73920579898926f 100644
--- a/src/executor/query/ProjectExecutor.cpp
+++ b/src/executor/query/ProjectExecutor.cpp
@@ -20,7 +20,7 @@ folly::Future<Status> ProjectExecutor::execute() {
     auto columns = project->columns()->columns();
     auto iter = ectx_->getResult(project->inputVar()).iter();
     DCHECK(!!iter);
-    QueryExpressionContext ctx(ectx_, iter.get());
+    QueryExpressionContext ctx(ectx_);
 
     VLOG(1) << "input: " << project->inputVar();
     DataSet ds;
@@ -28,7 +28,7 @@ folly::Future<Status> ProjectExecutor::execute() {
     for (; iter->valid(); iter->next()) {
         Row row;
         for (auto& col : columns) {
-            Value val = col->expr()->eval(ctx);
+            Value val = col->expr()->eval(ctx(iter.get()));
             row.values.emplace_back(std::move(val));
         }
         ds.rows.emplace_back(std::move(row));
diff --git a/src/executor/query/SortExecutor.cpp b/src/executor/query/SortExecutor.cpp
index bb58abf10401f133675574cf28fcdcf538407aa5..9fabe9855a37be8cfb991cb10def2738b654152f 100644
--- a/src/executor/query/SortExecutor.cpp
+++ b/src/executor/query/SortExecutor.cpp
@@ -5,7 +5,6 @@
  */
 
 #include "executor/query/SortExecutor.h"
-#include "context/QueryExpressionContext.h"
 #include "planner/Query.h"
 #include "util/ScopedTimer.h"
 
diff --git a/src/parser/MaintainSentences.h b/src/parser/MaintainSentences.h
index b84ea115f87fcc1256c68c52ea6fd06f0b74d4d0..c42d5a6a4172bb52e9502de027414f3c004aeceb 100644
--- a/src/parser/MaintainSentences.h
+++ b/src/parser/MaintainSentences.h
@@ -53,7 +53,7 @@ public:
     }
 
     Value getDefaultValue() const {
-        graph::QueryExpressionContext ctx(nullptr, nullptr);
+        graph::QueryExpressionContext ctx(nullptr);
         return defaultValue_->eval(ctx);
     }
 
diff --git a/src/util/SchemaUtil.cpp b/src/util/SchemaUtil.cpp
index 768da9044378bb54afa462e3c96c6694f36304af..7099f4d9888a4cd00c27185837f87dbbc79057b3 100644
--- a/src/util/SchemaUtil.cpp
+++ b/src/util/SchemaUtil.cpp
@@ -188,8 +188,8 @@ Status SchemaUtil::setTTLCol(SchemaPropItem* schemaProp, meta::cpp2::Schema& sch
 
 // static
 StatusOr<VertexID> SchemaUtil::toVertexID(Expression *expr) {
-    QueryExpressionContext ctx(nullptr, nullptr);
-    auto vertexId = expr->eval(ctx);
+    QueryExpressionContext ctx;
+    auto vertexId = expr->eval(ctx(nullptr));
     if (vertexId.type() != Value::Type::STRING) {
         LOG(ERROR) << "Wrong vertex id type";
         return Status::Error("Wrong vertex id type");
@@ -202,9 +202,9 @@ StatusOr<std::vector<Value>>
 SchemaUtil::toValueVec(std::vector<Expression*> exprs) {
     std::vector<Value> values;
     values.reserve(exprs.size());
-    QueryExpressionContext ctx(nullptr, nullptr);
+    QueryExpressionContext ctx;
     for (auto *expr : exprs) {
-        auto value = expr->eval(ctx);
+        auto value = expr->eval(ctx(nullptr));
          if (value.isNull() && value.getNull() != NullType::__NULL__) {
             LOG(ERROR) << "Wrong value type: " << value.type();;
             return Status::Error("Wrong value type");
diff --git a/src/validator/AdminValidator.cpp b/src/validator/AdminValidator.cpp
index e9b02a84e117017aa67ec9ceeb7f26f45bee3787..aeb6ca8b96993a09315a45826249a439fcc01832 100644
--- a/src/validator/AdminValidator.cpp
+++ b/src/validator/AdminValidator.cpp
@@ -277,7 +277,7 @@ Status SetConfigValidator::validateImpl() {
     name_ = *item->getName();
     module_ = item->getModule();
     auto updateItems = item->getUpdateItems();
-    QueryExpressionContext ctx(nullptr, nullptr);
+    QueryExpressionContext ctx;
     if (updateItems == nullptr) {
         module_ = item->getModule();
         if (item->getName() != nullptr) {
@@ -285,7 +285,7 @@ Status SetConfigValidator::validateImpl() {
         }
 
         if (item->getValue() != nullptr) {
-            value_ = Expression::eval(item->getValue(), ctx);
+            value_ = Expression::eval(item->getValue(), ctx(nullptr));
         }
     } else {
         Map configs;
@@ -297,7 +297,7 @@ Status SetConfigValidator::validateImpl() {
             }
             name = *updateItem->getFieldName();
 
-            value = Expression::eval(const_cast<Expression*>(updateItem->value()), ctx);
+            value = Expression::eval(const_cast<Expression*>(updateItem->value()), ctx(nullptr));
 
             if (value.isNull() || (!value.isNumeric() && !value.isStr() && !value.isBool())) {
                 return Status::Error("Wrong value: %s", name.c_str());
diff --git a/src/validator/TraversalValidator.cpp b/src/validator/TraversalValidator.cpp
index 042faaa74f3bdfe2845a41332c5c12060ff1aafc..f2597e592e2b8184edd851a648890c2be58b8bc6 100644
--- a/src/validator/TraversalValidator.cpp
+++ b/src/validator/TraversalValidator.cpp
@@ -74,13 +74,13 @@ Status TraversalValidator::validateFrom(const FromClause* from) {
         }
     } else {
         auto vidList = from->vidList();
-        QueryExpressionContext ctx(qctx_->ectx(), nullptr);
+        QueryExpressionContext ctx;
         for (auto* expr : vidList) {
             if (!evaluableExpr(expr)) {
                 return Status::Error("`%s' is not an evaluable expression.",
                         expr->toString().c_str());
             }
-            auto vid = expr->eval(ctx);
+            auto vid = expr->eval(ctx(nullptr));
             if (!vid.isStr()) {
                 return Status::Error("Vid should be a string.");
             }
diff --git a/src/validator/Validator.cpp b/src/validator/Validator.cpp
index 3122c28980d0158e42287e976a407e2ca1727f8a..b8f40e4e8a93316386bc01c5f13692a8aa94542a 100644
--- a/src/validator/Validator.cpp
+++ b/src/validator/Validator.cpp
@@ -452,9 +452,9 @@ StatusOr<Value::Type> Validator::deduceExprType(const Expression* expr) const {
                     << castExpr->type();
                 return Status::Error(out.str());
             }
-            QueryExpressionContext ctx(nullptr, nullptr);
+            QueryExpressionContext ctx;
             auto* typeCastExpr = const_cast<TypeCastingExpression*>(castExpr);
-            auto val = typeCastExpr->eval(ctx);
+            auto val = typeCastExpr->eval(ctx(nullptr));
             if (val.isNull()) {
                 return Status::SemanticError("`%s` is not a valid expression ",
                                              expr->toString().c_str());
@@ -540,9 +540,9 @@ StatusOr<Value::Type> Validator::deduceExprType(const Expression* expr) const {
             return Status::SemanticError("LabelExpression can not be instantiated.");
         }
         case Expression::Kind::kConstant: {
-            QueryExpressionContext ctx(nullptr, nullptr);
+            QueryExpressionContext ctx;
             auto* mutableExpr = const_cast<Expression*>(expr);
-            return mutableExpr->eval(ctx).type();
+            return mutableExpr->eval(ctx(nullptr)).type();
         }
         case Expression::Kind::kEdgeSrc: {
             return Value::Type::STRING;