ASTERIXDB-1576: fix and add negative regression tests.

Change-Id: I8b4f66907f8ac8043fe245c9c5a331884db2b005
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1079
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Yingyi Bu <buyingyi@gmail.com>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.1.ddl.sqlpp
new file mode 100644
index 0000000..47ceba2
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.1.ddl.sqlpp
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop dataset samptable if exists;
+drop type samptabletype if exists;
+
+create type samptabletype as closed {
+  id: int8
+};
+
+create dataset samptable1(samptabletype) primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.2.update.sqlpp
new file mode 100644
index 0000000..06ec978
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.2.update.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+insert into samptable1 ({'id' : 0});
+
+insert into samptable1 ({'id' : 1});
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.3.query.sqlpp
new file mode 100644
index 0000000..9f61a07
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-2/query-ASTERIXDB-1576-2.3.query.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+// Negative test for duplicate alias names.
+select *
+from sample1 s1,
+     samptable1 s2 join samptable1 s2 on s2.id=s2.id
+;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.1.ddl.sqlpp
new file mode 100644
index 0000000..47ceba2
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.1.ddl.sqlpp
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop dataset samptable if exists;
+drop type samptabletype if exists;
+
+create type samptabletype as closed {
+  id: int8
+};
+
+create dataset samptable1(samptabletype) primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.2.update.sqlpp
new file mode 100644
index 0000000..06ec978
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.2.update.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+insert into samptable1 ({'id' : 0});
+
+insert into samptable1 ({'id' : 1});
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.3.query.sqlpp
new file mode 100644
index 0000000..2132251
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576-3/query-ASTERIXDB-1576-3.3.query.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+// Negative test for duplicate alias names.
+with s1 as sample1, s1 as sample1
+select *
+from s1, s1
+;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.1.ddl.sqlpp
new file mode 100644
index 0000000..47ceba2
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.1.ddl.sqlpp
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop dataset samptable if exists;
+drop type samptabletype if exists;
+
+create type samptabletype as closed {
+  id: int8
+};
+
+create dataset samptable1(samptabletype) primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.2.update.sqlpp
new file mode 100644
index 0000000..06ec978
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.2.update.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+insert into samptable1 ({'id' : 0});
+
+insert into samptable1 ({'id' : 1});
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.3.query.sqlpp
new file mode 100644
index 0000000..8a7804f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/query-ASTERIXDB-1576/query-ASTERIXDB-1576.3.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+// Negative test for duplicate alias names.
+select *
+from samptable1, samptable1, samptable1
+;
\ 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 5100f52..912b592 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -67,6 +67,24 @@
         <output-dir compare="Text">query-ASTERIXDB-883</output-dir>
       </compilation-unit>
     </test-case>
+    <test-case FilePath="flwor">
+      <compilation-unit name="query-ASTERIXDB-1576">
+        <output-dir compare="Text">query-ASTERIXDB-883</output-dir>
+        <expected-error>Duplicate alias definitions: samptable1</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="flwor">
+      <compilation-unit name="query-ASTERIXDB-1576-2">
+        <output-dir compare="Text">query-ASTERIXDB-883</output-dir>
+        <expected-error>Duplicate alias definitions: s2</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="flwor">
+      <compilation-unit name="query-ASTERIXDB-1576-3">
+        <output-dir compare="Text">query-ASTERIXDB-883</output-dir>
+        <expected-error>Duplicate alias definitions: s1</expected-error>
+      </compilation-unit>
+    </test-case>
   </test-group>
   <test-group name="explain">
     <test-case FilePath="explain">
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 97cad5e..ad277d3 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
@@ -225,6 +225,11 @@
         return vars;
     }
 
+    // Returns local symbols within the current scope.
+    public Set<String> getLocalSymbols() {
+        return symbols.keySet();
+    }
+
     public Scope getParentScope(){
         return parent;
     }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/struct/VarIdentifier.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/struct/VarIdentifier.java
index c2a6f38..ca165ac 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/struct/VarIdentifier.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/struct/VarIdentifier.java
@@ -84,4 +84,9 @@
         VarIdentifier vid = (VarIdentifier) obj;
         return ObjectUtils.equals(value, vid.value);
     }
+
+    @Override
+    public String toString() {
+        return value;
+    }
 }
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 c13f00d..9c3e1fb 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
@@ -22,8 +22,8 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
+import java.util.Map.Entry;
 
 import org.apache.asterix.common.config.MetadataConstants;
 import org.apache.asterix.common.exceptions.AsterixException;
@@ -80,9 +80,13 @@
 
     @Override
     public Expression visit(FromClause fromClause, ILangExpression arg) throws AsterixException {
-        scopeChecker.extendCurrentScope();
+        Scope scopeForFromClause = scopeChecker.extendCurrentScope();
         for (FromTerm fromTerm : fromClause.getFromTerms()) {
             fromTerm.accept(this, fromClause);
+
+            // Merges the variables defined in the current from term into the scope of the current from clause.
+            Scope scopeForFromTerm = scopeChecker.removeCurrentScope();
+            mergeScopes(scopeForFromClause, scopeForFromTerm);
         }
         return null;
     }
@@ -95,12 +99,12 @@
 
         // Registers the data item variable.
         VariableExpr leftVar = fromTerm.getLeftVariable();
-        scopeChecker.getCurrentScope().addNewVarSymbolToScope(leftVar.getVar());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), leftVar.getVar());
 
         // Registers the positional variable
         if (fromTerm.hasPositionalVariable()) {
             VariableExpr posVar = fromTerm.getPositionalVariable();
-            scopeChecker.getCurrentScope().addNewVarSymbolToScope(posVar.getVar());
+            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), posVar.getVar());
         }
         // Visits join/unnest/nest clauses.
         for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
@@ -111,8 +115,7 @@
 
     @Override
     public Expression visit(JoinClause joinClause, ILangExpression arg) throws AsterixException {
-        Scope backupScope = scopeChecker.removeCurrentScope();
-        Scope parentScope = scopeChecker.getCurrentScope();
+        Scope leftScope = scopeChecker.removeCurrentScope();
         scopeChecker.createNewScope();
         // NOTE: the two join branches cannot be correlated, instead of checking
         // the correlation here,
@@ -121,19 +124,17 @@
 
         // Registers the data item variable.
         VariableExpr rightVar = joinClause.getRightVariable();
-        scopeChecker.getCurrentScope().addNewVarSymbolToScope(rightVar.getVar());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar());
 
         if (joinClause.hasPositionalVariable()) {
             // Registers the positional variable.
             VariableExpr posVar = joinClause.getPositionalVariable();
-            scopeChecker.getCurrentScope().addNewVarSymbolToScope(posVar.getVar());
+            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), posVar.getVar());
         }
 
         Scope rightScope = scopeChecker.removeCurrentScope();
-        Scope mergedScope = new Scope(scopeChecker, parentScope);
-        mergedScope.merge(backupScope);
-        mergedScope.merge(rightScope);
-        scopeChecker.pushExistingScope(mergedScope);
+        mergeScopes(leftScope, rightScope);
+        scopeChecker.pushExistingScope(leftScope);
         // The condition expression can refer to the just registered variables
         // for the right branch.
         joinClause.setConditionExpression(visit(joinClause.getConditionExpression(), joinClause));
@@ -149,12 +150,12 @@
 
         // Registers the data item variable.
         VariableExpr rightVar = nestClause.getRightVariable();
-        scopeChecker.getCurrentScope().addNewVarSymbolToScope(rightVar.getVar());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar());
 
         if (nestClause.hasPositionalVariable()) {
             // Registers the positional variable.
             VariableExpr posVar = nestClause.getPositionalVariable();
-            scopeChecker.getCurrentScope().addNewVarSymbolToScope(posVar.getVar());
+            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), posVar.getVar());
         }
 
         // The condition expression can refer to the just registered variables
@@ -169,12 +170,12 @@
 
         // register the data item variable
         VariableExpr rightVar = unnestClause.getRightVariable();
-        scopeChecker.getCurrentScope().addNewVarSymbolToScope(rightVar.getVar());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), rightVar.getVar());
 
         if (unnestClause.hasPositionalVariable()) {
             // register the positional variable
             VariableExpr posVar = unnestClause.getPositionalVariable();
-            scopeChecker.getCurrentScope().addNewVarSymbolToScope(posVar.getVar());
+            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), posVar.getVar());
         }
         return null;
     }
@@ -227,7 +228,7 @@
             gbyKeyVarExpr.setExpr(visit(gbyKeyVarExpr.getExpr(), gc));
             VariableExpr gbyKeyVar = gbyKeyVarExpr.getVar();
             if (gbyKeyVar != null) {
-                newScope.addNewVarSymbolToScope(gbyKeyVar.getVar());
+                addNewVarSymbolToScope(newScope, gbyKeyVar.getVar());
             }
         }
         if (gc.hasGroupFieldList()) {
@@ -240,12 +241,12 @@
                 decorVarExpr.setExpr(visit(decorVarExpr.getExpr(), gc));
                 VariableExpr decorVar = decorVarExpr.getVar();
                 if (decorVar != null) {
-                    newScope.addNewVarSymbolToScope(decorVar.getVar());
+                    addNewVarSymbolToScope(newScope, decorVar.getVar());
                 }
             }
         }
         if (gc.hasGroupVar()) {
-            scopeChecker.getCurrentScope().addNewVarSymbolToScope(gc.getGroupVar().getVar());
+            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), gc.getGroupVar().getVar());
         }
         if (gc.hasWithMap()) {
             Map<Expression, VariableExpr> newWithMap = new HashMap<>();
@@ -253,7 +254,7 @@
                 Expression expr = visit(entry.getKey(), arg);
                 Expression newKey = expr;
                 VariableExpr value = entry.getValue();
-                newScope.addNewVarSymbolToScope(value.getVar());
+                addNewVarSymbolToScope(newScope, value.getVar());
                 newWithMap.put(newKey, value);
             }
             gc.setWithVarMap(newWithMap);
@@ -278,7 +279,7 @@
     public Expression visit(LetClause letClause, ILangExpression arg) throws AsterixException {
         scopeChecker.extendCurrentScope();
         letClause.setBindingExpr(visit(letClause.getBindingExpr(), letClause));
-        scopeChecker.getCurrentScope().addNewVarSymbolToScope(letClause.getVarExpr().getVar());
+        addNewVarSymbolToScope(scopeChecker.getCurrentScope(), letClause.getVarExpr().getVar());
         return null;
     }
 
@@ -334,7 +335,7 @@
         scopeChecker.createNewScope();
         for (QuantifiedPair pair : qe.getQuantifiedList()) {
             pair.setExpr(visit(pair.getExpr(), qe));
-            scopeChecker.getCurrentScope().addNewVarSymbolToScope(pair.getVarExpr().getVar());
+            addNewVarSymbolToScope(scopeChecker.getCurrentScope(), pair.getVarExpr().getVar());
         }
         qe.setSatisfiesExpr(visit(qe.getSatisfiesExpr(), qe));
         scopeChecker.removeCurrentScope();
@@ -368,4 +369,25 @@
         argList.addAll(liveVars);
         return new CallExpr(resolveFunction, argList);
     }
+
+    // Adds a new encountered alias identifier into a scope
+    private void addNewVarSymbolToScope(Scope scope, VarIdentifier var) throws AsterixException {
+        if (scope.findLocalSymbol(var.getValue()) != null) {
+            throw new AsterixException("Duplicate alias definitions: "
+                    + SqlppVariableUtil.toUserDefinedName(var.getValue()));
+        }
+        scope.addNewVarSymbolToScope(var);
+    }
+
+    // Merges <code>scopeToBeMerged</code> into <code>hostScope</code>.
+    private void mergeScopes(Scope hostScope, Scope scopeToBeMerged) throws AsterixException {
+        Set<String> symbolsToBeMerged = scopeToBeMerged.getLocalSymbols();
+        for (String symbolToBeMerged : symbolsToBeMerged) {
+            if (hostScope.findLocalSymbol(symbolToBeMerged) != null) {
+                throw new AsterixException("Duplicate alias definitions: "
+                        + SqlppVariableUtil.toUserDefinedName(symbolToBeMerged));
+            }
+        }
+        hostScope.merge(scopeToBeMerged);
+    }
 }