SQL++ support in AsterixDB:
1. implemented SQL++ expression to logical plan translator;
2. refactored REST API to be agnostic of query languages;
3. disabled fuzzy join queries for SQL++ runtime tests;
4. fixed several rewriting rules.

Change-Id: I82919c4527b304325059519d819a2c30cf2902a9
Reviewed-on: https://asterix-gerrit.ics.uci.edu/479
Reviewed-by: Till Westmann <tillw@apache.org>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/clause/DistinctClause.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/clause/DistinctClause.java
index 789c5bd..9ee86e2 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/clause/DistinctClause.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/clause/DistinctClause.java
@@ -38,6 +38,10 @@
         return distinctByExprs;
     }
 
+    public void setDistinctByExpr(List<Expression> exprList) {
+        this.distinctByExprs = exprList;
+    }
+
     @Override
     public ClauseType getClauseType() {
         return ClauseType.DISTINCT_BY_CLAUSE;
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/AQLParserFactory.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/AQLParserFactory.java
new file mode 100644
index 0000000..41ca142
--- /dev/null
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/AQLParserFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.aql.parser;
+
+import java.io.Reader;
+
+import org.apache.asterix.lang.common.base.IParser;
+import org.apache.asterix.lang.common.base.IParserFactory;
+
+public class AQLParserFactory implements IParserFactory {
+
+    @Override
+    public IParser createParser(String query) {
+        return new AQLParser(query);
+    }
+
+    @Override
+    public IParser createParser(Reader reader) {
+        return new AQLParser(reader);
+    }
+
+}
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/FunctionUtils.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/FunctionParser.java
similarity index 69%
rename from asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/FunctionUtils.java
rename to asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/FunctionParser.java
index 2f326ae..96086a1 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/FunctionUtils.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/FunctionParser.java
@@ -17,28 +17,29 @@
  * under the License.
  */
 
-package org.apache.asterix.lang.aql.util;
+package org.apache.asterix.lang.aql.parser;
 
 import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.asterix.common.exceptions.AsterixException;
-import org.apache.asterix.common.functions.FunctionSignature;
-import org.apache.asterix.lang.aql.parser.AQLParser;
+import org.apache.asterix.lang.common.base.IParser;
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.Statement;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.asterix.metadata.entities.Function;
-import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
-import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
-import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
 
-public class FunctionUtils {
+public class FunctionParser {
 
-    public static final String IMPORT_PRIVATE_FUNCTIONS = "import-private-functions";
+    private final IParserFactory parserFactory;
 
-    public static FunctionDecl getFunctionDecl(Function function) throws AsterixException {
+    public FunctionParser(IParserFactory parserFactory) {
+        this.parserFactory = parserFactory;
+    }
+
+    public FunctionDecl getFunctionDecl(Function function) throws AsterixException {
         String functionBody = function.getFunctionBody();
         List<String> params = function.getParams();
         List<VarIdentifier> varIdentifiers = new ArrayList<VarIdentifier>();
@@ -63,19 +64,10 @@
         builder.append("\n");
         builder.append("}");
 
-        AQLParser parser = new AQLParser(new StringReader(new String(builder)));
-
+        IParser parser = parserFactory.createParser(new StringReader(new String(builder)));
         List<Statement> statements = parser.parse();
         FunctionDecl decl = (FunctionDecl) statements.get(1);
         return decl;
     }
 
-    public static IFunctionInfo getFunctionInfo(FunctionIdentifier fi) {
-        return AsterixBuiltinFunctions.getAsterixFunctionInfo(fi);
-    }
-
-    public static IFunctionInfo getFunctionInfo(FunctionSignature fs) {
-        return getFunctionInfo(new FunctionIdentifier(fs.getNamespace(), fs.getName(), fs.getArity()));
-    }
-
 }
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AQLRewriterFactory.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AQLRewriterFactory.java
new file mode 100644
index 0000000..87885b8
--- /dev/null
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AQLRewriterFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.aql.rewrites;
+
+import org.apache.asterix.lang.common.base.IQueryRewriter;
+import org.apache.asterix.lang.common.base.IRewriterFactory;
+import org.apache.asterix.lang.common.base.IStatementRewriter;
+
+public class AQLRewriterFactory implements IRewriterFactory {
+
+    @Override
+    public IQueryRewriter createQueryRewriter() {
+        return new AqlQueryRewriter();
+    }
+
+    @Override
+    public IStatementRewriter createStatementRewriter() {
+        return new AqlStatementRewriter();
+    }
+
+}
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlRewriter.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
similarity index 86%
rename from asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlRewriter.java
rename to asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
index dc99549..263cf9c 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlRewriter.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
@@ -28,12 +28,14 @@
 import org.apache.asterix.lang.aql.clause.ForClause;
 import org.apache.asterix.lang.aql.expression.FLWOGRExpression;
 import org.apache.asterix.lang.aql.expression.UnionExpr;
-import org.apache.asterix.lang.aql.util.FunctionUtils;
+import org.apache.asterix.lang.aql.parser.AQLParserFactory;
+import org.apache.asterix.lang.aql.parser.FunctionParser;
 import org.apache.asterix.lang.aql.visitor.AQLInlineUdfsVisitor;
 import org.apache.asterix.lang.aql.visitor.base.IAQLVisitor;
 import org.apache.asterix.lang.common.base.Clause;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.Expression.Kind;
+import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.clause.GroupbyClause;
 import org.apache.asterix.lang.common.clause.LetClause;
 import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair;
@@ -42,6 +44,7 @@
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.statement.Query;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
+import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.lang.common.visitor.GatherFunctionCallsVisitor;
 import org.apache.asterix.metadata.MetadataManager;
 import org.apache.asterix.metadata.MetadataTransactionContext;
@@ -49,33 +52,33 @@
 import org.apache.asterix.metadata.entities.Function;
 import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
 
-public final class AqlRewriter {
+class AqlQueryRewriter implements IQueryRewriter {
 
-    private final Query topExpr;
-    private final List<FunctionDecl> declaredFunctions;
-    private final LangRewritingContext context;
-    private final MetadataTransactionContext mdTxnCtx;
-    private final AqlMetadataProvider metadataProvider;
+    private final FunctionParser functionParser = new FunctionParser(new AQLParserFactory());
+    private Query topExpr;
+    private List<FunctionDecl> declaredFunctions;
+    private LangRewritingContext context;
+    private MetadataTransactionContext mdTxnCtx;
+    private AqlMetadataProvider metadataProvider;
 
-    public AqlRewriter(List<FunctionDecl> declaredFunctions, Query topExpr, AqlMetadataProvider metadataProvider) {
+    private void setup(List<FunctionDecl> declaredFunctions, Query topExpr, AqlMetadataProvider metadataProvider,
+            LangRewritingContext context) {
         this.topExpr = topExpr;
-        context = new LangRewritingContext(topExpr.getVarCounter());
+        this.context = context;
         this.declaredFunctions = declaredFunctions;
         this.mdTxnCtx = metadataProvider.getMetadataTxnContext();
         this.metadataProvider = metadataProvider;
     }
 
-    public Query getExpr() {
-        return topExpr;
-    }
-
-    public int getVarCounter() {
-        return context.getVarCounter();
-    }
-
-    public void rewrite() throws AsterixException {
-        wrapInLets();
+    @Override
+    public void rewrite(List<FunctionDecl> declaredFunctions, Query topExpr, AqlMetadataProvider metadataProvider,
+            LangRewritingContext context) throws AsterixException {
+        setup(declaredFunctions, topExpr, metadataProvider, context);
+        if (topExpr.isTopLevel()) {
+            wrapInLets();
+        }
         inlineDeclaredUdfs();
+        topExpr.setVarCounter(context.getVarCounter());
     }
 
     private void wrapInLets() {
@@ -109,7 +112,8 @@
         buildOtherUdfs(topExpr.getBody(), otherFDecls, funIds);
         declaredFunctions.addAll(otherFDecls);
         if (!declaredFunctions.isEmpty()) {
-            AQLInlineUdfsVisitor visitor = new AQLInlineUdfsVisitor(context);
+            AQLInlineUdfsVisitor visitor = new AQLInlineUdfsVisitor(context, new AQLRewriterFactory(),
+                    declaredFunctions, metadataProvider);
             while (topExpr.accept(visitor, declaredFunctions)) {
                 // loop until no more changes
             }
@@ -122,7 +126,7 @@
         if (expression == null) {
             return;
         }
-        String value = metadataProvider.getConfig().get(FunctionUtils.IMPORT_PRIVATE_FUNCTIONS);
+        String value = metadataProvider.getConfig().get(FunctionUtil.IMPORT_PRIVATE_FUNCTIONS);
         boolean includePrivateFunctions = (value != null) ? Boolean.valueOf(value.toLowerCase()) : false;
         Set<FunctionSignature> functionCalls = getFunctionCalls(expression);
         for (FunctionSignature signature : functionCalls) {
@@ -147,7 +151,7 @@
             }
 
             if (function.getLanguage().equalsIgnoreCase(Function.LANGUAGE_AQL)) {
-                FunctionDecl functionDecl = FunctionUtils.getFunctionDecl(function);
+                FunctionDecl functionDecl = functionParser.getFunctionDecl(function);
                 if (functionDecl != null) {
                     if (functionDecls.contains(functionDecl)) {
                         throw new AsterixException("ERROR:Recursive invocation "
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java
new file mode 100644
index 0000000..b9566f4
--- /dev/null
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.aql.rewrites;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.aql.visitor.AqlDeleteRewriteVisitor;
+import org.apache.asterix.lang.common.base.IStatementRewriter;
+import org.apache.asterix.lang.common.base.Statement;
+
+class AqlStatementRewriter implements IStatementRewriter {
+
+    @Override
+    public void rewrite(Statement stmt) throws AsterixException {
+        rewriteDeleteStatement(stmt);
+    }
+
+    private void rewriteDeleteStatement(Statement stmt) throws AsterixException {
+        if (stmt != null) {
+            AqlDeleteRewriteVisitor visitor = new AqlDeleteRewriteVisitor();
+            stmt.accept(visitor, null);
+        }
+    }
+}
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java
index a86c409..e6f1999 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java
@@ -29,12 +29,13 @@
 import org.apache.asterix.common.feeds.FeedId;
 import org.apache.asterix.common.feeds.FeedPolicyAccessor;
 import org.apache.asterix.common.functions.FunctionSignature;
-import org.apache.asterix.lang.aql.parser.AQLParser;
-import org.apache.asterix.lang.aql.parser.ParseException;
-import org.apache.asterix.lang.aql.util.FunctionUtils;
+import org.apache.asterix.lang.aql.parser.AQLParserFactory;
+import org.apache.asterix.lang.common.base.IParser;
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.Statement;
 import org.apache.asterix.lang.common.statement.InsertStatement;
 import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
 import org.apache.asterix.metadata.MetadataException;
 import org.apache.asterix.metadata.MetadataManager;
@@ -63,6 +64,7 @@
     private final String[] locations;
 
     public static final String WAIT_FOR_COMPLETION = "wait-for-completion-feed";
+    private final IParserFactory parserFactory = new AQLParserFactory();
 
     public SubscribeFeedStatement(String[] locations, FeedConnectionRequest subscriptionRequest) {
         this.connectionRequest = subscriptionRequest;
@@ -95,7 +97,7 @@
 
         StringBuilder builder = new StringBuilder();
         builder.append("use dataverse " + sourceFeedId.getDataverse() + ";\n");
-        builder.append("set" + " " + FunctionUtils.IMPORT_PRIVATE_FUNCTIONS + " " + "'" + Boolean.TRUE + "'" + ";\n");
+        builder.append("set" + " " + FunctionUtil.IMPORT_PRIVATE_FUNCTIONS + " " + "'" + Boolean.TRUE + "'" + ";\n");
         builder.append("set" + " " + FeedActivity.FeedActivityDetails.FEED_POLICY_NAME + " " + "'"
                 + connectionRequest.getPolicy() + "'" + ";\n");
 
@@ -136,13 +138,13 @@
         if (LOGGER.isLoggable(Level.INFO)) {
             LOGGER.info("Connect feed statement translated to\n" + builder.toString());
         }
-        AQLParser parser = new AQLParser(new StringReader(builder.toString()));
+        IParser parser = parserFactory.createParser(new StringReader(builder.toString()));
 
         List<Statement> statements;
         try {
-            statements = parser.Statement();
+            statements = parser.parse();
             query = ((InsertStatement) statements.get(3)).getQuery();
-        } catch (ParseException pe) {
+        } catch (AsterixException pe) {
             throw new MetadataException(pe);
         }
 
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/AQLVariableSubstitutionUtil.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/AQLVariableSubstitutionUtil.java
index 06e6fa7..717eb5c 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/AQLVariableSubstitutionUtil.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/AQLVariableSubstitutionUtil.java
@@ -18,8 +18,6 @@
  */
 package org.apache.asterix.lang.aql.util;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.asterix.common.exceptions.AsterixException;
@@ -32,18 +30,6 @@
 
 public class AQLVariableSubstitutionUtil {
 
-    public static List<ILangExpression> substituteVariable(List<ILangExpression> expressions,
-            Map<VariableExpr, Expression> varExprMap) throws AsterixException {
-        AQLCloneAndSubstituteVariablesVisitor visitor = new AQLCloneAndSubstituteVariablesVisitor(
-                new LangRewritingContext(0));
-        VariableSubstitutionEnvironment env = new VariableSubstitutionEnvironment(varExprMap);
-        List<ILangExpression> newExprs = new ArrayList<ILangExpression>();
-        for (ILangExpression expression : expressions) {
-            newExprs.add(expression.accept(visitor, env).first);
-        }
-        return newExprs;
-    }
-
     public static ILangExpression substituteVariable(ILangExpression expression,
             Map<VariableExpr, Expression> varExprMap) throws AsterixException {
         AQLCloneAndSubstituteVariablesVisitor visitor = new AQLCloneAndSubstituteVariablesVisitor(
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/RangeMapBuilder.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/RangeMapBuilder.java
index a15fb45..2fc4b14 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/RangeMapBuilder.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/util/RangeMapBuilder.java
@@ -24,9 +24,11 @@
 import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.formats.nontagged.AqlBinaryComparatorFactoryProvider;
 import org.apache.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
-import org.apache.asterix.lang.aql.parser.AQLParser;
+import org.apache.asterix.lang.aql.parser.AQLParserFactory;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.Expression.Kind;
+import org.apache.asterix.lang.common.base.IParser;
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.Literal;
 import org.apache.asterix.lang.common.base.Statement;
 import org.apache.asterix.lang.common.expression.ListConstructor;
@@ -54,13 +56,14 @@
 import org.apache.hyracks.dataflow.common.data.partition.range.RangeMap;
 
 public abstract class RangeMapBuilder {
+    private static final IParserFactory parserFactory = new AQLParserFactory();
 
     public static IRangeMap parseHint(Object hint) throws AsterixException {
         ArrayBackedValueStorage abvs = new ArrayBackedValueStorage();
         DataOutput out = abvs.getDataOutput();;
         abvs.reset();
 
-        AQLParser parser = new AQLParser((String) hint);
+        IParser parser = parserFactory.createParser((String) hint);
         List<Statement> hintStatements = parser.parse();
         if (hintStatements.size() != 1) {
             throw new AsterixException("Only one range statement is allowed for the range hint.");
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLPrintVisitor.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitor.java
similarity index 94%
rename from asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLPrintVisitor.java
rename to asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitor.java
index 2798ef8..0636114 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLPrintVisitor.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitor.java
@@ -30,16 +30,16 @@
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.visitor.QueryPrintVisitor;
 
-public class AQLPrintVisitor extends QueryPrintVisitor implements IAQLVisitor<Void, Integer> {
+class AQLAstPrintVisitor extends QueryPrintVisitor implements IAQLVisitor<Void, Integer> {
 
     private final PrintWriter out;
 
-    public AQLPrintVisitor() {
+    public AQLAstPrintVisitor() {
         super();
         out = new PrintWriter(System.out);
     }
 
-    public AQLPrintVisitor(PrintWriter out) {
+    public AQLAstPrintVisitor(PrintWriter out) {
         super(out);
         this.out = out;
     }
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitorFactory.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitorFactory.java
new file mode 100644
index 0000000..ff76fee
--- /dev/null
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitorFactory.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.aql.visitor;
+
+import java.io.PrintWriter;
+
+import org.apache.asterix.lang.common.base.IAstPrintVisitorFactory;
+import org.apache.asterix.lang.common.visitor.QueryPrintVisitor;
+
+public class AQLAstPrintVisitorFactory implements IAstPrintVisitorFactory {
+
+    @Override
+    public QueryPrintVisitor createLangVisitor(PrintWriter writer) {
+        return new AQLAstPrintVisitor(writer);
+    }
+
+}
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLCloneAndSubstituteVariablesVisitor.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLCloneAndSubstituteVariablesVisitor.java
index 511354e..dfbf757 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLCloneAndSubstituteVariablesVisitor.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLCloneAndSubstituteVariablesVisitor.java
@@ -33,7 +33,7 @@
 import org.apache.asterix.lang.common.expression.VariableExpr;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.rewrites.VariableSubstitutionEnvironment;
-import org.apache.asterix.lang.common.utils.VariableCloneAndSubstitutionUtil;
+import org.apache.asterix.lang.common.util.VariableCloneAndSubstitutionUtil;
 import org.apache.asterix.lang.common.visitor.CloneAndSubstituteVariablesVisitor;
 import org.apache.hyracks.algebricks.common.utils.Pair;
 
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLInlineUdfsVisitor.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLInlineUdfsVisitor.java
index b53d888..dd1a1fb 100644
--- a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLInlineUdfsVisitor.java
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLInlineUdfsVisitor.java
@@ -29,17 +29,21 @@
 import org.apache.asterix.lang.aql.visitor.base.IAQLVisitor;
 import org.apache.asterix.lang.common.base.Clause;
 import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.IRewriterFactory;
 import org.apache.asterix.lang.common.clause.LetClause;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.visitor.AbstractInlineUdfsVisitor;
+import org.apache.asterix.metadata.declared.AqlMetadataProvider;
 import org.apache.hyracks.algebricks.common.utils.Pair;
 
 public class AQLInlineUdfsVisitor extends AbstractInlineUdfsVisitor
         implements IAQLVisitor<Boolean, List<FunctionDecl>> {
 
-    public AQLInlineUdfsVisitor(LangRewritingContext context) {
-        super(context, new AQLCloneAndSubstituteVariablesVisitor(context));
+    public AQLInlineUdfsVisitor(LangRewritingContext context, IRewriterFactory rewriterFactory,
+            List<FunctionDecl> declaredFunctions, AqlMetadataProvider metadataProvider) {
+        super(context, rewriterFactory, declaredFunctions, metadataProvider,
+                new AQLCloneAndSubstituteVariablesVisitor(context));
     }
 
     @Override
@@ -71,11 +75,9 @@
 
     @Override
     public Boolean visit(DistinctClause dc, List<FunctionDecl> arg) throws AsterixException {
-        boolean changed = false;
-        for (Expression expr : dc.getDistinctByExpr()) {
-            changed = expr.accept(this, arg);
-        }
-        return changed;
+        Pair<Boolean, ArrayList<Expression>> p = inlineUdfsInExprList(dc.getDistinctByExpr(), arg);
+        dc.setDistinctByExpr(p.second);
+        return p.first;
     }
 
     @Override
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java
new file mode 100644
index 0000000..cedeb77
--- /dev/null
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.aql.visitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.common.functions.FunctionConstants;
+import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.lang.aql.clause.ForClause;
+import org.apache.asterix.lang.aql.expression.FLWOGRExpression;
+import org.apache.asterix.lang.aql.visitor.base.AbstractAqlAstVisitor;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.clause.WhereClause;
+import org.apache.asterix.lang.common.expression.CallExpr;
+import org.apache.asterix.lang.common.expression.LiteralExpr;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.literal.StringLiteral;
+import org.apache.asterix.lang.common.statement.DeleteStatement;
+import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.struct.Identifier;
+
+public class AqlDeleteRewriteVisitor extends AbstractAqlAstVisitor<Void, Void> {
+
+    @Override
+    public Void visit(DeleteStatement deleteStmt, Void visitArg) {
+        List<Expression> arguments = new ArrayList<Expression>();
+        Identifier dataverseName = deleteStmt.getDataverseName();
+        Identifier datasetName = deleteStmt.getDatasetName();
+        String arg = dataverseName == null ? datasetName.getValue()
+                : dataverseName.getValue() + "." + datasetName.getValue();
+        LiteralExpr argumentLiteral = new LiteralExpr(new StringLiteral(arg));
+        arguments.add(argumentLiteral);
+        CallExpr callExpression = new CallExpr(new FunctionSignature(FunctionConstants.ASTERIX_NS, "dataset", 1),
+                arguments);
+
+        List<Clause> clauseList = new ArrayList<Clause>();
+        VariableExpr var = deleteStmt.getVariableExpr();
+        Clause forClause = new ForClause(var, callExpression);
+        clauseList.add(forClause);
+        Clause whereClause = null;
+        Expression condition = deleteStmt.getCondition();
+        if (condition != null) {
+            whereClause = new WhereClause(condition);
+            clauseList.add(whereClause);
+        }
+        VariableExpr returnExpr = new VariableExpr(var.getVar());
+        returnExpr.setIsNewVar(false);
+        FLWOGRExpression flowgr = new FLWOGRExpression(clauseList, returnExpr);
+        Query query = new Query();
+        query.setBody(flowgr);
+        deleteStmt.setQuery(query);
+        return null;
+    }
+
+}
diff --git a/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlAstVisitor.java b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlAstVisitor.java
new file mode 100644
index 0000000..05c1b81
--- /dev/null
+++ b/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlAstVisitor.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.aql.visitor.base;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.aql.clause.DistinctClause;
+import org.apache.asterix.lang.aql.clause.ForClause;
+import org.apache.asterix.lang.aql.expression.FLWOGRExpression;
+import org.apache.asterix.lang.aql.expression.UnionExpr;
+import org.apache.asterix.lang.common.visitor.base.AbstractAstVisitor;
+
+public abstract class AbstractAqlAstVisitor<R, T> extends AbstractAstVisitor<R, T> implements IAQLVisitor<R, T> {
+
+    @Override
+    public R visit(FLWOGRExpression flwogreExpr, T arg) throws AsterixException {
+        return null;
+    }
+
+    @Override
+    public R visit(UnionExpr u, T arg) throws AsterixException {
+        return null;
+    }
+
+    @Override
+    public R visit(ForClause forClause, T arg) throws AsterixException {
+        return null;
+    }
+
+    @Override
+    public R visit(DistinctClause distinctClause, T arg) throws AsterixException {
+        return null;
+    }
+
+}
diff --git a/asterix-lang-aql/src/main/javacc/AQL.jj b/asterix-lang-aql/src/main/javacc/AQL.jj
index bb574d0..78c9abd 100644
--- a/asterix-lang-aql/src/main/javacc/AQL.jj
+++ b/asterix-lang-aql/src/main/javacc/AQL.jj
@@ -135,7 +135,7 @@
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 
 
-public class AQLParser extends ScopeChecker implements IParser {
+class AQLParser extends ScopeChecker implements IParser {
 
     // optimizer hints
     private static final String AUTO_HINT = "auto";
@@ -886,7 +886,7 @@
 {
   "insert" "into" <DATASET> nameComponents = QualifiedName() query = Query()
     {
-      query.setTopLevel(false);
+      query.setTopLevel(true);
       return new InsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter());
     }
 }