You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by dl...@apache.org on 2019/04/12 02:57:17 UTC

[asterixdb] branch master updated: [ASTERIXDB-2539][COMP] Exclude LET variables from "Single Variable Resolution" rule

This is an automated email from the ASF dual-hosted git repository.

dlych pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 393215e  [ASTERIXDB-2539][COMP] Exclude LET variables from "Single Variable Resolution" rule
393215e is described below

commit 393215edef5f0482ed92c932790c87015202cb44
Author: Dmitry Lychagin <dm...@couchbase.com>
AuthorDate: Thu Apr 11 10:26:56 2019 -0700

    [ASTERIXDB-2539][COMP] Exclude LET variables from "Single Variable Resolution" rule
    
    - user model changes: yes
    - storage format changes: no
    - interface changes: no
    
    Details:
    - Variables introduced by LET clauses should not be
      considered by "Single Variable Resolution" rule
    - In INSERT/UPSERT statements with RETURNING expression
      the automatically introduced variable should be named
      as the target dataset
    - Refactor VariableCheckAndRewriteVisitor and
      other code related to name resolution
    - Added testcases and updated documentation
    
    Change-Id: I9b9f70a1671378f5216ec4e30416d4d67c3df089
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/3322
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Till Westmann <ti...@apache.org>
---
 .../resources/parserts/queries_sqlpp/LetFor.sqlpp  |   2 +-
 .../parserts/queries_sqlpp/functionDecl1.sqlpp     |   2 +-
 .../parserts/queries_sqlpp/nestedFLWOGR.sqlpp      |   2 +-
 .../parserts/results_parser_sqlpp/LetFor.ast       |  13 ++-
 .../results_parser_sqlpp/functionDecl1.ast         |  13 ++-
 .../parserts/results_parser_sqlpp/nestedFLWOGR.ast |  13 ++-
 .../cross-dv15/cross-dv15.1.ddl.sqlpp              |   2 +-
 ...ert-returning-fieldname-implicit-2.1.ddl.sqlpp} |  11 +-
 ...t-returning-fieldname-implicit-2.3.query.sqlpp} |   0
 ...sert-returning-fieldname-implicit.3.query.sqlpp |   2 +-
 ...ert-returning-fieldname-implicit-2.1.ddl.sqlpp} |   5 +-
 ...t-returning-fieldname-implicit-2.3.query.sqlpp} |   9 +-
 ...psert-returning-fieldname-implicit.1.ddl.sqlpp} |   5 +-
 ...ert-returning-fieldname-implicit.3.query.sqlpp} |   9 +-
 .../upsert-returning-fieldname.1.ddl.sqlpp}        |   5 +-
 .../upsert-returning-fieldname.3.query.sqlpp}      |   5 +-
 .../field_accessor_1/field_accessor_1.1.ddl.sqlpp} |  17 ++-
 .../field_accessor_1.2.update.sqlpp}               |  10 +-
 .../field_accessor_1.3.query.sqlpp}                |  13 ++-
 .../field_accessor_1.4.query.sqlpp}                |  14 ++-
 .../field_accessor_1.5.query.sqlpp}                |  13 ++-
 .../field_accessor_1.6.query.sqlpp}                |  10 +-
 .../field_accessor_1.7.query.sqlpp}                |  15 ++-
 .../field_accessor_1.8.query.sqlpp}                |  12 ++-
 .../field_accessor_2_negative.1.ddl.sqlpp}         |  17 ++-
 .../field_accessor_2_negative.2.update.sqlpp}      |  24 +++--
 .../field_accessor_2_negative.3.query.sqlpp}       |  12 ++-
 .../field_accessor_2_negative.4.query.sqlpp}       |  12 ++-
 .../field_accessor_2_negative.5.query.sqlpp}       |  12 ++-
 .../field_accessor_2_negative.6.query.sqlpp}       |  12 ++-
 .../field_accessor_2_negative.7.query.sqlpp}       |  12 ++-
 .../field_accessor_2_negative.8.query.sqlpp}       |  11 +-
 .../field_accessor_2_negative.9.query.sqlpp}       |  11 +-
 .../field_accessor_1/field_accessor_1.3.adm        |   1 +
 .../field_accessor_1/field_accessor_1.4.adm        |   1 +
 .../field_accessor_1/field_accessor_1.5.adm        |   1 +
 .../field_accessor_1/field_accessor_1.6.adm        |   1 +
 .../field_accessor_1/field_accessor_1.7.adm        |   1 +
 .../field_accessor_1/field_accessor_1.8.adm        |   1 +
 .../test/resources/runtimets/testsuite_sqlpp.xml   |  51 +++++++--
 .../main/markdown/sqlpp/appendix_3_resolution.md   |  17 ++-
 .../apache/asterix/lang/common/context/Scope.java  |  96 +++++++++++------
 .../asterix/lang/common/parser/ScopeChecker.java   |  10 +-
 .../lang/common/rewrites/LangRewritingContext.java |  11 --
 .../AbstractSqlppExpressionExtractionVisitor.java  |   1 -
 .../rewrites/visitor/InlineColumnAliasVisitor.java |   2 -
 .../visitor/Sql92AggregateFunctionVisitor.java     |  68 ++++++------
 .../SqlppGroupByAggregationSugarVisitor.java       |  84 ++++++++-------
 .../SqlppWindowAggregationSugarVisitor.java        |  15 ++-
 .../visitor/VariableCheckAndRewriteVisitor.java    |  76 +++++++------
 .../asterix/lang/sqlpp/util/SqlppVariableUtil.java |  10 --
 .../visitor/CheckDatasetOnlyResolutionVisitor.java | 117 ++++++++++++---------
 .../AbstractSqlppExpressionScopingVisitor.java     |  51 ++++++---
 .../base/AbstractSqlppSimpleExpressionVisitor.java |  28 ++---
 .../asterix-lang-sqlpp/src/main/javacc/SQLPP.jj    |  25 +++--
 55 files changed, 589 insertions(+), 404 deletions(-)

diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
index 5c118fa..86120f4 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-with  users as User
+with  users as (from User u select value u)
 select element {'name':user.name}
 from  users as user
 where some i in user.interests satisfies (i = 'movies')
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/functionDecl1.sqlpp b/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/functionDecl1.sqlpp
index 2d1d8af..fdfd94a 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/functionDecl1.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/functionDecl1.sqlpp
@@ -34,6 +34,6 @@ declare function calculate(events) {
     limit 5
 )
 };
-with  result as calculate(Events)
+with  result as calculate((from Events e select value e))
 select element result
 ;
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/nestedFLWOGR.sqlpp b/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/nestedFLWOGR.sqlpp
index c5719ec..f4c3304 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/nestedFLWOGR.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/nestedFLWOGR.sqlpp
@@ -19,7 +19,7 @@
 
 select element {'name':user.name}
 from  (
-    with  data as User
+    with  data as (from User u select value u)
     select element data
 ) as user
 where some i in user.interests satisfies (i = 'movies')
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/LetFor.ast b/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/LetFor.ast
index cf95f08..4623444 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/LetFor.ast
+++ b/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/LetFor.ast
@@ -1,9 +1,16 @@
 Query:
 Let Variable [ Name=$users ]
   :=
-  FunctionCall asterix.dataset@1[
-    LiteralExpr [STRING] [User]
-  ]
+  (
+    SELECT ELEMENT [
+    Variable [ Name=$u ]
+    ]
+    FROM [      FunctionCall asterix.dataset@1[
+        LiteralExpr [STRING] [User]
+      ]
+      AS Variable [ Name=$u ]
+    ]
+  )
 SELECT ELEMENT [
 RecordConstructor [
   (
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/functionDecl1.ast b/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/functionDecl1.ast
index 6c92c37..2443f90 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/functionDecl1.ast
+++ b/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/functionDecl1.ast
@@ -102,9 +102,16 @@ Query:
 Let Variable [ Name=$result ]
   :=
   FunctionCall null.calculate@1[
-    FunctionCall asterix.dataset@1[
-      LiteralExpr [STRING] [Events]
-    ]
+    (
+      SELECT ELEMENT [
+      Variable [ Name=$e ]
+      ]
+      FROM [        FunctionCall asterix.dataset@1[
+          LiteralExpr [STRING] [Events]
+        ]
+        AS Variable [ Name=$e ]
+      ]
+    )
   ]
 SELECT ELEMENT [
 Variable [ Name=$result ]
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/nestedFLWOGR.ast b/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/nestedFLWOGR.ast
index b43814a..aa25b42 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/nestedFLWOGR.ast
+++ b/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/nestedFLWOGR.ast
@@ -14,9 +14,16 @@ RecordConstructor [
 FROM [  (
     Let Variable [ Name=$data ]
       :=
-      FunctionCall asterix.dataset@1[
-        LiteralExpr [STRING] [User]
-      ]
+      (
+        SELECT ELEMENT [
+        Variable [ Name=$u ]
+        ]
+        FROM [          FunctionCall asterix.dataset@1[
+            LiteralExpr [STRING] [User]
+          ]
+          AS Variable [ Name=$u ]
+        ]
+      )
     SELECT ELEMENT [
     Variable [ Name=$data ]
     ]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cross-dataverse/cross-dv15/cross-dv15.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cross-dataverse/cross-dv15/cross-dv15.1.ddl.sqlpp
index 91981df..166bcdf 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cross-dataverse/cross-dv15/cross-dv15.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cross-dataverse/cross-dv15/cross-dv15.1.ddl.sqlpp
@@ -33,7 +33,7 @@ create function testdv1.fun01(){
 
 // UDF with one input
 create function testdv1.fun02(a){
-`function 02`
+a.`function 02`
 };
 
 // UDF with two inputs
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit-2/insert-returning-fieldname-implicit-2.1.ddl.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit-2/insert-returning-fieldname-implicit-2.1.ddl.sqlpp
index a41976b..ff45c01 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit-2/insert-returning-fieldname-implicit-2.1.ddl.sqlpp
@@ -23,12 +23,15 @@
  * Date            : Mar 2015
  */
 
+
 drop dataverse test if exists;
 create dataverse test;
 use test;
 
-create type sub as
-{ subscriptionId: uuid }
-;
+create type TweetMessageTypeuuid as closed {
+  tweetid: uuid,
+  `message-text`: string
+};
 
-create dataset subscriptions(sub) primary key subscriptionId;
\ No newline at end of file
+create dataset TweetMessageuuids(TweetMessageTypeuuid)
+primary key tweetid autogenerated;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit-2/insert-returning-fieldname-implicit-2.3.query.sqlpp
similarity index 100%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit-2/insert-returning-fieldname-implicit-2.3.query.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp
index c8d14e9..fa50da0 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp
@@ -27,4 +27,4 @@ use test;
 
 insert into TweetMessageuuids (
      { "message-text":"hello"}
-) returning `message-text`;
\ No newline at end of file
+) returning TweetMessageuuids.`message-text`;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit-2/upsert-returning-fieldname-implicit-2.1.ddl.sqlpp
similarity index 83%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit-2/upsert-returning-fieldname-implicit-2.1.ddl.sqlpp
index a41976b..e4f8d09 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit-2/upsert-returning-fieldname-implicit-2.1.ddl.sqlpp
@@ -17,10 +17,9 @@
  * under the License.
  */
 /*
- * Test case Name  : insert-returning-fieldname
- * Description     : Check fields returned on insert
+ * Test case Name  : upsert-returning-fieldname-implicit
+ * Description     : Check fields returned on upsert
  * Expected Result : Success
- * Date            : Mar 2015
  */
 
 drop dataverse test if exists;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit-2/upsert-returning-fieldname-implicit-2.3.query.sqlpp
similarity index 82%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit-2/upsert-returning-fieldname-implicit-2.3.query.sqlpp
index dad3a82..ba73bd7 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit-2/upsert-returning-fieldname-implicit-2.3.query.sqlpp
@@ -17,14 +17,13 @@
  * under the License.
  */
 /*
- * Test case Name  : insert-returning-fieldname
- * Description     : Check fields returned on insert
+ * Test case Name  : upsert-returning-fieldname
+ * Description     : Check fields returned on upsert
  * Expected Result : Success
- * Date            : Mar 2015
  */
 
 use test;
 
-upsert into subscriptions as record(
+upsert into subscriptions (
 [{"subscriptionId":create_uuid(), "word": "hello"}]
-) returning record.word;
\ No newline at end of file
+) returning word;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit/upsert-returning-fieldname-implicit.1.ddl.sqlpp
similarity index 83%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit/upsert-returning-fieldname-implicit.1.ddl.sqlpp
index a41976b..e4f8d09 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit/upsert-returning-fieldname-implicit.1.ddl.sqlpp
@@ -17,10 +17,9 @@
  * under the License.
  */
 /*
- * Test case Name  : insert-returning-fieldname
- * Description     : Check fields returned on insert
+ * Test case Name  : upsert-returning-fieldname-implicit
+ * Description     : Check fields returned on upsert
  * Expected Result : Success
- * Date            : Mar 2015
  */
 
 drop dataverse test if exists;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit/upsert-returning-fieldname-implicit.3.query.sqlpp
similarity index 82%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit/upsert-returning-fieldname-implicit.3.query.sqlpp
index dad3a82..420ff66 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname-implicit/upsert-returning-fieldname-implicit.3.query.sqlpp
@@ -17,14 +17,13 @@
  * under the License.
  */
 /*
- * Test case Name  : insert-returning-fieldname
- * Description     : Check fields returned on insert
+ * Test case Name  : upsert-returning-fieldname
+ * Description     : Check fields returned on upsert
  * Expected Result : Success
- * Date            : Mar 2015
  */
 
 use test;
 
-upsert into subscriptions as record(
+upsert into subscriptions (
 [{"subscriptionId":create_uuid(), "word": "hello"}]
-) returning record.word;
\ No newline at end of file
+) returning subscriptions.word;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname/upsert-returning-fieldname.1.ddl.sqlpp
similarity index 83%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname/upsert-returning-fieldname.1.ddl.sqlpp
index a41976b..95476c4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname/upsert-returning-fieldname.1.ddl.sqlpp
@@ -17,10 +17,9 @@
  * under the License.
  */
 /*
- * Test case Name  : insert-returning-fieldname
- * Description     : Check fields returned on insert
+ * Test case Name  : upsert-returning-fieldname
+ * Description     : Check fields returned on upsert
  * Expected Result : Success
- * Date            : Mar 2015
  */
 
 drop dataverse test if exists;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname/upsert-returning-fieldname.3.query.sqlpp
similarity index 85%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname/upsert-returning-fieldname.3.query.sqlpp
index dad3a82..b715d75 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-qualified/insert-returning-fieldname-qualified.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/upsert-returning-fieldname/upsert-returning-fieldname.3.query.sqlpp
@@ -17,10 +17,9 @@
  * under the License.
  */
 /*
- * Test case Name  : insert-returning-fieldname
- * Description     : Check fields returned on insert
+ * Test case Name  : upsert-returning-fieldname
+ * Description     : Check fields returned on upsert
  * Expected Result : Success
- * Date            : Mar 2015
  */
 
 use test;
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.1.ddl.sqlpp
similarity index 77%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.1.ddl.sqlpp
index 5c118fa..02c9795 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.1.ddl.sqlpp
@@ -17,8 +17,15 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop dataset samptable if exists;
+drop type samptabletype if exists;
+
+create type samptabletype as {
+  id: tinyint
+};
+
+create dataset samptable(samptabletype) primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.2.update.sqlpp
similarity index 77%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.2.update.sqlpp
index 5c118fa..7880a4e 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.2.update.sqlpp
@@ -17,8 +17,8 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+use test;
+
+insert into samptable ({'id' : 1, 'c1': 1, 'c2': 'a', 'c3': [ { 'c10': 10 }, { 'c10': 20 }, { 'c10': 30 } ] });
+
+insert into samptable ({'id' : 2, 'c1': 2, 'c2': 'b', 'c3': [ { 'c10': 40 }, { 'c10': 50 }, { 'c10': 60 } ] });
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.3.query.sqlpp
similarity index 80%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.3.query.sqlpp
index 5c118fa..cd3759a 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.3.query.sqlpp
@@ -17,8 +17,11 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Test that non-qualified identifier resolution ignores variables introduced by LET clauses */
+
+use test;
+
+from samptable
+let c_c1 = c1, c_c1_1 = c1 + 1
+where c2 > 'a'
+select id, c_c1, c_c1_1, c2
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.4.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.4.query.sqlpp
index 5c118fa..c5fd553 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.4.query.sqlpp
@@ -17,8 +17,12 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Test that non-qualified identifier resolution ignores
+   positional variable in FROM clause */
+
+use test;
+
+from ( from samptable s select s.* order by s.id ) s2 at i
+let c_c1 = c1
+where c2 > 'a'
+select id, i, c_c1, c2
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.5.query.sqlpp
similarity index 80%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.5.query.sqlpp
index 5c118fa..9fe805a 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.5.query.sqlpp
@@ -17,8 +17,11 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Test non-qualified identifier resolution inside quantified expression with a
+   single quantified variable */
+
+use test;
+
+from samptable s
+where some x in s.c3 satisfies c10 > 50
+select id, c3
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.6.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.6.query.sqlpp
index 5c118fa..450869d 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.6.query.sqlpp
@@ -17,8 +17,8 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Resolve to a dataset if used in a top-level expression */
+
+use test;
+
+array_count(samptable)
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.7.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.7.query.sqlpp
index 5c118fa..c7d7ec4 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.7.query.sqlpp
@@ -17,8 +17,13 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Resolve to a dataset if used in a top-level expression,
+   do not resolve to a statement parameter */
+
+// requesttype=application/json
+
+// param $p_obj:json={"samptable":[1,2,3,4,5,6,7,8]}
+
+use test;
+
+array_count(samptable)
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.8.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.8.query.sqlpp
index 5c118fa..0c30894 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_1/field_accessor_1.8.query.sqlpp
@@ -17,8 +17,10 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Resolve to a dataset if used in a top-level expression */
+
+use test;
+
+{
+  "t1": tostring({ "x": [-array_count(samptable)][0:][0] + 4 }.x)
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.1.ddl.sqlpp
similarity index 77%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.1.ddl.sqlpp
index 5c118fa..02c9795 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.1.ddl.sqlpp
@@ -17,8 +17,15 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop dataset samptable if exists;
+drop type samptabletype if exists;
+
+create type samptabletype as {
+  id: tinyint
+};
+
+create dataset samptable(samptabletype) primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.2.update.sqlpp
similarity index 73%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.2.update.sqlpp
index c8d14e9..8bc3f97 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-returning-fieldname-implicit/insert-returning-fieldname-implicit.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.2.update.sqlpp
@@ -16,15 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/*
- * Test case Name  : insert-returning-fieldname
- * Description     : Check fields returned on insert
- * Expected Result : Success
- * Date            : Mar 2015
- */
 
 use test;
 
-insert into TweetMessageuuids (
-     { "message-text":"hello"}
-) returning `message-text`;
\ No newline at end of file
+insert into samptable ({
+  'id': 1,
+  'c1': 1,
+  'c2': 'a',
+  'c3': [ { 'c10': 10 }, { 'c10': 20 }, { 'c10': 30 } ],
+  'c4': { 'c20': 100 }
+});
+
+insert into samptable ({
+  'id': 2,
+  'c1': 2,
+  'c2': 'b',
+  'c3': [ { 'c10': 40 }, { 'c10': 50 }, { 'c10': 60 } ],
+  'c4': { 'c20': 200 }
+});
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.3.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.3.query.sqlpp
index 5c118fa..1a1a232 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.3.query.sqlpp
@@ -17,8 +17,10 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Ambiguous after JOIN */
+
+use test;
+
+from samptable s join samptable s2 on s.id = s2.id
+where c2 > 'a'
+select s.id s_id, s2.id s2_id
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.4.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.4.query.sqlpp
index 5c118fa..a63f382 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.4.query.sqlpp
@@ -17,8 +17,10 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Ambiguous after multiple FROM terms */
+
+use test;
+
+from samptable s, samptable s2
+where c2 > 'a'
+select s.id s_id, s2.id s2_id
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.5.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.5.query.sqlpp
index 5c118fa..056d6c9 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.5.query.sqlpp
@@ -17,8 +17,10 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Ambiguous after UNNEST */
+
+use test;
+
+from samptable s unnest s.c3 s_c3
+where c2 > 'a'
+select s.id s_id, s_c3.c10
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.6.query.sqlpp
similarity index 84%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.6.query.sqlpp
index 5c118fa..7f0d131 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.6.query.sqlpp
@@ -17,8 +17,10 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Ambiguous after multiple quantified variables */
+
+use test;
+
+from samptable s
+where some x in s.c3, y in range(1, 20) satisfies c10 < y
+select s.id
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.7.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.7.query.sqlpp
index 5c118fa..80aa3ac 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.7.query.sqlpp
@@ -17,8 +17,10 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Cannot do non-qualified resolution after GROUP BY */
+
+use test;
+
+from samptable s
+group by s.c4
+select c20
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.8.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.8.query.sqlpp
index 5c118fa..a19fe28 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.8.query.sqlpp
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* Cannot do non-qualified resolution after implicit GROUP BY ALL */
+
+use test;
+
+from samptable s
+select count(c2), c1
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.9.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.9.query.sqlpp
index 5c118fa..e2d5741 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/LetFor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/resolution/field_accessor_2_negative/field_accessor_2_negative.9.query.sqlpp
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-with  users as User
-select element {'name':user.name}
-from  users as user
-where some i in user.interests satisfies (i = 'movies')
-;
+/* No non-qualified resolution if there is no FROM clause */
+
+use test;
+
+let x = { "a": 1, "samptable": 2, "c": 3 }
+select value samptable
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.3.adm
new file mode 100644
index 0000000..6dec87a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.3.adm
@@ -0,0 +1 @@
+{ "id": 2, "c_c1": 2, "c_c1_1": 3, "c2": "b" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.4.adm
new file mode 100644
index 0000000..95bdf8e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.4.adm
@@ -0,0 +1 @@
+{ "id": 2, "i": 2, "c_c1": 2, "c2": "b" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.5.adm
new file mode 100644
index 0000000..8566517
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.5.adm
@@ -0,0 +1 @@
+{ "id": 2, "c3": [ { "c10": 40 }, { "c10": 50 }, { "c10": 60 } ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.6.adm
new file mode 100644
index 0000000..d8263ee
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.6.adm
@@ -0,0 +1 @@
+2
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.7.adm
new file mode 100644
index 0000000..d8263ee
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.7.adm
@@ -0,0 +1 @@
+2
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.8.adm
new file mode 100644
index 0000000..8f4358e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/resolution/field_accessor_1/field_accessor_1.8.adm
@@ -0,0 +1 @@
+{ "t1": "2" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 07da3f9..74bb8a8 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -3746,24 +3746,23 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="dml">
-      <compilation-unit name="insert-returning-fieldname">
+      <compilation-unit name="insert-returning-udf">
         <output-dir compare="Text">insert-returning-fieldname</output-dir>
       </compilation-unit>
     </test-case>
     <test-case FilePath="dml">
-      <compilation-unit name="insert-returning-udf">
+      <compilation-unit name="insert-returning-fieldname">
         <output-dir compare="Text">insert-returning-fieldname</output-dir>
       </compilation-unit>
     </test-case>
     <test-case FilePath="dml">
-      <compilation-unit name="insert-returning-fieldname-qualified">
+      <compilation-unit name="insert-returning-fieldname-implicit">
         <output-dir compare="Text">insert-returning-fieldname</output-dir>
       </compilation-unit>
     </test-case>
     <test-case FilePath="dml">
-      <compilation-unit name="insert-returning-fieldname-implicit">
+      <compilation-unit name="insert-returning-fieldname-implicit-2">
         <output-dir compare="Text">insert-returning-fieldname</output-dir>
-        <expected-error>Need an alias for the enclosed expression</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="dml">
@@ -4094,6 +4093,21 @@
         <output-dir compare="Text">upsert-return-custom-result</output-dir>
       </compilation-unit>
     </test-case>
+    <test-case FilePath="dml">
+      <compilation-unit name="upsert-returning-fieldname">
+        <output-dir compare="Text">insert-returning-fieldname</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="dml">
+      <compilation-unit name="upsert-returning-fieldname-implicit">
+        <output-dir compare="Text">insert-returning-fieldname</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="dml">
+      <compilation-unit name="upsert-returning-fieldname-implicit-2">
+        <output-dir compare="Text">insert-returning-fieldname</output-dir>
+      </compilation-unit>
+    </test-case>
   </test-group>
   <test-group name="employee">
     <test-case FilePath="employee">
@@ -4640,7 +4654,7 @@
     <test-case FilePath="global-aggregate">
       <compilation-unit name="q05_error">
         <output-dir compare="Text">q01</output-dir>
-        <expected-error>ASX1091: Type mismatch: expected value of type object, but got the value of type array (in line 22, at column 8)</expected-error>
+        <expected-error>ASX1073: Cannot resolve alias reference for undefined identifier u (in line 22, at column 8)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="global-aggregate">
@@ -4775,7 +4789,7 @@
     <test-case FilePath="group-by">
       <compilation-unit name="sugar-02-2">
         <output-dir compare="Text">core-02</output-dir>
-        <expected-error>Cannot resolve ambiguous alias reference for identifier deptId</expected-error>
+        <expected-error>ASX1073: Cannot resolve alias reference for undefined identifier deptId (in line 28, at column 8)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="group-by">
@@ -7140,8 +7154,8 @@
     <test-case FilePath="numeric">
       <compilation-unit name="scientific_error">
         <output-dir compare="Text">none</output-dir>
-        <expected-error>Cannot find dataset e in dataverse Default nor an alias with name e</expected-error>
-        <expected-error>Cannot find dataset e in dataverse Default nor an alias with name e</expected-error>
+        <expected-error>ASX1073: Cannot resolve alias reference for undefined identifier e (in line 24, at column 10)</expected-error>
+        <expected-error>ASX1073: Cannot resolve alias reference for undefined identifier e (in line 24, at column 8)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="numeric">
@@ -7613,6 +7627,23 @@
         <output-dir compare="Text">function_dataverse</output-dir>
       </compilation-unit>
     </test-case>
+    <test-case FilePath="resolution">
+      <compilation-unit name="field_accessor_1">
+        <output-dir compare="Text">field_accessor_1</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="resolution">
+      <compilation-unit name="field_accessor_2_negative">
+        <output-dir compare="Text">field_accessor_1</output-dir>
+        <expected-error>ASX1074: Cannot resolve ambiguous alias reference for identifier c2 (in line 25, at column 7)</expected-error>
+        <expected-error>ASX1074: Cannot resolve ambiguous alias reference for identifier c2 (in line 25, at column 7)</expected-error>
+        <expected-error>ASX1074: Cannot resolve ambiguous alias reference for identifier c2 (in line 25, at column 7)</expected-error>
+        <expected-error>ASX1074: Cannot resolve ambiguous alias reference for identifier c10 (in line 25, at column 51)</expected-error>
+        <expected-error>ASX1073: Cannot resolve alias reference for undefined identifier c20 (in line 26, at column 8)</expected-error>
+        <expected-error>ASX1073: Cannot resolve alias reference for undefined identifier c1 (in line 25, at column 19)</expected-error>
+        <expected-error>ASX1073: Cannot resolve alias reference for undefined identifier samptable (in line 25, at column 14)</expected-error>
+      </compilation-unit>
+    </test-case>
   </test-group>
   <test-group name="scan">
     <test-case FilePath="scan">
@@ -10505,7 +10536,7 @@
     <test-case FilePath="user-defined-functions">
       <compilation-unit name="udf30">
         <output-dir compare="Text">udf30</output-dir>
-        <expected-error>Cannot find dataset y in dataverse Default nor an alias with name y</expected-error>
+        <expected-error>ASX1073: Cannot resolve alias reference for undefined identifier y (in line 30, at column 8)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="user-defined-functions">
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/appendix_3_resolution.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/appendix_3_resolution.md
index c3a6a19..6bde7ce 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/appendix_3_resolution.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/appendix_3_resolution.md
@@ -229,12 +229,14 @@ The rules for resolving the leftmost identifier are:
     1.  If the identifier matches a variable-name that is in scope, it resolves to the binding of that variable.
         (In the case of a correlated subquery, the in-scope variable might have been bound in an outer query block.)
 
-    2.  (The "Single Variable Rule"): Otherwise, if the FROM clause (or a LET clause if there is no FROM clause) in the current query block binds exactly one variable, the identifier is treated as a field access on the object bound to that variable.
+    2.  (The "Single Variable Rule"): Otherwise, if the FROM clause in the current query block binds exactly one variable, the identifier is treated as a field access on the object bound to that variable.
         For example, in the query `FROM customer SELECT address`, the identifier address is treated as a field in the object bound to the variable customer.
         At runtime, if the object bound to customer has no `address` field, the `address` expression will return `missing`.
-        If the FROM clause (and its LET subclause, if any) in the current query block binds multiple variables, name resolution fails with an "ambiguous name" error.
+        If the FROM clause in the current query block binds multiple variables, name resolution fails with an "ambiguous name" error.
+        If there's no FROM clause in the current query block, name resolution fails with an "undefined identifier" error.
         Note that the Single Variable Rule searches for bound variables only in the current query block, not in outer (containing) blocks.
         The purpose of this rule is to permit the compiler to resolve field-references unambiguously without relying on any schema information.
+        Also note that variables defined by LET clauses do not participate in the resolution process performed by this rule.
 
         Exception: In a query that has a GROUP BY clause, the Single Variable Rule does not apply in any clauses that occur after the GROUP BY because, in these clauses, the variables bound by the FROM clause are no longer in scope.
         In clauses after GROUP BY, only Rule 2.1 applies.
@@ -251,6 +253,15 @@ The rules for resolving the leftmost identifier are:
 
     In the result of this query, objects that have a foo field will be ordered by the value of this field; objects that have no foo field will appear at at the beginning of the query result (in ascending order) or at the end (in descending order.)
 
-4.  Once the leftmost identifier has been resolved, the following dots and identifiers in the name (if any) are treated as a path expression that navigates to a field nested inside that object.
+4.  _In a standalone expression_: If a query consists of a standalone expression then identifiers inside that
+    expression are resolved according to Rule 1.
+    For example, if the whole query is `ARRAY_COUNT(a.b)` then `a.b` will be treated as dataset `b` contained in
+    dataverse `a`.
+    Note that this rule only applies to identifiers which are located directly inside a standalone expression.
+    Identifiers inside SELECT statements in a standalone expresion are still resolved according to Rules 1-3.
+    For example, if the whole query is `ARRAY_SUM( (FROM employee AS e SELECT VALUE salary) )` then `salary` is resolved
+    as `e.salary` following the "Single Variable Rule" (Rule 2.2).
+
+5.  Once the leftmost identifier has been resolved, the following dots and identifiers in the name (if any) are treated as a path expression that navigates to a field nested inside that object.
     The name resolves to the field at the end of the path.
     If this field does not exist, the value `missing` is returned.
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/context/Scope.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/context/Scope.java
index fa47f5e..92be7c9 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/context/Scope.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/context/Scope.java
@@ -19,23 +19,28 @@
 package org.apache.asterix.lang.common.context;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
+import java.util.Map;
 import java.util.Set;
-import java.util.function.Predicate;
 
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.lang.common.expression.VariableExpr;
 import org.apache.asterix.lang.common.parser.ScopeChecker;
 import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.commons.collections4.iterators.ReverseListIterator;
+import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.api.exceptions.SourceLocation;
 
 public final class Scope {
     private final ScopeChecker scopeChecker;
     private final Scope parent;
-    private final LinkedHashMap<String, Identifier> symbols;
+    private final LinkedHashMap<String, Pair<Identifier, Set<? extends SymbolAnnotation>>> symbols;
     private final boolean maskParentScope;
     private FunctionSignatures functionSignatures;
 
@@ -60,15 +65,15 @@ public final class Scope {
      * @param name
      * @return the Identifier of this symbol; otherwise null;
      */
-    public Identifier findSymbol(String name) {
-        Identifier ident = symbols.get(name);
-        if (ident == null && !maskParentScope && parent != null) {
-            ident = parent.findSymbol(name);
+    public Pair<Identifier, Set<? extends SymbolAnnotation>> findSymbol(String name) {
+        Pair<Identifier, Set<? extends SymbolAnnotation>> symbol = symbols.get(name);
+        if (symbol == null && !maskParentScope && parent != null) {
+            symbol = parent.findSymbol(name);
         }
-        return ident;
+        return symbol;
     }
 
-    public Identifier findLocalSymbol(String name) {
+    public Pair<Identifier, Set<? extends SymbolAnnotation>> findLocalSymbol(String name) {
         return symbols.get(name);
     }
 
@@ -78,13 +83,24 @@ public final class Scope {
      * @param ident
      */
     public void addSymbolToScope(Identifier ident) {
-        symbols.put(ident.getValue(), ident);
+        addSymbolToScope(ident, null);
+    }
+
+    public void addSymbolToScope(Identifier ident, Set<? extends SymbolAnnotation> annotations) {
+        if (annotations == null) {
+            annotations = Collections.emptySet();
+        }
+        symbols.put(ident.getValue(), new Pair<>(ident, annotations));
     }
 
     public void addNewVarSymbolToScope(VarIdentifier ident) {
+        addNewVarSymbolToScope(ident, null);
+    }
+
+    public void addNewVarSymbolToScope(VarIdentifier ident, Set<? extends SymbolAnnotation> annotations) {
         scopeChecker.incVarCounter();
         ident.setId(scopeChecker.getVarCounter());
-        addSymbolToScope(ident);
+        addSymbolToScope(ident, annotations);
     }
 
     /**
@@ -140,12 +156,13 @@ public final class Scope {
      *
      * @return an iterator of visible symbols.
      */
-    public Iterator<Identifier> liveSymbols(Scope stopAtExclusive) {
-        final Iterator<Identifier> identifierIterator = new ReverseListIterator<>(new ArrayList<>(symbols.values()));
-        final Iterator<Identifier> parentIterator =
+    public Iterator<Pair<Identifier, Set<? extends SymbolAnnotation>>> liveSymbols(Scope stopAtExclusive) {
+        final Iterator<Pair<Identifier, Set<? extends SymbolAnnotation>>> identifierIterator =
+                new ReverseListIterator<>(new ArrayList<>(symbols.values()));
+        final Iterator<Pair<Identifier, Set<? extends SymbolAnnotation>>> parentIterator =
                 parent == null || parent == stopAtExclusive ? null : parent.liveSymbols(stopAtExclusive);
-        return new Iterator<Identifier>() {
-            private Identifier currentSymbol = null;
+        return new Iterator<Pair<Identifier, Set<? extends SymbolAnnotation>>>() {
+            private Pair<Identifier, Set<? extends SymbolAnnotation>> currentSymbol = null;
 
             @Override
             public boolean hasNext() {
@@ -154,8 +171,8 @@ public final class Scope {
                     currentSymbol = identifierIterator.next();
                 } else if (!maskParentScope && parentIterator != null && parentIterator.hasNext()) {
                     do {
-                        Identifier symbolFromParent = parentIterator.next();
-                        if (!symbols.containsKey(symbolFromParent.getValue())) {
+                        Pair<Identifier, Set<? extends SymbolAnnotation>> symbolFromParent = parentIterator.next();
+                        if (!symbols.containsKey(symbolFromParent.first.getValue())) {
                             currentSymbol = symbolFromParent;
                             break;
                         }
@@ -171,7 +188,7 @@ public final class Scope {
             }
 
             @Override
-            public Identifier next() {
+            public Pair<Identifier, Set<? extends SymbolAnnotation>> next() {
                 if (currentSymbol == null) {
                     throw new IllegalStateException(
                             "Please make sure that hasNext() returns true before calling next().");
@@ -183,30 +200,40 @@ public final class Scope {
         };
     }
 
-    public Set<VariableExpr> getLiveVariables() {
+    public Map<VariableExpr, Set<? extends SymbolAnnotation>> getLiveVariables() {
         return getLiveVariables(null);
     }
 
-    public Set<VariableExpr> getLiveVariables(Scope stopAtExclusive) {
-        return getLiveVariables(stopAtExclusive, null);
-    }
-
-    public Set<VariableExpr> getLiveVariables(Scope stopAtExclusive, Predicate<? super VarIdentifier> excludeFilter) {
-        LinkedHashSet<VariableExpr> vars = new LinkedHashSet<>();
-        Iterator<Identifier> identifierIterator = liveSymbols(stopAtExclusive);
-        while (identifierIterator.hasNext()) {
-            Identifier identifier = identifierIterator.next();
+    public Map<VariableExpr, Set<? extends SymbolAnnotation>> getLiveVariables(Scope stopAtExclusive) {
+        LinkedHashMap<VariableExpr, Set<? extends SymbolAnnotation>> vars = new LinkedHashMap<>();
+        Iterator<Pair<Identifier, Set<? extends SymbolAnnotation>>> symbolIterator = liveSymbols(stopAtExclusive);
+        while (symbolIterator.hasNext()) {
+            Pair<Identifier, Set<? extends SymbolAnnotation>> p = symbolIterator.next();
+            Identifier identifier = p.first;
             if (identifier instanceof VarIdentifier) {
                 VarIdentifier varId = (VarIdentifier) identifier;
-                if (excludeFilter != null && excludeFilter.test(varId)) {
-                    continue;
-                }
-                vars.add(new VariableExpr(varId));
+                vars.put(new VariableExpr(varId), p.second);
             }
         }
         return vars;
     }
 
+    public static Set<VariableExpr> findVariablesAnnotatedBy(Set<VariableExpr> candidateVars,
+            SymbolAnnotation annotationTest, Map<VariableExpr, Set<? extends SymbolAnnotation>> annotationMap,
+            SourceLocation sourceLoc) throws CompilationException {
+        Set<VariableExpr> resultVars = new HashSet<>();
+        for (VariableExpr var : candidateVars) {
+            Set<? extends SymbolAnnotation> varAnnotations = annotationMap.get(var);
+            if (varAnnotations == null) {
+                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc);
+            }
+            if (varAnnotations.contains(annotationTest)) {
+                resultVars.add(var);
+            }
+        }
+        return resultVars;
+    }
+
     // Returns local symbols within the current scope.
     public Set<String> getLocalSymbols() {
         return symbols.keySet();
@@ -215,4 +242,7 @@ public final class Scope {
     public Scope getParentScope() {
         return parent;
     }
+
+    public interface SymbolAnnotation {
+    }
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
index f332b0a..58470e3 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
@@ -18,12 +18,14 @@
  */
 package org.apache.asterix.lang.common.parser;
 
+import java.util.Set;
 import java.util.Stack;
 
 import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.lang.common.context.RootScopeFactory;
 import org.apache.asterix.lang.common.context.Scope;
 import org.apache.asterix.lang.common.struct.Identifier;
+import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.algebricks.core.algebra.base.Counter;
 
 public class ScopeChecker {
@@ -124,10 +126,12 @@ public class ScopeChecker {
      */
     public final Identifier lookupSymbol(String name) {
         if (name != null) {
-            return getCurrentScope().findSymbol(name);
-        } else {
-            return null;
+            Pair<Identifier, Set<? extends Scope.SymbolAnnotation>> symbol = getCurrentScope().findSymbol(name);
+            if (symbol != null) {
+                return symbol.first;
+            }
         }
+        return null;
     }
 
     /**
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/rewrites/LangRewritingContext.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/rewrites/LangRewritingContext.java
index b2fd3a0..dbcb358 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/rewrites/LangRewritingContext.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/rewrites/LangRewritingContext.java
@@ -19,9 +19,7 @@
 package org.apache.asterix.lang.common.rewrites;
 
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.hyracks.algebricks.core.algebra.base.Counter;
@@ -30,7 +28,6 @@ public final class LangRewritingContext {
     private Counter varCounter;
     private int systemVarCounter = 1;
     private Map<Integer, VarIdentifier> oldVarIdToNewVarId = new HashMap<>();
-    private Set<VarIdentifier> excludedForFieldAccessVars = new HashSet<>();
 
     public LangRewritingContext(int varCounter) {
         this.varCounter = new Counter(varCounter);
@@ -71,12 +68,4 @@ public final class LangRewritingContext {
         varCounter.inc();
         return varCounter.get();
     }
-
-    public void addExcludedForFieldAccessVar(VarIdentifier varId) {
-        excludedForFieldAccessVars.add(varId);
-    }
-
-    public boolean isExcludedForFieldAccessVar(VarIdentifier varId) {
-        return excludedForFieldAccessVars.contains(varId);
-    }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/AbstractSqlppExpressionExtractionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/AbstractSqlppExpressionExtractionVisitor.java
index 4441d65..57bfad5 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/AbstractSqlppExpressionExtractionVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/AbstractSqlppExpressionExtractionVisitor.java
@@ -104,7 +104,6 @@ abstract class AbstractSqlppExpressionExtractionVisitor extends AbstractSqlppSim
             VariableExpr varExpr = new VariableExpr(var);
             varExpr.setSourceLocation(bindExpr.getSourceLocation());
             toLetWhereList.add(new LetClause(varExpr, bindExpr));
-            context.addExcludedForFieldAccessVar(var);
         }
         fromBindingList.clear();
     }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java
index f68688f..416f49b 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java
@@ -185,8 +185,6 @@ public class InlineColumnAliasVisitor extends AbstractSqlppExpressionScopingVisi
             VariableExpr letVarRefExpr = new VariableExpr(letVarId);
             letVarRefExpr.setSourceLocation(sourceLoc);
             columnAliasBinding.setExpression(letVarRefExpr);
-
-            context.addExcludedForFieldAccessVar(letVarId);
         }
     }
 
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/Sql92AggregateFunctionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/Sql92AggregateFunctionVisitor.java
index f52acbf..9f13eb2 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/Sql92AggregateFunctionVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/Sql92AggregateFunctionVisitor.java
@@ -66,19 +66,23 @@ class Sql92AggregateFunctionVisitor extends AbstractSqlppSimpleExpressionVisitor
 
     private final Expression groupVar;
 
-    private final Map<Expression, Identifier> fieldVars;
+    private final Map<VariableExpr, Identifier> groupVarFieldMap;
 
-    private final Collection<VariableExpr> outerVars;
+    private final Collection<VariableExpr> preGroupContextVars;
+
+    private final Collection<VariableExpr> preGroupUnmappedVars;
 
-    private final Set<VariableExpr> prohibitVars;
+    private final Collection<VariableExpr> outerVars;
 
     Sql92AggregateFunctionVisitor(LangRewritingContext context, VariableExpr groupVar,
-            Map<Expression, Identifier> fieldVars, Collection<VariableExpr> outerVars, Set<VariableExpr> prohibitVars) {
+            Map<VariableExpr, Identifier> groupVarFieldMap, Collection<VariableExpr> preGroupContextVars,
+            Collection<VariableExpr> preGroupUnmappedVars, Collection<VariableExpr> outerVars) {
         this.context = context;
         this.groupVar = groupVar;
-        this.fieldVars = fieldVars;
+        this.groupVarFieldMap = groupVarFieldMap;
+        this.preGroupContextVars = preGroupContextVars;
+        this.preGroupUnmappedVars = preGroupUnmappedVars;
         this.outerVars = outerVars;
-        this.prohibitVars = prohibitVars;
     }
 
     @Override
@@ -88,8 +92,8 @@ class Sql92AggregateFunctionVisitor extends AbstractSqlppSimpleExpressionVisitor
         boolean aggregate = FunctionMapUtil.isSql92AggregateFunction(signature);
         boolean rewritten = false;
         for (Expression expr : callExpr.getExprList()) {
-            Expression newExpr = aggregate
-                    ? wrapAggregationArgument(expr, groupVar, fieldVars, outerVars, prohibitVars, context) : expr;
+            Expression newExpr = aggregate ? wrapAggregationArgument(expr, groupVar, groupVarFieldMap,
+                    preGroupContextVars, preGroupUnmappedVars, outerVars, context) : expr;
             rewritten |= newExpr != expr;
             newExprList.add(newExpr.accept(this, arg));
         }
@@ -103,8 +107,9 @@ class Sql92AggregateFunctionVisitor extends AbstractSqlppSimpleExpressionVisitor
     }
 
     static Expression wrapAggregationArgument(Expression expr, Expression groupVar,
-            Map<Expression, Identifier> fieldVars, Collection<VariableExpr> outerVars,
-            Collection<VariableExpr> prohibitVars, LangRewritingContext context) throws CompilationException {
+            Map<VariableExpr, Identifier> groupVarFieldMap, Collection<VariableExpr> preGroupContextVars,
+            Collection<VariableExpr> preGroupUnmappedVars, Collection<VariableExpr> outerVars,
+            LangRewritingContext context) throws CompilationException {
         SourceLocation sourceLoc = expr.getSourceLocation();
         Set<VariableExpr> freeVars = SqlppRewriteUtil.getFreeVariable(expr);
 
@@ -119,25 +124,27 @@ class Sql92AggregateFunctionVisitor extends AbstractSqlppSimpleExpressionVisitor
         Map<Expression, Expression> varExprMap = new HashMap<>();
         for (VariableExpr usedVar : freeVars) {
             // Reference to a field in the group variable.
-            if (fieldVars.containsKey(usedVar)) {
+            if (groupVarFieldMap.containsKey(usedVar)) {
                 // Rewrites to a reference to a field in the group variable.
                 FieldAccessor fa =
-                        new FieldAccessor(fromBindingVar, new VarIdentifier(fieldVars.get(usedVar).getValue()));
+                        new FieldAccessor(fromBindingVar, new VarIdentifier(groupVarFieldMap.get(usedVar).getValue()));
                 fa.setSourceLocation(usedVar.getSourceLocation());
                 varExprMap.put(usedVar, fa);
             } else if (outerVars.contains(usedVar)) {
                 // Do nothing
-            } else if (prohibitVars != null && prohibitVars.contains(usedVar)) {
+            } else if (preGroupUnmappedVars != null && preGroupUnmappedVars.contains(usedVar)) {
                 throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_USE_OF_IDENTIFIER, sourceLoc,
                         SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar().getValue()).getValue());
             } else {
                 // Rewrites to a reference to a single field in the group variable.
-                Identifier ident = findField(fieldVars, usedVar, context);
-                FieldAccessor faInner = new FieldAccessor(fromBindingVar, ident);
+                VariableExpr preGroupVar = VariableCheckAndRewriteVisitor.pickContextVar(preGroupContextVars, usedVar);
+                Identifier groupVarField = groupVarFieldMap.get(preGroupVar);
+                if (groupVarField == null) {
+                    throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc);
+                }
+                FieldAccessor faInner = new FieldAccessor(fromBindingVar, groupVarField);
                 faInner.setSourceLocation(usedVar.getSourceLocation());
-                FieldAccessor faOuter =
-                        new FieldAccessor(faInner, SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar()));
-                faOuter.setSourceLocation(usedVar.getSourceLocation());
+                Expression faOuter = resolveAsFieldAccess(faInner, usedVar.getVar(), usedVar.getSourceLocation());
                 varExprMap.put(usedVar, faOuter);
             }
         }
@@ -159,24 +166,11 @@ class Sql92AggregateFunctionVisitor extends AbstractSqlppSimpleExpressionVisitor
         return selectExpr;
     }
 
-    private static Identifier findField(Map<Expression, Identifier> fieldVars, VariableExpr usedVar,
-            LangRewritingContext context) throws CompilationException {
-        Identifier ident = null;
-        for (Map.Entry<Expression, Identifier> me : fieldVars.entrySet()) {
-            Expression fieldVarExpr = me.getKey();
-            if (fieldVarExpr.getKind() == Expression.Kind.VARIABLE_EXPRESSION
-                    && context.isExcludedForFieldAccessVar(((VariableExpr) fieldVarExpr).getVar())) {
-                continue;
-            }
-            if (ident != null) {
-                throw new CompilationException(ErrorCode.AMBIGUOUS_IDENTIFIER, usedVar.getSourceLocation(),
-                        SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar().getValue()).getValue());
-            }
-            ident = me.getValue();
-        }
-        if (ident == null) {
-            throw new CompilationException(ErrorCode.COMPILATION_ERROR, usedVar.getSourceLocation(), "");
-        }
-        return ident;
+    // TODO: move to VariableCheckAndRewriteVisitor
+    private static Expression resolveAsFieldAccess(Expression sourceExpr, VarIdentifier var, SourceLocation sourceLoc) {
+        VarIdentifier fieldName = SqlppVariableUtil.toUserDefinedVariableName(var.getValue());
+        FieldAccessor fa = new FieldAccessor(sourceExpr, fieldName);
+        fa.setSourceLocation(sourceLoc);
+        return fa;
     }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java
index da7e1eb..935a100 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java
@@ -20,7 +20,7 @@ package org.apache.asterix.lang.sqlpp.rewrites.visitor;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -35,6 +35,7 @@ import org.apache.asterix.lang.common.clause.GroupbyClause;
 import org.apache.asterix.lang.common.clause.LetClause;
 import org.apache.asterix.lang.common.clause.LimitClause;
 import org.apache.asterix.lang.common.clause.OrderbyClause;
+import org.apache.asterix.lang.common.context.Scope;
 import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair;
 import org.apache.asterix.lang.common.expression.VariableExpr;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
@@ -46,6 +47,7 @@ import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
 import org.apache.asterix.lang.sqlpp.util.SqlppRewriteUtil;
 import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
 import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppExpressionScopingVisitor;
+import org.apache.hyracks.algebricks.common.utils.Pair;
 
 /**
  * An AST pre-processor to rewrite group-by sugar queries, which does the following transformations:
@@ -86,7 +88,7 @@ public class SqlppGroupByAggregationSugarVisitor extends AbstractSqlppExpression
     @Override
     public Expression visit(SelectBlock selectBlock, ILangExpression arg) throws CompilationException {
 
-        Set<VariableExpr> outerScopeVars = scopeChecker.getCurrentScope().getLiveVariables();
+        Set<VariableExpr> outerVars = scopeChecker.getCurrentScope().getLiveVariables().keySet();
 
         // Traverses the select block in the order of "from", "let/where"s, "group by", "let/having"s and "select".
         FromClause fromClause = selectBlock.getFromClause();
@@ -99,17 +101,23 @@ public class SqlppGroupByAggregationSugarVisitor extends AbstractSqlppExpression
             }
         }
         if (selectBlock.hasGroupbyClause()) {
-            Set<VariableExpr> visibleVarsPreGroupByScope = scopeChecker.getCurrentScope().getLiveVariables();
+            Map<VariableExpr, Set<? extends Scope.SymbolAnnotation>> preGroupAnnotatedVars =
+                    scopeChecker.getCurrentScope().getLiveVariables();
+            Set<VariableExpr> preGroupVars = preGroupAnnotatedVars.keySet();
 
             GroupbyClause groupbyClause = selectBlock.getGroupbyClause();
             groupbyClause.accept(this, arg);
-            Collection<VariableExpr> visibleVarsInCurrentScope = SqlppVariableUtil.getBindingVariables(groupbyClause);
+            Collection<VariableExpr> groupByBindingVars = SqlppVariableUtil.getBindingVariables(groupbyClause);
 
             VariableExpr groupVar = groupbyClause.getGroupVar();
-            Map<Expression, Identifier> groupFieldVars = getGroupFieldVariables(groupbyClause);
-
-            Set<VariableExpr> unmappedVars =
-                    getUnmappedVariables(visibleVarsPreGroupByScope, outerScopeVars, groupFieldVars);
+            if (!groupbyClause.hasGroupFieldList()) {
+                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, groupbyClause.getSourceLocation());
+            }
+            Map<VariableExpr, Identifier> groupVarFieldMap = createGroupVarFieldMap(groupbyClause.getGroupFieldList());
+            Set<VariableExpr> preGroupMappedVars = groupVarFieldMap.keySet();
+            Set<VariableExpr> preGroupContextVars = Scope.findVariablesAnnotatedBy(preGroupMappedVars,
+                    SqlppVariableAnnotation.CONTEXT_VARIABLE, preGroupAnnotatedVars, groupbyClause.getSourceLocation());
+            Set<VariableExpr> preGroupUnmappedVars = getUnmappedVariables(preGroupVars, preGroupMappedVars, outerVars);
 
             Collection<VariableExpr> freeVariables = new HashSet<>();
             Collection<VariableExpr> freeVariablesInGbyLets = new HashSet<>();
@@ -117,16 +125,16 @@ public class SqlppGroupByAggregationSugarVisitor extends AbstractSqlppExpression
                 for (AbstractClause letHavingClause : selectBlock.getLetHavingListAfterGroupby()) {
                     letHavingClause.accept(this, arg);
                     // Rewrites each let/having clause after the group-by.
-                    rewriteExpressionUsingGroupVariable(groupVar, groupFieldVars, letHavingClause, outerScopeVars,
-                            unmappedVars);
+                    rewriteExpressionUsingGroupVariable(letHavingClause, groupVar, groupVarFieldMap,
+                            preGroupContextVars, preGroupUnmappedVars, outerVars);
                     switch (letHavingClause.getClauseType()) {
                         case LET_CLAUSE:
                             LetClause letClause = (LetClause) letHavingClause;
                             Collection<VariableExpr> freeVariablesInClause =
                                     SqlppVariableUtil.getFreeVariables(letClause.getBindingExpr());
-                            freeVariablesInClause.removeAll(visibleVarsInCurrentScope);
+                            freeVariablesInClause.removeAll(groupByBindingVars);
                             freeVariablesInGbyLets.addAll(freeVariablesInClause);
-                            visibleVarsInCurrentScope.add(letClause.getVarExpr());
+                            groupByBindingVars.add(letClause.getVarExpr());
                             break;
                         case HAVING_CLAUSE:
                             freeVariables.addAll(SqlppVariableUtil.getFreeVariables(letHavingClause));
@@ -144,16 +152,16 @@ public class SqlppGroupByAggregationSugarVisitor extends AbstractSqlppExpression
                     // Rewrites the ORDER BY clause.
                     OrderbyClause orderbyClause = parentSelectExpression.getOrderbyClause();
                     orderbyClause.accept(this, arg);
-                    rewriteExpressionUsingGroupVariable(groupVar, groupFieldVars, orderbyClause, outerScopeVars,
-                            unmappedVars);
+                    rewriteExpressionUsingGroupVariable(orderbyClause, groupVar, groupVarFieldMap, preGroupContextVars,
+                            preGroupUnmappedVars, outerVars);
                     freeVariables.addAll(SqlppVariableUtil.getFreeVariables(orderbyClause));
                 }
                 if (parentSelectExpression.hasLimit()) {
                     // Rewrites the LIMIT clause.
                     LimitClause limitClause = parentSelectExpression.getLimitClause();
                     limitClause.accept(this, arg);
-                    rewriteExpressionUsingGroupVariable(groupVar, groupFieldVars, limitClause, outerScopeVars,
-                            unmappedVars);
+                    rewriteExpressionUsingGroupVariable(limitClause, groupVar, groupVarFieldMap, preGroupContextVars,
+                            preGroupUnmappedVars, outerVars);
                     freeVariables.addAll(SqlppVariableUtil.getFreeVariables(limitClause));
                 }
             }
@@ -162,17 +170,18 @@ public class SqlppGroupByAggregationSugarVisitor extends AbstractSqlppExpression
             SelectClause selectClause = selectBlock.getSelectClause();
             selectClause.accept(this, arg);
             // Rewrites the select clause.
-            rewriteExpressionUsingGroupVariable(groupVar, groupFieldVars, selectClause, outerScopeVars, unmappedVars);
+            rewriteExpressionUsingGroupVariable(selectClause, groupVar, groupVarFieldMap, preGroupContextVars,
+                    preGroupUnmappedVars, outerVars);
             freeVariables.addAll(SqlppVariableUtil.getFreeVariables(selectClause));
-            freeVariables.removeAll(visibleVarsInCurrentScope);
+            freeVariables.removeAll(groupByBindingVars);
 
             // Gets the final free variables.
             freeVariables.addAll(freeVariablesInGbyLets);
             freeVariables.removeIf(SqlppVariableUtil::isExternalVariableReference);
 
             // Gets outer scope variables.
-            Collection<VariableExpr> decorVars = scopeChecker.getCurrentScope().getLiveVariables();
-            decorVars.removeAll(visibleVarsInCurrentScope);
+            Collection<VariableExpr> decorVars = scopeChecker.getCurrentScope().getLiveVariables().keySet();
+            decorVars.removeAll(groupByBindingVars);
 
             // Only retains used free variables.
             if (!decorVars.containsAll(freeVariables)) {
@@ -203,33 +212,34 @@ public class SqlppGroupByAggregationSugarVisitor extends AbstractSqlppExpression
         return null;
     }
 
-    private Map<Expression, Identifier> getGroupFieldVariables(GroupbyClause groupbyClause) {
-        return groupbyClause.hasGroupFieldList()
-                ? SqlppVariableUtil.createFieldVariableMap(groupbyClause.getGroupFieldList()) : Collections.emptyMap();
+    static Map<VariableExpr, Identifier> createGroupVarFieldMap(List<Pair<Expression, Identifier>> fieldList) {
+        Map<VariableExpr, Identifier> fieldVars = new HashMap<>();
+        for (Pair<Expression, Identifier> p : fieldList) {
+            if (p.first.getKind() == Expression.Kind.VARIABLE_EXPRESSION) {
+                fieldVars.put((VariableExpr) p.first, p.second);
+            }
+        }
+        return fieldVars;
     }
 
     /**
      * Returns variables of the current SELECT block that were defined before GROUP BY clause but were not mapped by
      * GROUP AS sub-clause. These variables cannot be used by SQL aggregate functions after the GROUP BY
      */
-    private Set<VariableExpr> getUnmappedVariables(Set<VariableExpr> preGroupByScopeVariables,
-            Set<VariableExpr> outerScopeVariables, Map<Expression, Identifier> groupFieldVariables) {
-        Set<VariableExpr> result = new HashSet<>(preGroupByScopeVariables);
-        result.removeAll(outerScopeVariables);
-        for (Expression expr : groupFieldVariables.keySet()) {
-            if (expr.getKind() == Expression.Kind.VARIABLE_EXPRESSION) {
-                result.remove(expr);
-            }
-        }
+    private Set<VariableExpr> getUnmappedVariables(Set<VariableExpr> preGroupByVars,
+            Set<VariableExpr> preGroupByMappedVars, Set<VariableExpr> outerVars) {
+        Set<VariableExpr> result = new HashSet<>(preGroupByVars);
+        result.removeAll(preGroupByMappedVars);
+        result.removeAll(outerVars);
         return result;
     }
 
     // Applying sugar rewriting for group-by.
-    private void rewriteExpressionUsingGroupVariable(VariableExpr groupVar, Map<Expression, Identifier> fieldVars,
-            ILangExpression expr, Set<VariableExpr> outerScopeVariables, Set<VariableExpr> prohibitVars)
-            throws CompilationException {
-        Sql92AggregateFunctionVisitor visitor =
-                new Sql92AggregateFunctionVisitor(context, groupVar, fieldVars, outerScopeVariables, prohibitVars);
+    private void rewriteExpressionUsingGroupVariable(ILangExpression expr, VariableExpr groupVar,
+            Map<VariableExpr, Identifier> groupVarFieldMap, Set<VariableExpr> preGroupContextVars,
+            Set<VariableExpr> preGroupUnmappedVars, Set<VariableExpr> outerVars) throws CompilationException {
+        Sql92AggregateFunctionVisitor visitor = new Sql92AggregateFunctionVisitor(context, groupVar, groupVarFieldMap,
+                preGroupContextVars, preGroupUnmappedVars, outerVars);
         expr.accept(visitor, null);
     }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowAggregationSugarVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowAggregationSugarVisitor.java
index 597a1ab..a5f43b6 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowAggregationSugarVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowAggregationSugarVisitor.java
@@ -30,6 +30,7 @@ import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.ILangExpression;
+import org.apache.asterix.lang.common.context.Scope;
 import org.apache.asterix.lang.common.expression.VariableExpr;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.struct.Identifier;
@@ -99,11 +100,17 @@ public class SqlppWindowAggregationSugarVisitor extends AbstractSqlppExpressionS
     }
 
     void wrapAggregationArguments(WindowExpression winExpr, int limit) throws CompilationException {
-        Set<VariableExpr> liveVars = scopeChecker.getCurrentScope().getLiveVariables();
-
         VariableExpr winVar = winExpr.getWindowVar();
+
+        Map<VariableExpr, Set<? extends Scope.SymbolAnnotation>> liveAnnotatedVars =
+                scopeChecker.getCurrentScope().getLiveVariables();
+        Set<VariableExpr> liveVars = liveAnnotatedVars.keySet();
+        Set<VariableExpr> liveContextVars = Scope.findVariablesAnnotatedBy(liveVars,
+                SqlppVariableAnnotation.CONTEXT_VARIABLE, liveAnnotatedVars, winExpr.getSourceLocation());
+
         List<Pair<Expression, Identifier>> winFieldList = winExpr.getWindowFieldList();
-        Map<Expression, Identifier> fieldMap = SqlppVariableUtil.createFieldVariableMap(winFieldList);
+        Map<VariableExpr, Identifier> winVarFieldMap =
+                SqlppGroupByAggregationSugarVisitor.createGroupVarFieldMap(winFieldList);
 
         List<Expression> exprList = winExpr.getExprList();
         int n = exprList.size();
@@ -111,7 +118,7 @@ public class SqlppWindowAggregationSugarVisitor extends AbstractSqlppExpressionS
         for (int i = 0; i < n; i++) {
             Expression expr = exprList.get(i);
             Expression newExpr = i < limit ? Sql92AggregateFunctionVisitor.wrapAggregationArgument(expr, winVar,
-                    fieldMap, liveVars, null, context) : expr;
+                    winVarFieldMap, liveContextVars, null, liveVars, context) : expr;
             newExprList.add(newExpr);
         }
         winExpr.setExprList(newExprList);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
index 45a18e8..b883af5 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.asterix.common.exceptions.CompilationException;
@@ -30,6 +31,7 @@ import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.Expression.Kind;
 import org.apache.asterix.lang.common.base.ILangExpression;
+import org.apache.asterix.lang.common.context.Scope;
 import org.apache.asterix.lang.common.expression.CallExpr;
 import org.apache.asterix.lang.common.expression.FieldAccessor;
 import org.apache.asterix.lang.common.expression.LiteralExpr;
@@ -58,7 +60,8 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
     protected final MetadataProvider metadataProvider;
 
     /**
-     * @param context, manages ids of variables and guarantees uniqueness of variables.
+     * @param context,
+     *            manages ids of variables and guarantees uniqueness of variables.
      */
     public VariableCheckAndRewriteVisitor(LangRewritingContext context, MetadataProvider metadataProvider,
             Collection<VarIdentifier> externalVars) {
@@ -70,7 +73,7 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
     public Expression visit(FieldAccessor fa, ILangExpression parent) throws CompilationException {
         Expression leadingExpr = fa.getExpr();
         if (leadingExpr.getKind() != Kind.VARIABLE_EXPRESSION) {
-            fa.setExpr(leadingExpr.accept(this, fa));
+            fa.setExpr(leadingExpr.accept(this, parent));
             return fa;
         } else {
             VariableExpr varExpr = (VariableExpr) leadingExpr;
@@ -78,7 +81,7 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
             Expression resolvedExpr = resolve(varExpr,
                     /* Resolves within the dataverse that has the same name as the variable name. */
                     SqlppVariableUtil.toUserDefinedVariableName(varExpr.getVar().getValue()).getValue(), lastIdentifier,
-                    fa, parent);
+                    parent);
             if (resolvedExpr.getKind() == Kind.CALL_EXPRESSION) {
                 CallExpr callExpr = (CallExpr) resolvedExpr;
                 if (callExpr.getFunctionSignature().equals(FN_DATASET)) {
@@ -94,12 +97,12 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
     @Override
     public Expression visit(VariableExpr varExpr, ILangExpression parent) throws CompilationException {
         return resolve(varExpr, metadataProvider.getDefaultDataverseName(),
-                SqlppVariableUtil.toUserDefinedVariableName(varExpr.getVar().getValue()).getValue(), varExpr, parent);
+                SqlppVariableUtil.toUserDefinedVariableName(varExpr.getVar().getValue()).getValue(), parent);
     }
 
     // Resolve a variable expression with dataverse name and dataset name.
-    private Expression resolve(VariableExpr varExpr, String dataverseName, String datasetName,
-            Expression originalExprWithUndefinedIdentifier, ILangExpression parent) throws CompilationException {
+    private Expression resolve(VariableExpr varExpr, String dataverseName, String datasetName, ILangExpression parent)
+            throws CompilationException {
 
         VarIdentifier varId = varExpr.getVar();
         String varName = varId.getValue();
@@ -117,23 +120,20 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
                     SqlppVariableUtil.variableNameToDisplayedFieldName(varId.getValue()));
         }
 
-        boolean resolveToDatasetOnly = resolveToDatasetOnly(originalExprWithUndefinedIdentifier, parent);
-        if (resolveToDatasetOnly) {
+        boolean resolveToDataset = parent.accept(CheckDatasetOnlyResolutionVisitor.INSTANCE, varExpr);
+        if (resolveToDataset) {
+            // resolve the undefined identifier reference as a dataset access.
+            // for a From/Join/UNNEST/Quantifiers binding expression
             return resolveAsDataset(dataverseName, datasetName, sourceLoc);
-        }
-
-        Set<VariableExpr> localVars = scopeChecker.getCurrentScope().getLiveVariables(scopeChecker.getPrecedingScope(),
-                context::isExcludedForFieldAccessVar);
-        switch (localVars.size()) {
-            case 0:
-                return resolveAsDataset(dataverseName, datasetName, sourceLoc);
-            case 1:
-                return resolveAsFieldAccess(localVars.iterator().next(),
-                        SqlppVariableUtil.toUserDefinedVariableName(varName).getValue(), sourceLoc);
-            default:
-                // More than one possibilities.
-                throw new CompilationException(ErrorCode.AMBIGUOUS_IDENTIFIER, sourceLoc,
-                        SqlppVariableUtil.toUserDefinedVariableName(varName).getValue());
+        } else {
+            // resolve the undefined identifier reference as a field access on a context variable
+            Map<VariableExpr, Set<? extends Scope.SymbolAnnotation>> localVars =
+                    scopeChecker.getCurrentScope().getLiveVariables(scopeChecker.getPrecedingScope());
+            Set<VariableExpr> contextVars = Scope.findVariablesAnnotatedBy(localVars.keySet(),
+                    SqlppVariableAnnotation.CONTEXT_VARIABLE, localVars, sourceLoc);
+            VariableExpr contextVar = pickContextVar(contextVars, varExpr);
+            String fieldName = SqlppVariableUtil.toUserDefinedVariableName(varId.getValue()).getValue();
+            return resolveAsFieldAccess(contextVar, fieldName, sourceLoc);
         }
     }
 
@@ -149,7 +149,7 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
             throws CompilationException {
         Dataset dataset = findDataset(dataverseName, datasetName, sourceLoc);
         if (dataset == null) {
-            throwUnresolvableError(dataverseName, datasetName, sourceLoc);
+            throw createUnresolvableError(dataverseName, datasetName, sourceLoc);
         }
         metadataProvider.addAccessedDataset(dataset);
         List<Expression> argList = new ArrayList<>(1);
@@ -169,25 +169,17 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
         return callExpr;
     }
 
-    private void throwUnresolvableError(String dataverseName, String datasetName, SourceLocation sourceLoc)
-            throws CompilationException {
+    private CompilationException createUnresolvableError(String dataverseName, String datasetName,
+            SourceLocation sourceLoc) {
         String defaultDataverseName = metadataProvider.getDefaultDataverseName();
         if (dataverseName == null && defaultDataverseName == null) {
-            throw new CompilationException(ErrorCode.NAME_RESOLVE_UNKNOWN_DATASET, sourceLoc, datasetName);
+            return new CompilationException(ErrorCode.NAME_RESOLVE_UNKNOWN_DATASET, sourceLoc, datasetName);
         }
         //If no available dataset nor in-scope variable to resolve to, we throw an error.
-        throw new CompilationException(ErrorCode.NAME_RESOLVE_UNKNOWN_DATASET_IN_DATAVERSE, sourceLoc, datasetName,
+        return new CompilationException(ErrorCode.NAME_RESOLVE_UNKNOWN_DATASET_IN_DATAVERSE, sourceLoc, datasetName,
                 dataverseName == null ? defaultDataverseName : dataverseName);
     }
 
-    // For a From/Join/UNNEST/Quantifiers binding expression, we resolve the undefined identifier reference as
-    // a dataset access only.
-    private boolean resolveToDatasetOnly(Expression originalExpressionWithUndefinedIdentifier, ILangExpression parent)
-            throws CompilationException {
-        CheckDatasetOnlyResolutionVisitor visitor = new CheckDatasetOnlyResolutionVisitor();
-        return parent.accept(visitor, originalExpressionWithUndefinedIdentifier);
-    }
-
     private Dataset findDataset(String dataverseName, String datasetName, SourceLocation sourceLoc)
             throws CompilationException {
         try {
@@ -246,4 +238,18 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
         }
         return super.visit(winExpr, arg);
     }
+
+    static VariableExpr pickContextVar(Collection<VariableExpr> contextVars, VariableExpr usedVar)
+            throws CompilationException {
+        switch (contextVars.size()) {
+            case 0:
+                throw new CompilationException(ErrorCode.UNDEFINED_IDENTIFIER, usedVar.getSourceLocation(),
+                        SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar().getValue()).getValue());
+            case 1:
+                return contextVars.iterator().next();
+            default:
+                throw new CompilationException(ErrorCode.AMBIGUOUS_IDENTIFIER, usedVar.getSourceLocation(),
+                        SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar().getValue()).getValue());
+        }
+    }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java
index 3fc5683..5d9ce21 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java
@@ -20,10 +20,8 @@ package org.apache.asterix.lang.sqlpp.util;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import org.apache.asterix.common.exceptions.CompilationException;
@@ -203,14 +201,6 @@ public class SqlppVariableUtil {
         return bindingVars;
     }
 
-    public static Map<Expression, Identifier> createFieldVariableMap(List<Pair<Expression, Identifier>> fieldList) {
-        Map<Expression, Identifier> fieldVars = new HashMap<>();
-        for (Pair<Expression, Identifier> p : fieldList) {
-            fieldVars.put(p.first, p.second);
-        }
-        return fieldVars;
-    }
-
     public static void addToFieldVariableList(VariableExpr varExpr, List<Pair<Expression, Identifier>> outFieldList) {
         VarIdentifier var = varExpr.getVar();
         VariableExpr newVarExpr = new VariableExpr(var);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckDatasetOnlyResolutionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckDatasetOnlyResolutionVisitor.java
index c7b685e..e4ccef5 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckDatasetOnlyResolutionVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckDatasetOnlyResolutionVisitor.java
@@ -39,6 +39,7 @@ import org.apache.asterix.lang.common.expression.RecordConstructor;
 import org.apache.asterix.lang.common.expression.UnaryExpr;
 import org.apache.asterix.lang.common.expression.VariableExpr;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.InsertStatement;
 import org.apache.asterix.lang.common.statement.Query;
 import org.apache.asterix.lang.common.struct.QuantifiedPair;
 import org.apache.asterix.lang.sqlpp.clause.FromClause;
@@ -56,188 +57,204 @@ import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
 import org.apache.asterix.lang.sqlpp.expression.CaseExpression;
 import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
 import org.apache.asterix.lang.sqlpp.expression.WindowExpression;
+import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
 import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppQueryExpressionVisitor;
 
 /**
  * This class checks whether a reference to an undefined identifier (the second parameter of the visit method)
  * that is directly enclosed in the first parameter of the visit method should only be resolved to a dataset.
  */
-public class CheckDatasetOnlyResolutionVisitor extends AbstractSqlppQueryExpressionVisitor<Boolean, ILangExpression> {
+public final class CheckDatasetOnlyResolutionVisitor
+        extends AbstractSqlppQueryExpressionVisitor<Boolean, VariableExpr> {
+
+    public static final CheckDatasetOnlyResolutionVisitor INSTANCE = new CheckDatasetOnlyResolutionVisitor();
+
+    private CheckDatasetOnlyResolutionVisitor() {
+    }
 
     @Override
-    public Boolean visit(Query q, ILangExpression expr) throws CompilationException {
-        return false;
+    public Boolean visit(FromTerm fromTerm, VariableExpr arg) throws CompilationException {
+        return contains(fromTerm.getLeftExpression(), arg);
     }
 
     @Override
-    public Boolean visit(FunctionDecl fd, ILangExpression expr) throws CompilationException {
-        return false;
+    public Boolean visit(JoinClause joinClause, VariableExpr arg) throws CompilationException {
+        return contains(joinClause.getRightExpression(), arg);
     }
 
     @Override
-    public Boolean visit(LiteralExpr l, ILangExpression expr) throws CompilationException {
-        return false;
+    public Boolean visit(NestClause nestClause, VariableExpr arg) throws CompilationException {
+        return contains(nestClause.getRightExpression(), arg);
     }
 
     @Override
-    public Boolean visit(VariableExpr v, ILangExpression expr) throws CompilationException {
-        return false;
+    public Boolean visit(UnnestClause unnestClause, VariableExpr arg) throws CompilationException {
+        return contains(unnestClause.getRightExpression(), arg);
     }
 
     @Override
-    public Boolean visit(ListConstructor lc, ILangExpression expr) throws CompilationException {
+    public Boolean visit(QuantifiedExpression qe, VariableExpr arg) throws CompilationException {
+        for (QuantifiedPair qp : qe.getQuantifiedList()) {
+            // If the target reference of undefined variable is a binding expression in a quantified pair,
+            // then we only resolve it to dataset.
+            if (contains(qp.getExpr(), arg)) {
+                return true;
+            }
+        }
         return false;
     }
 
     @Override
-    public Boolean visit(RecordConstructor rc, ILangExpression expr) throws CompilationException {
+    public Boolean visit(Query q, VariableExpr arg) throws CompilationException {
+        return contains(q, arg);
+    }
+
+    @Override
+    public Boolean visit(InsertStatement insert, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(OperatorExpr ifbo, ILangExpression expr) throws CompilationException {
+    public Boolean visit(FunctionDecl fd, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(FieldAccessor fa, ILangExpression expr) throws CompilationException {
+    public Boolean visit(LiteralExpr l, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(IndexAccessor ia, ILangExpression expr) throws CompilationException {
+    public Boolean visit(VariableExpr v, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(ListSliceExpression expression, ILangExpression expr) throws CompilationException {
+    public Boolean visit(ListConstructor lc, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(IfExpr ifexpr, ILangExpression expr) throws CompilationException {
+    public Boolean visit(RecordConstructor rc, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(QuantifiedExpression qe, ILangExpression expr) throws CompilationException {
-        for (QuantifiedPair qp : qe.getQuantifiedList()) {
-            // If the target reference of undefined variable is a binding expression in a quantified pair,
-            // then we only resolve it to dataset.
-            if (expr == qp.getExpr()) {
-                return true;
-            }
-        }
+    public Boolean visit(OperatorExpr ifbo, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(UnaryExpr u, ILangExpression expr) throws CompilationException {
+    public Boolean visit(FieldAccessor fa, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(CallExpr pf, ILangExpression expr) throws CompilationException {
+    public Boolean visit(IndexAccessor ia, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(LetClause lc, ILangExpression expr) throws CompilationException {
+    public Boolean visit(ListSliceExpression expression, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(WhereClause wc, ILangExpression expr) throws CompilationException {
+    public Boolean visit(IfExpr ifexpr, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(OrderbyClause oc, ILangExpression expr) throws CompilationException {
+    public Boolean visit(UnaryExpr u, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(GroupbyClause gc, ILangExpression expr) throws CompilationException {
+    public Boolean visit(CallExpr pf, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(LimitClause lc, ILangExpression expr) throws CompilationException {
+    public Boolean visit(LetClause lc, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(FromClause fromClause, ILangExpression expr) throws CompilationException {
+    public Boolean visit(WhereClause wc, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(FromTerm fromTerm, ILangExpression expr) throws CompilationException {
-        return expr == fromTerm.getLeftExpression();
+    public Boolean visit(OrderbyClause oc, VariableExpr arg) throws CompilationException {
+        return false;
     }
 
     @Override
-    public Boolean visit(JoinClause joinClause, ILangExpression expr) throws CompilationException {
-        return expr == joinClause.getRightExpression();
+    public Boolean visit(GroupbyClause gc, VariableExpr arg) throws CompilationException {
+        return false;
     }
 
     @Override
-    public Boolean visit(NestClause nestClause, ILangExpression expr) throws CompilationException {
-        return expr == nestClause.getRightExpression();
+    public Boolean visit(LimitClause lc, VariableExpr arg) throws CompilationException {
+        return false;
     }
 
     @Override
-    public Boolean visit(Projection projection, ILangExpression expr) throws CompilationException {
+    public Boolean visit(FromClause fromClause, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(SelectBlock selectBlock, ILangExpression expr) throws CompilationException {
+    public Boolean visit(Projection projection, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(SelectClause selectClause, ILangExpression expr) throws CompilationException {
+    public Boolean visit(SelectBlock selectBlock, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(SelectElement selectElement, ILangExpression expr) throws CompilationException {
+    public Boolean visit(SelectClause selectClause, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(SelectRegular selectRegular, ILangExpression expr) throws CompilationException {
+    public Boolean visit(SelectElement selectElement, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(SelectSetOperation selectSetOperation, ILangExpression expr) throws CompilationException {
+    public Boolean visit(SelectRegular selectRegular, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(SelectExpression selectStatement, ILangExpression expr) throws CompilationException {
+    public Boolean visit(SelectSetOperation selectSetOperation, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(UnnestClause unnestClause, ILangExpression expr) throws CompilationException {
-        return expr == unnestClause.getRightExpression();
+    public Boolean visit(SelectExpression selectStatement, VariableExpr arg) throws CompilationException {
+        return false;
     }
 
     @Override
-    public Boolean visit(HavingClause havingClause, ILangExpression expr) throws CompilationException {
+    public Boolean visit(HavingClause havingClause, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(CaseExpression caseExpr, ILangExpression arg) throws CompilationException {
+    public Boolean visit(CaseExpression caseExpr, VariableExpr arg) throws CompilationException {
         return false;
     }
 
     @Override
-    public Boolean visit(WindowExpression windowExpression, ILangExpression arg) throws CompilationException {
+    public Boolean visit(WindowExpression windowExpression, VariableExpr arg) throws CompilationException {
         return false;
     }
+
+    private boolean contains(ILangExpression expr, VariableExpr var) throws CompilationException {
+        return SqlppVariableUtil.getFreeVariables(expr).contains(var);
+    }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
index 8650eec..68f18d6 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
@@ -19,6 +19,8 @@
 package org.apache.asterix.lang.sqlpp.visitor.base;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -63,8 +65,7 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
     protected final LangRewritingContext context;
 
     /**
-     * @param context,
-     *            manages ids of variables and guarantees uniqueness of variables.
+     * @param context, manages ids of variables and guarantees uniqueness of variables.
      */
     public AbstractSqlppExpressionScopingVisitor(LangRewritingContext context) {
         this(context, null);
@@ -101,13 +102,15 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
 
     @Override
     public Expression visit(FromTerm fromTerm, ILangExpression arg) throws CompilationException {
-        scopeChecker.createNewScope();
         // Visit the left expression of a from term.
         fromTerm.setLeftExpression(visit(fromTerm.getLeftExpression(), fromTerm));
 
+        scopeChecker.createNewScope();
+
         // Registers the data item variable.
         VariableExpr leftVar = fromTerm.getLeftVariable();
-        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), leftVar.getVar(), leftVar.getSourceLocation());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), leftVar.getVar(), leftVar.getSourceLocation(),
+                SqlppVariableAnnotation.CONTEXT_VARIABLE);
 
         // Registers the positional variable
         if (fromTerm.hasPositionalVariable()) {
@@ -132,7 +135,8 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
 
         // Registers the data item variable.
         VariableExpr rightVar = joinClause.getRightVariable();
-        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar(), rightVar.getSourceLocation());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar(), rightVar.getSourceLocation(),
+                SqlppVariableAnnotation.CONTEXT_VARIABLE);
 
         if (joinClause.hasPositionalVariable()) {
             // Registers the positional variable.
@@ -158,7 +162,8 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
 
         // Registers the data item variable.
         VariableExpr rightVar = nestClause.getRightVariable();
-        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar(), rightVar.getSourceLocation());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar(), rightVar.getSourceLocation(),
+                SqlppVariableAnnotation.CONTEXT_VARIABLE);
 
         if (nestClause.hasPositionalVariable()) {
             // Registers the positional variable.
@@ -178,7 +183,8 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
 
         // register the data item variable
         VariableExpr rightVar = unnestClause.getRightVariable();
-        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar(), rightVar.getSourceLocation());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar(), rightVar.getSourceLocation(),
+                SqlppVariableAnnotation.CONTEXT_VARIABLE);
 
         if (unnestClause.hasPositionalVariable()) {
             // register the positional variable
@@ -331,7 +337,8 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
         for (QuantifiedPair pair : qe.getQuantifiedList()) {
             pair.setExpr(visit(pair.getExpr(), qe));
             VariableExpr varExpr = pair.getVarExpr();
-            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), varExpr.getVar(), varExpr.getSourceLocation());
+            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), varExpr.getVar(), varExpr.getSourceLocation(),
+                    SqlppVariableAnnotation.CONTEXT_VARIABLE);
         }
         qe.setSatisfiesExpr(visit(qe.getSatisfiesExpr(), qe));
         scopeChecker.removeCurrentScope();
@@ -365,7 +372,8 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
         // Registers the (inserted) data item variable.
         VariableExpr bindingVar = insertStatement.getVar();
         if (bindingVar != null) {
-            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), bindingVar.getVar(), bindingVar.getSourceLocation());
+            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), bindingVar.getVar(), bindingVar.getSourceLocation(),
+                    SqlppVariableAnnotation.CONTEXT_VARIABLE);
         }
 
         // Visits the expression for the returning expression.
@@ -393,13 +401,20 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
     }
 
     // Adds a new encountered alias identifier into a scope
-    private void addNewVarSymbolToScope(Scope scope, VarIdentifier var, SourceLocation sourceLoc)
-            throws CompilationException {
+    private void addNewVarSymbolToScope(Scope scope, VarIdentifier var, SourceLocation sourceLoc,
+            SqlppVariableAnnotation... varAnnotations) throws CompilationException {
         if (scope.findLocalSymbol(var.getValue()) != null) {
             throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc,
                     "Duplicate alias definitions: " + SqlppVariableUtil.toUserDefinedName(var.getValue()));
         }
-        scope.addNewVarSymbolToScope(var);
+        Set<SqlppVariableAnnotation> annotations;
+        if (varAnnotations == null || varAnnotations.length == 0) {
+            annotations = Collections.emptySet();
+        } else {
+            annotations = EnumSet.noneOf(SqlppVariableAnnotation.class);
+            Collections.addAll(annotations, varAnnotations);
+        }
+        scope.addNewVarSymbolToScope(var, annotations);
     }
 
     // Merges <code>scopeToBeMerged</code> into <code>hostScope</code>.
@@ -414,4 +429,16 @@ public class AbstractSqlppExpressionScopingVisitor extends AbstractSqlppSimpleEx
         }
         hostScope.merge(scopeToBeMerged);
     }
+
+    public enum SqlppVariableAnnotation implements Scope.SymbolAnnotation {
+        /**
+         * Context variables are those that participate in the second stage of the name resolution process.
+         * A single name identifier is first attempted to be resolved as a variable reference. If that fails
+         * because there's no variable with such name then (second stage) it's resolved as a field access on a context
+         * variable (if there's only one context variable defined in the local scope).
+         *
+         * See {@link org.apache.asterix.lang.sqlpp.rewrites.visitor.VariableCheckAndRewriteVisitor}
+         */
+        CONTEXT_VARIABLE
+    }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
index f9a5061..0428a73 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
@@ -202,7 +202,7 @@ public class AbstractSqlppSimpleExpressionVisitor
 
     @Override
     public Expression visit(OrderbyClause oc, ILangExpression arg) throws CompilationException {
-        oc.setOrderbyList(visit(oc.getOrderbyList(), arg));
+        oc.setOrderbyList(visit(oc.getOrderbyList(), oc));
         return null;
     }
 
@@ -272,8 +272,8 @@ public class AbstractSqlppSimpleExpressionVisitor
     @Override
     public Expression visit(RecordConstructor rc, ILangExpression arg) throws CompilationException {
         for (FieldBinding binding : rc.getFbList()) {
-            binding.setLeftExpr(visit(binding.getLeftExpr(), rc));
-            binding.setRightExpr(visit(binding.getRightExpr(), rc));
+            binding.setLeftExpr(visit(binding.getLeftExpr(), arg));
+            binding.setRightExpr(visit(binding.getRightExpr(), arg));
         }
         return rc;
     }
@@ -286,9 +286,9 @@ public class AbstractSqlppSimpleExpressionVisitor
 
     @Override
     public Expression visit(IfExpr ifExpr, ILangExpression arg) throws CompilationException {
-        ifExpr.setCondExpr(visit(ifExpr.getCondExpr(), ifExpr));
-        ifExpr.setThenExpr(visit(ifExpr.getThenExpr(), ifExpr));
-        ifExpr.setElseExpr(visit(ifExpr.getElseExpr(), ifExpr));
+        ifExpr.setCondExpr(visit(ifExpr.getCondExpr(), arg));
+        ifExpr.setThenExpr(visit(ifExpr.getThenExpr(), arg));
+        ifExpr.setElseExpr(visit(ifExpr.getElseExpr(), arg));
         return ifExpr;
     }
 
@@ -314,7 +314,7 @@ public class AbstractSqlppSimpleExpressionVisitor
 
     @Override
     public Expression visit(UnaryExpr u, ILangExpression arg) throws CompilationException {
-        u.setExpr(visit(u.getExpr(), u));
+        u.setExpr(visit(u.getExpr(), arg));
         return u;
     }
 
@@ -328,16 +328,16 @@ public class AbstractSqlppSimpleExpressionVisitor
     protected void visitWindowExpressionExcludingExprList(WindowExpression winExpr, ILangExpression arg)
             throws CompilationException {
         if (winExpr.hasPartitionList()) {
-            winExpr.setPartitionList(visit(winExpr.getPartitionList(), winExpr));
+            winExpr.setPartitionList(visit(winExpr.getPartitionList(), arg));
         }
         if (winExpr.hasOrderByList()) {
-            winExpr.setOrderbyList(visit(winExpr.getOrderbyList(), winExpr));
+            winExpr.setOrderbyList(visit(winExpr.getOrderbyList(), arg));
         }
         if (winExpr.hasFrameStartExpr()) {
-            winExpr.setFrameStartExpr(visit(winExpr.getFrameStartExpr(), winExpr));
+            winExpr.setFrameStartExpr(visit(winExpr.getFrameStartExpr(), arg));
         }
         if (winExpr.hasFrameEndExpr()) {
-            winExpr.setFrameEndExpr(visit(winExpr.getFrameEndExpr(), winExpr));
+            winExpr.setFrameEndExpr(visit(winExpr.getFrameEndExpr(), arg));
         }
         if (winExpr.hasWindowFieldList()) {
             for (Pair<Expression, Identifier> field : winExpr.getWindowFieldList()) {
@@ -348,13 +348,13 @@ public class AbstractSqlppSimpleExpressionVisitor
 
     @Override
     public Expression visit(FieldAccessor fa, ILangExpression arg) throws CompilationException {
-        fa.setExpr(visit(fa.getExpr(), fa));
+        fa.setExpr(visit(fa.getExpr(), arg));
         return fa;
     }
 
     @Override
     public Expression visit(IndexAccessor ia, ILangExpression arg) throws CompilationException {
-        ia.setExpr(visit(ia.getExpr(), ia));
+        ia.setExpr(visit(ia.getExpr(), arg));
         if (ia.getIndexExpr() != null) {
             ia.setIndexExpr(visit(ia.getIndexExpr(), arg));
         }
@@ -363,7 +363,7 @@ public class AbstractSqlppSimpleExpressionVisitor
 
     @Override
     public Expression visit(ListSliceExpression expression, ILangExpression arg) throws CompilationException {
-        expression.setExpr(visit(expression.getExpr(), expression));
+        expression.setExpr(visit(expression.getExpr(), arg));
         expression.setStartIndexExpression(visit(expression.getStartIndexExpression(), arg));
 
         // End index expression can be null (optional)
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 05b88cc..765e97b 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -1088,8 +1088,9 @@ InsertStatement InsertStatement() throws ParseException:
     query = Query(false)
     ( <RETURNING> returnExpression = Expression())?
     {
-      if (returnExpression != null && var == null) {
-        var = ExpressionToVariableUtil.getGeneratedVariable(query.getBody(), true);
+      if (var == null && returnExpression != null) {
+        var = new VariableExpr(SqlppVariableUtil.toInternalVariableIdentifier(nameComponents.second.getValue()));
+        addSourceLocation(var, startToken);
       }
       query.setTopLevel(true);
       InsertStatement stmt = new InsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter(),
@@ -1111,8 +1112,9 @@ UpsertStatement UpsertStatement() throws ParseException:
     query = Query(false)
     ( <RETURNING> returnExpression = Expression())?
     {
-      if (returnExpression != null && var == null) {
-        var = ExpressionToVariableUtil.getGeneratedVariable(query.getBody(), true);
+      if (var == null && returnExpression != null) {
+          var = new VariableExpr(SqlppVariableUtil.toInternalVariableIdentifier(nameComponents.second.getValue()));
+          addSourceLocation(var, startToken);
       }
       query.setTopLevel(true);
       UpsertStatement stmt = new UpsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter(),
@@ -1124,23 +1126,20 @@ UpsertStatement UpsertStatement() throws ParseException:
 DeleteStatement DeleteStatement() throws ParseException:
 {
   Token startToken = null;
-  VariableExpr varExpr = null;
+  VariableExpr var = null;
   Expression condition = null;
   Pair<Identifier, Identifier> nameComponents;
 }
 {
   <DELETE> { startToken = token; }
-  <FROM> nameComponents  = QualifiedName()
-         ((<AS>)? varExpr = Variable())?
+  <FROM> nameComponents  = QualifiedName() ((<AS>)? var = Variable())?
   (<WHERE> condition = Expression())?
   {
-      if(varExpr == null){
-        varExpr = new VariableExpr();
-        VarIdentifier var = SqlppVariableUtil.toInternalVariableIdentifier(nameComponents.second.getValue());
-        varExpr.setVar(var);
-        addSourceLocation(varExpr, startToken);
+      if (var == null) {
+        var = new VariableExpr(SqlppVariableUtil.toInternalVariableIdentifier(nameComponents.second.getValue()));
+        addSourceLocation(var, startToken);
       }
-      DeleteStatement stmt = new DeleteStatement(varExpr, nameComponents.first, nameComponents.second,
+      DeleteStatement stmt = new DeleteStatement(var, nameComponents.first, nameComponents.second,
           condition, getVarCounter());
       return addSourceLocation(stmt, startToken);
   }