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 2021/07/15 20:02:45 UTC

[asterixdb] branch master updated: [NO ISSUE][COMP] Support views

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 793c39e  [NO ISSUE][COMP] Support views
793c39e is described below

commit 793c39ef5840f190f2d48cf4052b20f33101f248
Author: Dmitry Lychagin <dm...@couchbase.com>
AuthorDate: Wed Apr 21 16:52:10 2021 -0700

    [NO ISSUE][COMP] Support views
    
    - user model changes: yes
    - storage format changes: no
    - interface changes: no
    
    Details:
    - Add CREATE VIEW, DROP VIEW statements
    - Add testcases
    - Update documentation
    
    Change-Id: I802415e56b3a15265c47142fe8986959d6bec266
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/11124
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Ali Alsuliman <al...@gmail.com>
---
 .../asterix/translator/AbstractLangTranslator.java |  12 +
 .../asterix/translator/IStatementExecutor.java     |   6 +-
 .../translator/LangExpressionToPlanTranslator.java |  14 +-
 .../apache/asterix/api/common/APIFramework.java    |  13 +-
 .../api/http/server/RebalanceApiServlet.java       |  20 +-
 .../asterix/app/function/DatasetRewriter.java      |  32 ++-
 .../asterix/app/translator/QueryTranslator.java    | 265 ++++++++++++++++-----
 .../hyracks/bootstrap/GlobalRecoveryManager.java   |   4 +-
 .../org/apache/asterix/utils/FeedOperations.java   |   2 +-
 .../org/apache/asterix/utils/RebalanceUtil.java    |   2 +-
 .../asterix/test/sqlpp/ParserTestExecutor.java     |  19 +-
 .../exception_create_system_view.1.ddl.sqlpp}      |  26 +-
 .../src/test/resources/metadata/testsuite.xml      |   6 +
 .../invalid-view-name.1.ddl.sqlpp}                 |  29 +--
 .../invalid-view-name.2.ddl.sqlpp}                 |  29 +--
 .../invalid-view-name.3.ddl.sqlpp}                 |  29 +--
 .../invalid-view-name.4.ddl.sqlpp}                 |  29 +--
 .../invalid-view-name.5.ddl.sqlpp}                 |  29 +--
 .../multipart-dataverse/view_1/view_1.1.ddl.sqlpp} |  30 +--
 .../view_1/view_1.2.query.sqlpp}                   |  30 +--
 .../view_1/view_1.3.query.sqlpp}                   |  31 +--
 .../view/create-view-1/create-view-1.1.ddl.sqlpp   |  68 ++++++
 .../view/create-view-1/create-view-1.10.ddl.sqlpp} |  26 +-
 .../create-view-1/create-view-1.11.query.sqlpp}    |  25 +-
 .../create-view-1/create-view-1.12.query.sqlpp}    |  29 +--
 .../create-view-1/create-view-1.2.query.sqlpp}     |  25 +-
 .../create-view-1/create-view-1.3.query.sqlpp}     |  29 +--
 .../view/create-view-1/create-view-1.4.ddl.sqlpp}  |  26 +-
 .../create-view-1/create-view-1.5.query.sqlpp}     |  25 +-
 .../create-view-1/create-view-1.6.query.sqlpp}     |  29 +--
 .../view/create-view-1/create-view-1.7.ddl.sqlpp}  |  26 +-
 .../create-view-1/create-view-1.8.query.sqlpp}     |  25 +-
 .../create-view-1/create-view-1.9.query.sqlpp}     |  29 +--
 .../create-view-2-negative.1.ddl.sqlpp}            |  25 +-
 .../create-view-2-negative.10.ddl.sqlpp}           |  29 +--
 .../create-view-2-negative.11.ddl.sqlpp}           |  31 +--
 .../create-view-2-negative.2.ddl.sqlpp}            |  26 +-
 .../create-view-2-negative.3.ddl.sqlpp}            |  26 +-
 .../create-view-2-negative.4.ddl.sqlpp}            |  27 +--
 .../create-view-2-negative.5.ddl.sqlpp}            |  29 +--
 .../create-view-2-negative.6.ddl.sqlpp}            |  29 +--
 .../create-view-2-negative.7.ddl.sqlpp}            |  29 +--
 .../create-view-2-negative.8.ddl.sqlpp}            |  27 +--
 .../create-view-2-negative.9.ddl.sqlpp}            |  28 +--
 .../drop-dataverse-1/drop-dataverse-1.1.ddl.sqlpp} |  28 +--
 .../drop-dataverse-2-negative.1.ddl.sqlpp}         |  29 +--
 .../drop-dataverse-2-negative.2.ddl.sqlpp}         |  29 +--
 .../drop-dataverse-2-negative.3.ddl.sqlpp}         |  29 +--
 .../drop-dataverse-2-negative.4.ddl.sqlpp}         |  29 +--
 .../drop-dataverse-2-negative.5.ddl.sqlpp}         |  31 +--
 .../view/drop-view-1/drop-view-1.1.ddl.sqlpp}      |  37 ++-
 .../view/drop-view-1/drop-view-1.2.query.sqlpp}    |  27 +--
 .../drop-view-2-negative.1.ddl.sqlpp}              |  25 +-
 .../drop-view-2-negative.10.query.sqlpp}           |  25 +-
 .../drop-view-2-negative.11.ddl.sqlpp}             |  33 ++-
 .../drop-view-2-negative.12.query.sqlpp}           |  25 +-
 .../drop-view-2-negative.13.ddl.sqlpp}             |  29 +--
 .../drop-view-2-negative.14.query.sqlpp}           |  25 +-
 .../drop-view-2-negative.15.ddl.sqlpp}             |  30 +--
 .../drop-view-2-negative.16.query.sqlpp}           |  25 +-
 .../drop-view-2-negative.2.ddl.sqlpp}              |  26 +-
 .../drop-view-2-negative.3.ddl.sqlpp}              |  26 +-
 .../drop-view-2-negative.4.query.sqlpp}            |  25 +-
 .../drop-view-2-negative.5.ddl.sqlpp}              |  29 +--
 .../drop-view-2-negative.6.query.sqlpp}            |  25 +-
 .../drop-view-2-negative.7.ddl.sqlpp}              |  31 +--
 .../drop-view-2-negative.8.query.sqlpp}            |  25 +-
 .../drop-view-2-negative.9.ddl.sqlpp}              |  30 +--
 .../queries_sqlpp/view/view-1/view-1.1.ddl.sqlpp}  |  39 +--
 .../view/view-1/view-1.2.update.sqlpp}             |  25 +-
 .../view/view-1/view-1.3.query.sqlpp}              |  25 +-
 .../view/view-1/view-1.4.query.sqlpp}              |  31 +--
 .../queries_sqlpp/view/view-1/view-1.5.ddl.sqlpp   |  74 ++++++
 .../view/view-1/view-1.6.update.sqlpp}             |  25 +-
 .../view/view-1/view-1.7.query.sqlpp}              |  28 +--
 .../view/view-1/view-1.8.query.sqlpp}              |  30 +--
 .../multipart-dataverse/view_1/view_1.2.adm        |   3 +
 .../multipart-dataverse/view_1/view_1.3.adm        |   2 +
 .../view/create-view-1/create-view-1.11.adm        |   2 +
 .../view/create-view-1/create-view-1.12.adm        |   1 +
 .../results/view/create-view-1/create-view-1.2.adm |   1 +
 .../results/view/create-view-1/create-view-1.3.adm |   3 +
 .../results/view/create-view-1/create-view-1.5.adm |   1 +
 .../results/view/create-view-1/create-view-1.6.adm |   1 +
 .../results/view/create-view-1/create-view-1.8.adm |   2 +
 .../results/view/create-view-1/create-view-1.9.adm |   1 +
 .../results/view/drop-view-1/drop-view-1.2.adm     |   1 +
 .../drop-view-2-negative.10.adm                    |   2 +
 .../drop-view-2-negative.12.adm                    |   1 +
 .../drop-view-2-negative.14.adm                    |   2 +
 .../drop-view-2-negative.16.adm                    |   2 +
 .../drop-view-2-negative.4.adm                     |   2 +
 .../drop-view-2-negative.6.adm                     |   1 +
 .../drop-view-2-negative.8.adm                     |   1 +
 .../runtimets/results/view/view-1/view-1.3.adm     |  10 +
 .../runtimets/results/view/view-1/view-1.4.adm     |   3 +
 .../runtimets/results/view/view-1/view-1.7.adm     |   1 +
 .../runtimets/results/view/view-1/view-1.8.adm     |   5 +
 .../resources/runtimets/testsuite_it_sqlpp.xml     |   2 +-
 .../test/resources/runtimets/testsuite_sqlpp.xml   |  96 +++++++-
 .../asterix/common/config/DatasetConfig.java       |   3 +-
 .../asterix/common/exceptions/ErrorCode.java       |   5 +-
 .../src/main/resources/asx_errormsg/en.properties  |   5 +-
 asterixdb/asterix-doc/src/main/grammar/sqlpp.ebnf  |   5 +-
 .../asterix-doc/src/main/markdown/sqlpp/0_toc.md   |   1 +
 .../src/main/markdown/sqlpp/7_ddl_dml.md           |  28 ++-
 .../main/markdown/sqlpp/appendix_3_resolution.md   |  11 +-
 .../apache/asterix/lang/common/base/IParser.java   |   4 +
 .../asterix/lang/common/base/IQueryRewriter.java   |  16 +-
 .../lang/common/base/IStatementRewriter.java       |   5 -
 .../apache/asterix/lang/common/base/Statement.java |   3 +
 .../lang/common/rewrites/LangRewritingContext.java |  25 +-
 .../lang/common/statement/CreateViewStatement.java |  94 ++++++++
 .../asterix/lang/common/statement/ViewDecl.java    |  88 +++++++
 .../lang/common/statement/ViewDropStatement.java   |  69 ++++++
 .../asterix/lang/common/util/ExpressionUtils.java  | 133 +++++++++++
 .../asterix/lang/common/util/FunctionUtil.java     | 131 +++-------
 .../apache/asterix/lang/common/util/ViewUtil.java  |  82 +++++++
 .../common/visitor/AbstractInlineUdfsVisitor.java  | 160 ++++++++-----
 .../lang/common/visitor/FormatPrintVisitor.java    |  29 +++
 .../common/visitor/GatherFunctionCallsVisitor.java |   6 -
 .../base/AbstractQueryExpressionVisitor.java       |  18 ++
 .../lang/common/visitor/base/ILangVisitor.java     |   9 +
 .../sqlpp/rewrites/SqlppFunctionBodyRewriter.java  |  13 +-
 .../rewrites/SqlppFunctionBodyRewriterFactory.java |  44 ----
 .../lang/sqlpp/rewrites/SqlppQueryRewriter.java    | 263 ++++++++++++++------
 .../sqlpp/rewrites/SqlppStatementRewriter.java     |  12 -
 .../rewrites/visitor/SqlppInlineUdfsVisitor.java   |  45 ++--
 .../visitor/VariableCheckAndRewriteVisitor.java    |  48 +++-
 .../asterix/lang/sqlpp/util/SqlppVariableUtil.java |   4 +
 .../lang/sqlpp/visitor/SqlppAstPrintVisitor.java   |   9 +-
 .../sqlpp/visitor/SqlppSynonymRewriteVisitor.java  |  11 +-
 .../asterix-lang-sqlpp/src/main/javacc/SQLPP.jj    | 115 ++++++++-
 .../org/apache/asterix/metadata/MetadataNode.java  | 221 ++++++++++++-----
 .../metadata/bootstrap/MetadataBootstrap.java      |   4 +
 .../metadata/bootstrap/MetadataRecordTypes.java    |   1 +
 .../metadata/declared/MetadataManagerUtil.java     |  39 ++-
 .../metadata/declared/MetadataProvider.java        |  18 +-
 .../apache/asterix/metadata/entities/Dataset.java  |   2 +-
 .../asterix/metadata/entities/DependencyKind.java  |  54 +++++
 .../apache/asterix/metadata/entities/Function.java |  35 +--
 .../asterix/metadata/entities/ViewDetails.java     | 153 ++++++++++++
 .../AbstractTupleTranslator.java                   |  30 +++
 .../DatasetTupleTranslator.java                    |  81 +++++--
 .../FunctionTupleTranslator.java                   |  32 +--
 .../apache/asterix/metadata/utils/DatasetUtil.java |  11 +-
 146 files changed, 2635 insertions(+), 1961 deletions(-)

diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AbstractLangTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AbstractLangTranslator.java
index 6f07718..ac7fabe 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AbstractLangTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AbstractLangTranslator.java
@@ -46,6 +46,7 @@ import org.apache.asterix.lang.common.statement.CreateFeedStatement;
 import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
 import org.apache.asterix.lang.common.statement.CreateLibraryStatement;
 import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
+import org.apache.asterix.lang.common.statement.CreateViewStatement;
 import org.apache.asterix.lang.common.statement.DatasetDecl;
 import org.apache.asterix.lang.common.statement.DataverseDropStatement;
 import org.apache.asterix.lang.common.statement.DeleteStatement;
@@ -341,6 +342,17 @@ public abstract class AbstractLangTranslator {
                 }
                 break;
 
+            case CREATE_VIEW:
+                CreateViewStatement viewCreateStmt = (CreateViewStatement) stmt;
+                if (viewCreateStmt.getDataverseName() != null) {
+                    dataverseName = viewCreateStmt.getDataverseName();
+                }
+                invalidOperation = isMetadataDataverse(dataverseName);
+                if (invalidOperation) {
+                    message = String.format(BAD_DATAVERSE_OBJECT_DDL_MESSAGE, "create", "view", dataverseName);
+                }
+                break;
+
             case CREATE_FEED:
                 CreateFeedStatement feedCreateStmt = (CreateFeedStatement) stmt;
                 if (feedCreateStmt.getDataverseName() != null) {
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IStatementExecutor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IStatementExecutor.java
index d60b791..8a91059 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IStatementExecutor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IStatementExecutor.java
@@ -36,7 +36,6 @@ import org.apache.asterix.common.api.IResponsePrinter;
 import org.apache.asterix.common.exceptions.ACIDException;
 import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.lang.common.base.IStatementRewriter;
 import org.apache.asterix.lang.common.base.Statement;
 import org.apache.asterix.lang.common.statement.Query;
 import org.apache.asterix.metadata.declared.MetadataProvider;
@@ -272,8 +271,6 @@ public interface IStatementExecutor {
      *            The data modification statement when the query results in a modification to a dataset
      * @param statementParameters
      *            Statement parameters
-     * @param statementRewriter
-     *            The statement rewriter
      * @param requestParameters
      *            The request parameters
      * @return the compiled {@code JobSpecification}
@@ -284,8 +281,7 @@ public interface IStatementExecutor {
      */
     JobSpecification rewriteCompileQuery(IClusterInfoCollector clusterInfoCollector, MetadataProvider metadataProvider,
             Query query, ICompiledDmlStatement dmlStatement, Map<String, IAObject> statementParameters,
-            IStatementRewriter statementRewriter, IRequestParameters requestParameters)
-            throws RemoteException, AlgebricksException, ACIDException;
+            IRequestParameters requestParameters) throws RemoteException, AlgebricksException, ACIDException;
 
     /**
      * returns the active dataverse for an entity or a statement
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index c053ab9..7f3644d 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -68,6 +68,7 @@ import org.apache.asterix.lang.common.expression.VariableExpr;
 import org.apache.asterix.lang.common.literal.StringLiteral;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.statement.ViewDecl;
 import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.struct.OperatorType;
 import org.apache.asterix.lang.common.struct.QuantifiedPair;
@@ -977,8 +978,17 @@ abstract class LangExpressionToPlanTranslator
     }
 
     @Override
-    public Pair<ILogicalOperator, LogicalVariable> visit(FunctionDecl fd, Mutable<ILogicalOperator> tupSource) {
-        throw new IllegalStateException("Function declarations should be inlined at AST rewriting phase.");
+    public Pair<ILogicalOperator, LogicalVariable> visit(FunctionDecl fd, Mutable<ILogicalOperator> tupSource)
+            throws CompilationException {
+        // Function declarations should be inlined at AST rewriting phase
+        throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, fd.getSourceLocation(), fd.getSignature());
+    }
+
+    @Override
+    public Pair<ILogicalOperator, LogicalVariable> visit(ViewDecl vd, Mutable<ILogicalOperator> tupSource)
+            throws CompilationException {
+        // View declarations should be inlined at AST rewriting phase
+        throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, vd.getSourceLocation(), vd.getViewName());
     }
 
     @Override
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
index 326ddcc..e46177a 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
@@ -64,6 +64,7 @@ import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.statement.Query;
 import org.apache.asterix.lang.common.statement.StartFeedStatement;
+import org.apache.asterix.lang.common.statement.ViewDecl;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.lang.sqlpp.rewrites.SqlppQueryRewriter;
@@ -186,9 +187,9 @@ public class APIFramework {
     }
 
     public Pair<IReturningStatement, Integer> reWriteQuery(List<FunctionDecl> declaredFunctions,
-            MetadataProvider metadataProvider, IReturningStatement q, SessionOutput output,
-            boolean allowNonStoredUdfCalls, boolean inlineUdfs, Collection<VarIdentifier> externalVars,
-            IWarningCollector warningCollector) throws CompilationException {
+            List<ViewDecl> declaredViews, MetadataProvider metadataProvider, IReturningStatement q,
+            SessionOutput output, boolean allowNonStoredUdfCalls, boolean inlineUdfsAndViews,
+            Collection<VarIdentifier> externalVars, IWarningCollector warningCollector) throws CompilationException {
         if (q == null) {
             return null;
         }
@@ -197,9 +198,9 @@ public class APIFramework {
             generateExpressionTree(q);
         }
         IQueryRewriter rw = rewriterFactory.createQueryRewriter();
-        LangRewritingContext rwCtx =
-                new LangRewritingContext(metadataProvider, declaredFunctions, warningCollector, q.getVarCounter());
-        rw.rewrite(rwCtx, q, allowNonStoredUdfCalls, inlineUdfs, externalVars);
+        LangRewritingContext rwCtx = new LangRewritingContext(metadataProvider, declaredFunctions, declaredViews,
+                warningCollector, q.getVarCounter());
+        rw.rewrite(rwCtx, q, allowNonStoredUdfCalls, inlineUdfsAndViews, externalVars);
         return new Pair<>(q, q.getVarCounter());
     }
 
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RebalanceApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RebalanceApiServlet.java
index f1652ea..58a37bd 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RebalanceApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RebalanceApiServlet.java
@@ -45,9 +45,12 @@ import org.apache.asterix.metadata.MetadataTransactionContext;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Dataverse;
+import org.apache.asterix.metadata.utils.DatasetUtil;
 import org.apache.asterix.metadata.utils.MetadataConstants;
 import org.apache.asterix.rebalance.NoOpDatasetRebalanceCallback;
 import org.apache.asterix.utils.RebalanceUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.api.client.IHyracksClientConnection;
 import org.apache.hyracks.http.api.IServletRequest;
@@ -181,7 +184,7 @@ public class RebalanceApiServlet extends AbstractServlet {
 
             if (datasetName == null) {
                 // Rebalances datasets in a given dataverse or all non-metadata datasets.
-                List<Dataset> datasets = dataverseName == null ? getAllDatasetsForRebalance()
+                Iterable<Dataset> datasets = dataverseName == null ? getAllDatasetsForRebalance()
                         : getAllDatasetsForRebalance(dataverseName);
                 for (Dataset dataset : datasets) {
                     // By the time rebalanceDataset(...) is called, the dataset could have been dropped.
@@ -212,8 +215,8 @@ public class RebalanceApiServlet extends AbstractServlet {
     }
 
     // Lists all datasets that should be rebalanced in a given datavserse.
-    private List<Dataset> getAllDatasetsForRebalance(DataverseName dataverseName) throws Exception {
-        List<Dataset> datasets;
+    private Iterable<Dataset> getAllDatasetsForRebalance(DataverseName dataverseName) throws Exception {
+        Iterable<Dataset> datasets;
         MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
         try {
             datasets = getDatasetsInDataverseForRebalance(dataverseName, mdTxnCtx);
@@ -226,13 +229,13 @@ public class RebalanceApiServlet extends AbstractServlet {
     }
 
     // Lists all datasets that should be rebalanced.
-    private List<Dataset> getAllDatasetsForRebalance() throws Exception {
+    private Iterable<Dataset> getAllDatasetsForRebalance() throws Exception {
         List<Dataset> datasets = new ArrayList<>();
         MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
         try {
             List<Dataverse> dataverses = MetadataManager.INSTANCE.getDataverses(mdTxnCtx);
             for (Dataverse dv : dataverses) {
-                datasets.addAll(getDatasetsInDataverseForRebalance(dv.getDataverseName(), mdTxnCtx));
+                CollectionUtils.addAll(datasets, getDatasetsInDataverseForRebalance(dv.getDataverseName(), mdTxnCtx));
             }
             MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
         } catch (Exception e) {
@@ -243,10 +246,11 @@ public class RebalanceApiServlet extends AbstractServlet {
     }
 
     // Gets all datasets in a dataverse for the rebalance operation, with a given metadata transaction context.
-    private List<Dataset> getDatasetsInDataverseForRebalance(DataverseName dvName, MetadataTransactionContext mdTxnCtx)
-            throws Exception {
+    private Iterable<Dataset> getDatasetsInDataverseForRebalance(DataverseName dvName,
+            MetadataTransactionContext mdTxnCtx) throws Exception {
         return MetadataConstants.METADATA_DATAVERSE_NAME.equals(dvName) ? Collections.emptyList()
-                : MetadataManager.INSTANCE.getDataverseDatasets(mdTxnCtx, dvName);
+                : IterableUtils.filteredIterable(MetadataManager.INSTANCE.getDataverseDatasets(mdTxnCtx, dvName),
+                        DatasetUtil::isNotView);
     }
 
     // Rebalances a given dataset.
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/function/DatasetRewriter.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/function/DatasetRewriter.java
index 6944b25..e25c530 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/function/DatasetRewriter.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/function/DatasetRewriter.java
@@ -24,15 +24,16 @@ import static org.apache.asterix.common.utils.IdentifierUtil.dataset;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.asterix.common.config.DatasetConfig.DatasetType;
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.metadata.declared.DataSource;
 import org.apache.asterix.metadata.declared.DataSourceId;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.entities.Dataset;
+import org.apache.asterix.metadata.utils.DatasetUtil;
 import org.apache.asterix.om.functions.IFunctionToDataSourceRewriter;
 import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
 import org.apache.asterix.om.types.ARecordType;
@@ -41,7 +42,6 @@ import org.apache.asterix.optimizer.rules.UnnestToDataScanRule;
 import org.apache.asterix.optimizer.rules.util.EquivalenceClassUtils;
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
 import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
@@ -75,15 +75,25 @@ public class DatasetRewriter implements IFunctionToDataSourceRewriter, IResultTy
 
         MetadataProvider metadataProvider = (MetadataProvider) context.getMetadataProvider();
         Dataset dataset = fetchDataset(metadataProvider, f);
-        DataSourceId dsid = new DataSourceId(dataset.getDataverseName(), dataset.getDatasetName());
         List<LogicalVariable> variables = new ArrayList<>();
-        if (dataset.getDatasetType() == DatasetType.INTERNAL) {
-            int numPrimaryKeys = dataset.getPrimaryKeys().size();
-            for (int i = 0; i < numPrimaryKeys; i++) {
-                variables.add(context.newVar());
-            }
+        switch (dataset.getDatasetType()) {
+            case INTERNAL:
+                int numPrimaryKeys = dataset.getPrimaryKeys().size();
+                for (int i = 0; i < numPrimaryKeys; i++) {
+                    variables.add(context.newVar());
+                }
+                break;
+            case EXTERNAL:
+                break;
+            default:
+                // VIEWS are not expected at this point
+                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, unnest.getSourceLocation(),
+                        "Unexpected dataset type " + dataset.getDatasetType() + " for dataset "
+                                + DatasetUtil.getFullyQualifiedDisplayName(dataset));
         }
         variables.add(unnest.getVariable());
+
+        DataSourceId dsid = new DataSourceId(dataset.getDataverseName(), dataset.getDatasetName());
         DataSource dataSource = metadataProvider.findDataSource(dsid);
         boolean hasMeta = dataSource.hasMeta();
         if (hasMeta) {
@@ -132,9 +142,9 @@ public class DatasetRewriter implements IFunctionToDataSourceRewriter, IResultTy
 
     public static Dataset fetchDataset(MetadataProvider metadataProvider, AbstractFunctionCallExpression datasetFnCall)
             throws CompilationException {
-        Pair<DataverseName, String> datasetReference = FunctionUtil.parseDatasetFunctionArguments(datasetFnCall);
-        DataverseName dataverseName = datasetReference.first;
-        String datasetName = datasetReference.second;
+        DatasetFullyQualifiedName datasetReference = FunctionUtil.parseDatasetFunctionArguments(datasetFnCall);
+        DataverseName dataverseName = datasetReference.getDataverseName();
+        String datasetName = datasetReference.getDatasetName();
         Dataset dataset;
         try {
             dataset = metadataProvider.findDataset(dataverseName, datasetName);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
index 1fab5d0..3571d88 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
@@ -85,6 +85,7 @@ import org.apache.asterix.common.exceptions.WarningUtil;
 import org.apache.asterix.common.external.IDataSourceAdapter;
 import org.apache.asterix.common.functions.ExternalFunctionLanguage;
 import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.common.metadata.IMetadataLockUtil;
 import org.apache.asterix.common.utils.JobUtils;
@@ -97,17 +98,14 @@ import org.apache.asterix.external.indexing.IndexingConstants;
 import org.apache.asterix.external.operators.FeedIntakeOperatorNodePushable;
 import org.apache.asterix.external.util.ExternalDataConstants;
 import org.apache.asterix.external.util.ExternalDataUtils;
-import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.base.IReturningStatement;
 import org.apache.asterix.lang.common.base.IRewriterFactory;
 import org.apache.asterix.lang.common.base.IStatementRewriter;
 import org.apache.asterix.lang.common.base.Statement;
-import org.apache.asterix.lang.common.expression.CallExpr;
 import org.apache.asterix.lang.common.expression.IndexedTypeExpression;
-import org.apache.asterix.lang.common.expression.LiteralExpr;
 import org.apache.asterix.lang.common.expression.TypeExpression;
 import org.apache.asterix.lang.common.expression.TypeReferenceExpression;
-import org.apache.asterix.lang.common.literal.MissingLiteral;
 import org.apache.asterix.lang.common.statement.AdapterDropStatement;
 import org.apache.asterix.lang.common.statement.CompactStatement;
 import org.apache.asterix.lang.common.statement.ConnectFeedStatement;
@@ -121,6 +119,7 @@ import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
 import org.apache.asterix.lang.common.statement.CreateIndexStatement;
 import org.apache.asterix.lang.common.statement.CreateLibraryStatement;
 import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
+import org.apache.asterix.lang.common.statement.CreateViewStatement;
 import org.apache.asterix.lang.common.statement.DatasetDecl;
 import org.apache.asterix.lang.common.statement.DataverseDecl;
 import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -149,10 +148,13 @@ import org.apache.asterix.lang.common.statement.StopFeedStatement;
 import org.apache.asterix.lang.common.statement.SynonymDropStatement;
 import org.apache.asterix.lang.common.statement.TypeDecl;
 import org.apache.asterix.lang.common.statement.TypeDropStatement;
+import org.apache.asterix.lang.common.statement.ViewDecl;
+import org.apache.asterix.lang.common.statement.ViewDropStatement;
 import org.apache.asterix.lang.common.statement.WriteStatement;
 import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.asterix.lang.common.util.FunctionUtil;
+import org.apache.asterix.lang.common.util.ViewUtil;
 import org.apache.asterix.metadata.IDatasetDetails;
 import org.apache.asterix.metadata.MetadataManager;
 import org.apache.asterix.metadata.MetadataTransactionContext;
@@ -178,6 +180,7 @@ import org.apache.asterix.metadata.entities.InternalDatasetDetails;
 import org.apache.asterix.metadata.entities.Library;
 import org.apache.asterix.metadata.entities.NodeGroup;
 import org.apache.asterix.metadata.entities.Synonym;
+import org.apache.asterix.metadata.entities.ViewDetails;
 import org.apache.asterix.metadata.feeds.FeedMetadataUtil;
 import org.apache.asterix.metadata.functions.ExternalFunctionCompilerUtil;
 import org.apache.asterix.metadata.lock.ExternalDatasetsRegistry;
@@ -419,6 +422,12 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                     case SYNONYM_DROP:
                         handleDropSynonymStatement(metadataProvider, stmt);
                         break;
+                    case CREATE_VIEW:
+                        handleCreateViewStatement(metadataProvider, stmt, stmtRewriter, requestParameters);
+                        break;
+                    case VIEW_DROP:
+                        handleViewDropStatement(metadataProvider, stmt);
+                        break;
                     case LOAD:
                         handleLoadStatement(metadataProvider, stmt, hcc);
                         break;
@@ -731,8 +740,12 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
             }
 
             IDatasetDetails datasetDetails;
-            Dataset ds = metadataProvider.findDataset(dataverseName, datasetName);
+            Dataset ds = metadataProvider.findDataset(dataverseName, datasetName, true);
             if (ds != null) {
+                if (ds.getDatasetType() == DatasetType.VIEW) {
+                    throw new CompilationException(ErrorCode.VIEW_EXISTS, sourceLoc,
+                            DatasetUtil.getFullyQualifiedDisplayName(ds));
+                }
                 if (dd.getIfNotExists()) {
                     MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
                     return;
@@ -1844,23 +1857,31 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
             List<Dataset> datasets = MetadataManager.INSTANCE.getDataverseDatasets(mdTxnCtx, dataverseName);
             for (Dataset dataset : datasets) {
                 String datasetName = dataset.getDatasetName();
-                List<Index> indexes = MetadataManager.INSTANCE.getDatasetIndexes(mdTxnCtx, dataverseName, datasetName);
                 DatasetType dsType = dataset.getDatasetType();
-                if (dsType == DatasetType.INTERNAL) {
-                    for (Index index : indexes) {
-                        jobsToExecute.add(IndexUtil.buildDropIndexJobSpec(index, metadataProvider, dataset, sourceLoc));
-                    }
-                } else if (dsType == DatasetType.EXTERNAL) {
-                    for (Index index : indexes) {
-                        if (ExternalIndexingOperations.isFileIndex(index)) {
-                            jobsToExecute.add(
-                                    ExternalIndexingOperations.buildDropFilesIndexJobSpec(metadataProvider, dataset));
-                        } else {
+                switch (dsType) {
+                    case INTERNAL:
+                        List<Index> indexes =
+                                MetadataManager.INSTANCE.getDatasetIndexes(mdTxnCtx, dataverseName, datasetName);
+                        for (Index index : indexes) {
                             jobsToExecute
                                     .add(IndexUtil.buildDropIndexJobSpec(index, metadataProvider, dataset, sourceLoc));
                         }
-                    }
-                    externalDatasetsToDeregister.add(dataset);
+                        break;
+                    case EXTERNAL:
+                        indexes = MetadataManager.INSTANCE.getDatasetIndexes(mdTxnCtx, dataverseName, datasetName);
+                        for (Index index : indexes) {
+                            if (ExternalIndexingOperations.isFileIndex(index)) {
+                                jobsToExecute.add(ExternalIndexingOperations
+                                        .buildDropFilesIndexJobSpec(metadataProvider, dataset));
+                            } else {
+                                jobsToExecute.add(
+                                        IndexUtil.buildDropIndexJobSpec(index, metadataProvider, dataset, sourceLoc));
+                            }
+                        }
+                        externalDatasetsToDeregister.add(dataset);
+                        break;
+                    case VIEW:
+                        break;
                 }
             }
 
@@ -2009,7 +2030,7 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                     throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, sourceLoc, dataverseName);
                 }
             }
-            ds = metadataProvider.findDataset(dataverseName, datasetName);
+            ds = metadataProvider.findDataset(dataverseName, datasetName, true);
             if (ds == null) {
                 if (ifExists) {
                     MetadataManager.INSTANCE.commitTransaction(mdTxnCtx.getValue());
@@ -2018,6 +2039,9 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                     throw new CompilationException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, sourceLoc, datasetName,
                             dataverseName);
                 }
+            } else if (ds.getDatasetType() == DatasetType.VIEW) {
+                throw new CompilationException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, sourceLoc, datasetName,
+                        dataverseName);
             }
             validateDatasetState(metadataProvider, ds, sourceLoc);
 
@@ -2412,6 +2436,140 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
         }
     }
 
+    public void handleCreateViewStatement(MetadataProvider metadataProvider, Statement stmt,
+            IStatementRewriter stmtRewriter, IRequestParameters requestParameters) throws Exception {
+        CreateViewStatement cvs = (CreateViewStatement) stmt;
+        metadataProvider.validateDatabaseObjectName(cvs.getDataverseName(), cvs.getViewName(),
+                stmt.getSourceLocation());
+        DataverseName dataverseName = getActiveDataverseName(cvs.getDataverseName());
+        lockUtil.createDatasetBegin(lockManager, metadataProvider.getLocks(), dataverseName, cvs.getViewName(),
+                MetadataBuiltinEntities.ANY_OBJECT_DATATYPE.getDataverseName(),
+                MetadataBuiltinEntities.ANY_OBJECT_DATATYPE.getDatatypeName(), false, null, null, false, null, null,
+                true, DatasetType.VIEW, null);
+        try {
+            doCreateView(metadataProvider, cvs, dataverseName, cvs.getViewName(), stmtRewriter, requestParameters);
+        } finally {
+            metadataProvider.getLocks().unlock();
+            metadataProvider.setDefaultDataverse(activeDataverse);
+        }
+    }
+
+    protected void doCreateView(MetadataProvider metadataProvider, CreateViewStatement cvs, DataverseName dataverseName,
+            String viewName, IStatementRewriter stmtRewriter, IRequestParameters requestParameters) throws Exception {
+        SourceLocation sourceLoc = cvs.getSourceLocation();
+        MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+        metadataProvider.setMetadataTxnContext(mdTxnCtx);
+        try {
+            Dataverse dv = MetadataManager.INSTANCE.getDataverse(mdTxnCtx, dataverseName);
+            if (dv == null) {
+                throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, sourceLoc, dataverseName);
+            }
+            Dataset existingDataset = MetadataManager.INSTANCE.getDataset(mdTxnCtx, dataverseName, viewName);
+            if (existingDataset != null) {
+                if (DatasetUtil.isNotView(existingDataset)) {
+                    throw new CompilationException(ErrorCode.DATASET_EXISTS, sourceLoc,
+                            existingDataset.getDatasetName(), existingDataset.getDataverseName());
+                }
+                if (cvs.getIfNotExists()) {
+                    MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+                    return;
+                } else if (!cvs.getReplaceIfExists()) {
+                    throw new CompilationException(ErrorCode.VIEW_EXISTS, sourceLoc,
+                            existingDataset.getDatasetFullyQualifiedName());
+                }
+            }
+
+            // Check whether the view is usable:
+            // create a view declaration for this function,
+            // and a query body that queries this view:
+            ViewDecl viewDecl =
+                    new ViewDecl(new DatasetFullyQualifiedName(dataverseName, viewName), cvs.getViewBodyExpression());
+            viewDecl.setSourceLocation(sourceLoc);
+            IQueryRewriter queryRewriter = rewriterFactory.createQueryRewriter();
+            Query wrappedQuery = queryRewriter.createViewAccessorQuery(viewDecl);
+            metadataProvider.setDefaultDataverse(dv);
+            apiFramework.reWriteQuery(declaredFunctions, Collections.singletonList(viewDecl), metadataProvider,
+                    wrappedQuery, sessionOutput, false, false, Collections.emptyList(), warningCollector);
+
+            List<List<Triple<DataverseName, String, String>>> dependencies =
+                    ViewUtil.getViewDependencies(viewDecl, queryRewriter);
+
+            ViewDetails viewDetails = new ViewDetails(cvs.getViewBody(), dependencies);
+
+            Dataset view =
+                    new Dataset(dataverseName, viewName, MetadataBuiltinEntities.ANY_OBJECT_DATATYPE.getDataverseName(),
+                            MetadataBuiltinEntities.ANY_OBJECT_DATATYPE.getDatatypeName(),
+                            MetadataConstants.METADATA_NODEGROUP_NAME, "", Collections.emptyMap(), viewDetails,
+                            Collections.emptyMap(), DatasetType.VIEW, 0, MetadataUtil.PENDING_NO_OP);
+            if (existingDataset == null) {
+                MetadataManager.INSTANCE.addDataset(mdTxnCtx, view);
+            } else {
+                MetadataManager.INSTANCE.updateDataset(mdTxnCtx, view);
+            }
+            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+        } catch (Exception e) {
+            abort(e, e, mdTxnCtx);
+            throw e;
+        }
+    }
+
+    public void handleViewDropStatement(MetadataProvider metadataProvider, Statement stmt) throws Exception {
+        ViewDropStatement stmtDrop = (ViewDropStatement) stmt;
+        SourceLocation sourceLoc = stmtDrop.getSourceLocation();
+        String viewName = stmtDrop.getViewName().getValue();
+        metadataProvider.validateDatabaseObjectName(stmtDrop.getDataverseName(), viewName, sourceLoc);
+        DataverseName dataverseName = getActiveDataverseName(stmtDrop.getDataverseName());
+        lockUtil.dropDatasetBegin(lockManager, metadataProvider.getLocks(), dataverseName, viewName);
+        try {
+            doDropView(metadataProvider, stmtDrop, dataverseName, viewName);
+        } finally {
+            metadataProvider.getLocks().unlock();
+            ExternalDatasetsRegistry.INSTANCE.releaseAcquiredLocks(metadataProvider);
+        }
+    }
+
+    protected boolean doDropView(MetadataProvider metadataProvider, ViewDropStatement stmtViewDrop,
+            DataverseName dataverseName, String viewName) throws Exception {
+        SourceLocation sourceLoc = stmtViewDrop.getSourceLocation();
+        MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+        metadataProvider.setMetadataTxnContext(mdTxnCtx);
+        try {
+            // Check if the dataverse exists
+            Dataverse dv = MetadataManager.INSTANCE.getDataverse(mdTxnCtx, dataverseName);
+            if (dv == null) {
+                if (stmtViewDrop.getIfExists()) {
+                    if (warningCollector.shouldWarn()) {
+                        warningCollector.warn(Warning.of(stmtViewDrop.getSourceLocation(), ErrorCode.UNKNOWN_DATAVERSE,
+                                dataverseName));
+                    }
+                    MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+                    return false;
+                } else {
+                    throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, sourceLoc, dataverseName);
+                }
+            }
+            Dataset dataset = metadataProvider.findDataset(dataverseName, viewName, true);
+            if (dataset == null) {
+                if (stmtViewDrop.getIfExists()) {
+                    MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+                    return false;
+                } else {
+                    throw new CompilationException(ErrorCode.UNKNOWN_VIEW, sourceLoc,
+                            DatasetUtil.getFullyQualifiedDisplayName(dataverseName, viewName));
+                }
+            } else if (DatasetUtil.isNotView(dataset)) {
+                throw new CompilationException(ErrorCode.UNKNOWN_VIEW, sourceLoc,
+                        DatasetUtil.getFullyQualifiedDisplayName(dataverseName, viewName));
+            }
+            MetadataManager.INSTANCE.dropDataset(mdTxnCtx, dataverseName, viewName, false);
+            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+            return true;
+        } catch (Exception e) {
+            abort(e, e, mdTxnCtx);
+            throw e;
+        }
+    }
+
     protected void handleDeclareFunctionStatement(MetadataProvider metadataProvider, Statement stmt) throws Exception {
         FunctionDecl fds = (FunctionDecl) stmt;
         FunctionSignature signature = fds.getSignature();
@@ -2475,6 +2633,7 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                 existingInlineTypes = Collections.emptyList();
             }
 
+            IQueryRewriter queryRewriter = rewriterFactory.createQueryRewriter();
             Map<TypeSignature, Datatype> newInlineTypes;
             Function function;
             if (cfs.isExternal()) {
@@ -2514,7 +2673,7 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                         newInlineTypes.put(paramTypeSignature, paramInlineTypeEntity);
                     }
                     VarIdentifier paramName = paramPair.getFirst();
-                    paramNames.add(stmtRewriter.toFunctionParameterName(paramName));
+                    paramNames.add(queryRewriter.toFunctionParameterName(paramName));
                 }
 
                 TypeSignature returnTypeSignature;
@@ -2569,7 +2728,7 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                 for (Pair<VarIdentifier, TypeExpression> paramPair : paramList) {
                     VarIdentifier paramName = paramPair.getFirst();
                     paramVars.add(paramName);
-                    paramNames.add(stmtRewriter.toFunctionParameterName(paramName));
+                    paramNames.add(queryRewriter.toFunctionParameterName(paramName));
                     if (paramPair.getSecond() != null) {
                         throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc,
                                 paramName.toString());
@@ -2581,25 +2740,17 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                 // and a query body calls this function with each argument set to 'missing'
                 FunctionDecl fd = new FunctionDecl(functionSignature, paramVars, cfs.getFunctionBodyExpression(), true);
                 fd.setSourceLocation(sourceLoc);
-                CallExpr fcall = new CallExpr(functionSignature,
-                        Collections.nCopies(paramVars.size(), new LiteralExpr(MissingLiteral.INSTANCE)));
-                fcall.setSourceLocation(sourceLoc);
-                metadataProvider.setDefaultDataverse(dv);
-                Query wrappedQuery = new Query(false);
-                wrappedQuery.setSourceLocation(sourceLoc);
-                wrappedQuery.setBody(fcall);
-                wrappedQuery.setTopLevel(false);
-                List<FunctionDecl> fdList = new ArrayList<>(declaredFunctions);
+
+                Query wrappedQuery = queryRewriter.createFunctionAccessorQuery(fd);
+                List<FunctionDecl> fdList = new ArrayList<>(declaredFunctions.size() + 1);
+                fdList.addAll(declaredFunctions);
                 fdList.add(fd);
-                apiFramework.reWriteQuery(fdList, metadataProvider, wrappedQuery, sessionOutput, false, false,
+                metadataProvider.setDefaultDataverse(dv);
+                apiFramework.reWriteQuery(fdList, null, metadataProvider, wrappedQuery, sessionOutput, false, false,
                         Collections.emptyList(), warningCollector);
-                Expression fdNormBody = fd.getNormalizedFuncBody();
-                if (fdNormBody == null) {
-                    throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc,
-                            functionSignature.toString());
-                }
+
                 List<List<Triple<DataverseName, String, String>>> dependencies =
-                        FunctionUtil.getFunctionDependencies(rewriterFactory.createQueryRewriter(), fdNormBody);
+                        FunctionUtil.getFunctionDependencies(fd, queryRewriter);
 
                 newInlineTypes = Collections.emptyMap();
                 function = new Function(functionSignature, paramNames, null, null, cfs.getFunctionBody(),
@@ -2630,14 +2781,14 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                 }
                 MetadataManager.INSTANCE.updateFunction(mdTxnCtx, function);
             }
-            if (LOGGER.isInfoEnabled()) {
-                LOGGER.info("Installed function: " + functionSignature);
-            }
             MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
         } catch (Exception e) {
             abort(e, e, mdTxnCtx);
             throw e;
         }
+        if (LOGGER.isInfoEnabled()) {
+            LOGGER.info("Installed function: " + functionSignature);
+        }
     }
 
     private Triple<TypeSignature, TypeSignature, Datatype> translateFunctionParameterType(
@@ -3231,7 +3382,7 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
             try {
                 metadataProvider.setWriteTransaction(true);
                 final JobSpecification jobSpec =
-                        rewriteCompileInsertUpsert(hcc, metadataProvider, stmtInsertUpsert, stmtParams, stmtRewriter);
+                        rewriteCompileInsertUpsert(hcc, metadataProvider, stmtInsertUpsert, stmtParams);
                 MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
                 bActiveTxn = false;
                 return jobSpec;
@@ -3286,8 +3437,8 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
             CompiledDeleteStatement clfrqs = new CompiledDeleteStatement(stmtDelete.getVariableExpr(), dataverseName,
                     datasetName, stmtDelete.getCondition(), stmtDelete.getVarCounter(), stmtDelete.getQuery());
             clfrqs.setSourceLocation(stmt.getSourceLocation());
-            JobSpecification jobSpec = rewriteCompileQuery(hcc, metadataProvider, clfrqs.getQuery(), clfrqs, stmtParams,
-                    stmtRewriter, null);
+            JobSpecification jobSpec =
+                    rewriteCompileQuery(hcc, metadataProvider, clfrqs.getQuery(), clfrqs, stmtParams, null);
             afterCompile();
 
             MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
@@ -3310,13 +3461,13 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
     @Override
     public JobSpecification rewriteCompileQuery(IClusterInfoCollector clusterInfoCollector,
             MetadataProvider metadataProvider, Query query, ICompiledDmlStatement stmt,
-            Map<String, IAObject> stmtParams, IStatementRewriter stmtRewriter, IRequestParameters requestParameters)
+            Map<String, IAObject> stmtParams, IRequestParameters requestParameters)
             throws AlgebricksException, ACIDException {
 
-        Map<VarIdentifier, IAObject> externalVars = createExternalVariables(stmtParams, stmtRewriter);
+        Map<VarIdentifier, IAObject> externalVars = createExternalVariables(stmtParams);
 
         // Query Rewriting (happens under the same ongoing metadata transaction)
-        Pair<IReturningStatement, Integer> rewrittenResult = apiFramework.reWriteQuery(declaredFunctions,
+        Pair<IReturningStatement, Integer> rewrittenResult = apiFramework.reWriteQuery(declaredFunctions, null,
                 metadataProvider, query, sessionOutput, true, true, externalVars.keySet(), warningCollector);
 
         // Query Compilation (happens under the same ongoing metadata transaction)
@@ -3326,14 +3477,14 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
     }
 
     private JobSpecification rewriteCompileInsertUpsert(IClusterInfoCollector clusterInfoCollector,
-            MetadataProvider metadataProvider, InsertStatement insertUpsert, Map<String, IAObject> stmtParams,
-            IStatementRewriter stmtRewriter) throws AlgebricksException, ACIDException {
+            MetadataProvider metadataProvider, InsertStatement insertUpsert, Map<String, IAObject> stmtParams)
+            throws AlgebricksException, ACIDException {
         SourceLocation sourceLoc = insertUpsert.getSourceLocation();
 
-        Map<VarIdentifier, IAObject> externalVars = createExternalVariables(stmtParams, stmtRewriter);
+        Map<VarIdentifier, IAObject> externalVars = createExternalVariables(stmtParams);
 
         // Insert/upsert statement rewriting (happens under the same ongoing metadata transaction)
-        Pair<IReturningStatement, Integer> rewrittenResult = apiFramework.reWriteQuery(declaredFunctions,
+        Pair<IReturningStatement, Integer> rewrittenResult = apiFramework.reWriteQuery(declaredFunctions, null,
                 metadataProvider, insertUpsert, sessionOutput, true, true, externalVars.keySet(), warningCollector);
 
         InsertStatement rewrittenInsertUpsert = (InsertStatement) rewrittenResult.first;
@@ -3825,8 +3976,8 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
             boolean bActiveTxn = true;
             metadataProvider.setMetadataTxnContext(mdTxnCtx);
             try {
-                final JobSpecification jobSpec = rewriteCompileQuery(hcc, metadataProvider, query, null, stmtParams,
-                        stmtRewriter, requestParameters);
+                final JobSpecification jobSpec =
+                        rewriteCompileQuery(hcc, metadataProvider, query, null, stmtParams, requestParameters);
                 // update stats with count of compile-time warnings. needs to be adapted for multi-statement.
                 stats.updateTotalWarningsCount(warningCollector.getTotalWarningsCount());
                 afterCompile();
@@ -4377,18 +4528,14 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
         return i == 0;
     }
 
-    private Map<VarIdentifier, IAObject> createExternalVariables(Map<String, IAObject> stmtParams,
-            IStatementRewriter stmtRewriter) {
+    private Map<VarIdentifier, IAObject> createExternalVariables(Map<String, IAObject> stmtParams) {
         if (stmtParams == null || stmtParams.isEmpty()) {
             return Collections.emptyMap();
         }
+        IQueryRewriter queryRewriter = rewriterFactory.createQueryRewriter();
         Map<VarIdentifier, IAObject> m = new HashMap<>();
         for (Map.Entry<String, IAObject> me : stmtParams.entrySet()) {
-            String paramName = me.getKey();
-            String extVarName = stmtRewriter.toExternalVariableName(paramName);
-            if (extVarName != null) {
-                m.put(new VarIdentifier(extVarName), me.getValue());
-            }
+            m.put(queryRewriter.toExternalVariableName(me.getKey()), me.getValue());
         }
         return m;
     }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java
index e1c39a0..9438b16 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java
@@ -43,6 +43,7 @@ import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Dataverse;
 import org.apache.asterix.metadata.entities.ExternalDatasetDetails;
 import org.apache.asterix.metadata.entities.Index;
+import org.apache.asterix.metadata.utils.DatasetUtil;
 import org.apache.asterix.metadata.utils.ExternalIndexingOperations;
 import org.apache.asterix.metadata.utils.MetadataConstants;
 import org.apache.hyracks.api.application.ICCServiceContext;
@@ -137,7 +138,8 @@ public class GlobalRecoveryManager implements IGlobalRecoveryManager {
         for (Dataverse dataverse : dataverses) {
             List<Dataset> dataverseDatasets =
                     MetadataManager.INSTANCE.getDataverseDatasets(mdTxnCtx, dataverse.getDataverseName());
-            dataverseDatasets.stream().mapToInt(Dataset::getDatasetId).forEach(validDatasetIds::add);
+            dataverseDatasets.stream().filter(DatasetUtil::isNotView).mapToInt(Dataset::getDatasetId)
+                    .forEach(validDatasetIds::add);
         }
         ICcApplicationContext ccAppCtx = (ICcApplicationContext) serviceCtx.getApplicationContext();
         final List<String> ncs = new ArrayList<>(ccAppCtx.getClusterStateManager().getParticipantNodes());
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
index 9472da5..dcd52a0 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
@@ -253,7 +253,7 @@ public class FeedOperations {
             clfrqs = new CompiledStatements.CompiledUpsertStatement(feedConn.getDataverseName(),
                     feedConn.getDatasetName(), feedConnQuery, stmtUpsert.getVarCounter(), null, null);
         }
-        return statementExecutor.rewriteCompileQuery(hcc, metadataProvider, feedConnQuery, clfrqs, null, null, null);
+        return statementExecutor.rewriteCompileQuery(hcc, metadataProvider, feedConnQuery, clfrqs, null, null);
     }
 
     private static JobSpecification combineIntakeCollectJobs(MetadataProvider metadataProvider, Feed feed,
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/RebalanceUtil.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/RebalanceUtil.java
index fcdc25a..b0dc162 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/RebalanceUtil.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/RebalanceUtil.java
@@ -354,7 +354,7 @@ public class RebalanceUtil {
     // Drops dataset files of a given dataset.
     private static void dropDatasetFiles(Dataset dataset, MetadataProvider metadataProvider,
             IHyracksClientConnection hcc) throws Exception {
-        if (dataset.getDatasetType() == DatasetType.EXTERNAL) {
+        if (dataset.getDatasetType() == DatasetType.EXTERNAL || dataset.getDatasetType() == DatasetType.VIEW) {
             return;
         }
         List<JobSpecification> jobs = new ArrayList<>();
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
index 2039d53..8a87de7 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
@@ -19,6 +19,9 @@
 package org.apache.asterix.test.sqlpp;
 
 import static org.apache.hyracks.util.file.FileUtil.canonicalize;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -159,7 +162,17 @@ public class ParserTestExecutor extends TestExecutor {
                     return mockDataverse;
                 }
             });
-            when(metadataProvider.findDataset(Mockito.<DataverseName> any(), Mockito.<String> any()))
+            when(metadataProvider.findDataset(any(DataverseName.class), anyString())).thenAnswer(new Answer<Dataset>() {
+                @Override
+                public Dataset answer(InvocationOnMock invocation) {
+                    Object[] args = invocation.getArguments();
+                    final Dataset mockDataset = mock(Dataset.class);
+                    when(mockDataset.getDataverseName()).thenReturn((DataverseName) args[0]);
+                    when(mockDataset.getDatasetName()).thenReturn((String) args[1]);
+                    return mockDataset;
+                }
+            });
+            when(metadataProvider.findDataset(any(DataverseName.class), anyString(), anyBoolean()))
                     .thenAnswer(new Answer<Dataset>() {
                         @Override
                         public Dataset answer(InvocationOnMock invocation) {
@@ -170,7 +183,7 @@ public class ParserTestExecutor extends TestExecutor {
                             return mockDataset;
                         }
                     });
-            when(metadataProvider.lookupUserDefinedFunction(Mockito.<FunctionSignature> any()))
+            when(metadataProvider.lookupUserDefinedFunction(any(FunctionSignature.class)))
                     .thenAnswer(new Answer<Function>() {
                         @Override
                         public Function answer(InvocationOnMock invocation) {
@@ -189,7 +202,7 @@ public class ParserTestExecutor extends TestExecutor {
                 if (st.getKind() == Statement.Kind.QUERY) {
                     Query query = (Query) st;
                     IQueryRewriter rewriter = sqlppRewriterFactory.createQueryRewriter();
-                    LangRewritingContext rwContext = new LangRewritingContext(metadataProvider, functions,
+                    LangRewritingContext rwContext = new LangRewritingContext(metadataProvider, functions, null,
                             TestUtils.NOOP_WARNING_COLLECTOR, query.getVarCounter());
                     rewrite(rewriter, query, rwContext);
 
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/metadata/queries/exception/exception_create_system_view/exception_create_system_view.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/metadata/queries/exception/exception_create_system_view/exception_create_system_view.1.ddl.sqlpp
index 9d983b0..5e69371 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/metadata/queries/exception/exception_create_system_view/exception_create_system_view.1.ddl.sqlpp
@@ -16,28 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view Metadata.MyMetaView as
+  select count(*) from Metadata.`Dataset`;
diff --git a/asterixdb/asterix-app/src/test/resources/metadata/testsuite.xml b/asterixdb/asterix-app/src/test/resources/metadata/testsuite.xml
index a29dc48..dc6ae3d 100644
--- a/asterixdb/asterix-app/src/test/resources/metadata/testsuite.xml
+++ b/asterixdb/asterix-app/src/test/resources/metadata/testsuite.xml
@@ -363,6 +363,12 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="exception">
+      <compilation-unit name="exception_create_system_view">
+        <output-dir compare="Text">none</output-dir>
+        <expected-error>ASX1079: Compilation error: Invalid operation - Cannot create a view belonging to the dataverse: Metadata (in line 20, at column 1)</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="exception">
       <compilation-unit name="exception_declare_system_function">
         <output-dir compare="Text">none</output-dir>
         <expected-error>ASX1079: Compilation error: Invalid operation - Cannot declare a function belonging to the dataverse: Metadata (in line 22, at column 1)</expected-error>
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.1.ddl.sqlpp
index 9d983b0..1b1210f 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.1.ddl.sqlpp
@@ -16,28 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+/*
+ * Empty view name -> Error
+ */
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test if exists;
+create dataverse test;
 
-    String toExternalVariableName(String statementParameterName);
+use test;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view `` as
+  select r from range(0, 2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.2.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.2.ddl.sqlpp
index 9d983b0..a3a0172 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.2.ddl.sqlpp
@@ -16,28 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+/*
+ * View name starts with a space character -> Error
+ */
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test if exists;
+create dataverse test;
 
-    String toExternalVariableName(String statementParameterName);
+use test;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view ` a` as
+  select r from range(0, 2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.3.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.3.ddl.sqlpp
index 9d983b0..2774fe2 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.3.ddl.sqlpp
@@ -16,28 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+/*
+ * Invalid dataverse name in CREATE VIEW -> Error
+ */
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test if exists;
+create dataverse test;
 
-    String toExternalVariableName(String statementParameterName);
+use test;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view ` invalid`.a as
+  select r from range(0, 2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.4.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.4.ddl.sqlpp
index 9d983b0..d38df4c 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.4.ddl.sqlpp
@@ -16,28 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+/*
+ * Invalid dataverse name in CREATE VIEW -> Error
+ */
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test if exists;
+create dataverse test;
 
-    String toExternalVariableName(String statementParameterName);
+use test;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view `a/b`.a as
+  select r from range(0, 2) r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.5.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.5.ddl.sqlpp
index 9d983b0..6acc680 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/invalid-view-name/invalid-view-name.5.ddl.sqlpp
@@ -16,28 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
+/*
+ * Invalid dataverse name in DROP VIEW -> Error
+ */
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse c.d if exists;
+create dataverse c.d;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+use c.d;
 
-    String toExternalVariableName(String statementParameterName);
+create view e as
+  select r from range(0, 2) r;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop view `c/d`.e;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.1.ddl.sqlpp
index 9d983b0..f28ae6b 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.1.ddl.sqlpp
@@ -16,28 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
+/*
+ * Description: views in a dataverse with a multipart name
+ */
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+drop  dataverse x.y if exists;
+create  dataverse x.y;
 
-public interface IStatementRewriter {
+drop  dataverse x.z if exists;
+create  dataverse x.z;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create view x.z.vz as
+  select r from range(0,2) r;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create view x.y.vy as
+  select vz.* from x.z.vz;
 
-    String toExternalVariableName(String statementParameterName);
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.2.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.2.query.sqlpp
index 9d983b0..6293c28 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.2.query.sqlpp
@@ -16,28 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
-
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
+/*
+ * Description: views in a dataverse with a multipart name
+ */
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value r
+from x.y.vy r
+order by r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.3.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.3.query.sqlpp
index 9d983b0..de77ed0 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/view_1/view_1.3.query.sqlpp
@@ -16,28 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
-
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
+/*
+ * Description: views in a dataverse with a multipart name
+ */
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select DataverseName, DatasetName,
+  ViewDetails.Dependencies Dependencies
+from Metadata.`Dataset`
+where DataverseName like "x%" and DatasetType = "VIEW"
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.1.ddl.sqlpp
new file mode 100644
index 0000000..66965a1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.1.ddl.sqlpp
@@ -0,0 +1,68 @@
+/*
+ * 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 test1 if exists;
+create dataverse test1;
+
+drop dataverse test2 if exists;
+create dataverse test2;
+
+use test2;
+
+--- test2
+
+create synonym DataverseSyn2 for Metadata.`Dataverse`;
+
+create function f2() {
+  select count(*) as f2 from DataverseSyn2
+  where DataverseName like "t%"
+};
+
+create view v2 as select sum(r) as v2 from range(1,2) r;
+
+--- test1
+
+create synonym test1.DataverseSyn1 for Metadata.`Dataverse`;
+
+create view test1.v1 as select sum(r) as v1 from range(1,3) r;
+
+create function test1.f1() {
+  select count(*) as f1 from DataverseSyn1
+  where DataverseName like "t%"
+};
+
+create view test1.vA as
+  select v1.*, v2.*, f1.*, f2.*, s1.*, s2.*, d1.*
+  from
+    v1 v1,
+    test2.v2 v2,
+    f1() f1,
+    test2.f2() f2,
+    (
+      select count(*) as s1 from DataverseSyn1
+        where DataverseName like "te%"
+    ) s1,
+    (
+      select count(*) as s2 from test2.DataverseSyn2
+        where DataverseName like "tes%"
+    ) s2,
+    (
+      select count(*) as d1 from Metadata.`Dataverse`
+      where DataverseName like "test%"
+    ) d1;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.10.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.10.ddl.sqlpp
index 9d983b0..073842f 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.10.ddl.sqlpp
@@ -16,28 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- test "or replace"
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create or replace view test1.vA as
+  select r from range(3,4) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.11.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.11.query.sqlpp
index 9d983b0..443d9eb 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.11.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+use test1;
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value vA from vA order by r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.12.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.12.query.sqlpp
index 9d983b0..80aa2dc 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.12.query.sqlpp
@@ -16,28 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select DataverseName, DatasetName,
+  DatatypeDataverseName, DatatypeName, ViewDetails
+from Metadata.`Dataset`
+where DataverseName like "test%" and DatasetType = "VIEW" and DatasetName = "vA"
+order by DataverseName, DatasetName;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.2.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.2.query.sqlpp
index 9d983b0..d7b182f 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.2.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+use test1;
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value vA from vA;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.3.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.3.query.sqlpp
index 9d983b0..2cf093f 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.3.query.sqlpp
@@ -16,28 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select DataverseName, DatasetName,
+  DatatypeDataverseName, DatatypeName, ViewDetails
+from Metadata.`Dataset`
+where DataverseName like "test%" and DatasetType = "VIEW"
+order by DataverseName, DatasetName;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.4.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.4.ddl.sqlpp
index 9d983b0..237100e 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.4.ddl.sqlpp
@@ -16,28 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- test "if not exists" when the view already exists
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test1.vA if not exists as
+  select r from range(1,2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.5.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.5.query.sqlpp
index 9d983b0..636f5da 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.5.query.sqlpp
@@ -16,28 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- same result as before
 
-public interface IStatementRewriter {
+use test1;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value vA from vA;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.6.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.6.query.sqlpp
index 9d983b0..a204c97 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.6.query.sqlpp
@@ -16,28 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- same result as before
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select DataverseName, DatasetName,
+  DatatypeDataverseName, DatatypeName, ViewDetails
+from Metadata.`Dataset`
+where DataverseName like "test%" and DatasetType = "VIEW" and DatasetName = "vA"
+order by DataverseName, DatasetName;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.7.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.7.ddl.sqlpp
index 9d983b0..8d6169f 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.7.ddl.sqlpp
@@ -16,28 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- test "if not exists" when the view does not yet exist
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test1.vB if not exists as
+  select r from range(1,2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.8.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.8.query.sqlpp
index 9d983b0..bb1f529 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.8.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+use test1;
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value vB from vB order by r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.9.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.9.query.sqlpp
index 9d983b0..84038a9 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-1/create-view-1.9.query.sqlpp
@@ -16,28 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select DataverseName, DatasetName,
+  DatatypeDataverseName, DatatypeName, ViewDetails
+from Metadata.`Dataset`
+where DataverseName like "test%" and DatasetType = "VIEW" and DatasetName = "vB"
+order by DataverseName, DatasetName;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.1.ddl.sqlpp
index 9d983b0..f8224ef 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.1.ddl.sqlpp
@@ -16,28 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: unknown dataverse
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test.v1 as select r from range(1,2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.10.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.10.ddl.sqlpp
index 9d983b0..9a8fa71 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.10.ddl.sqlpp
@@ -16,28 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: recursive definitions (view/function)
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create view test.v1 as
+  select * from range(1,2) r;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create function test.f2() {
+  select * from v1 r
+};
 
-    String toExternalVariableName(String statementParameterName);
+create or replace view test.v1 as
+  select * from f2() r;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.11.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.11.ddl.sqlpp
index 9d983b0..5aab3ac 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.11.ddl.sqlpp
@@ -16,28 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: recursive definitions (function/view)
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create function test.f1() {
+  select * from range(1,2) r
+};
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create view test.v2 as
+  select * from f1() r
+;
 
-    String toExternalVariableName(String statementParameterName);
+create or replace function test.f1() {
+  select * from v2 r
+};
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.2.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.2.ddl.sqlpp
index 9d983b0..0340d2c 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.2.ddl.sqlpp
@@ -16,28 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: invalid view definition (syntax)
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test.v1 as select * from range(1,2) r order by;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.3.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.3.ddl.sqlpp
index 9d983b0..93cde91 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.3.ddl.sqlpp
@@ -16,28 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: invalid view definition (unknown used function)
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test.v1 as select * from undefined_range(1,2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.4.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.4.ddl.sqlpp
index 9d983b0..6969d78 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.4.ddl.sqlpp
@@ -16,28 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: create view fails because view with this name already exists
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test.v1 as select * from range(1,2) r;
+create view test.v1 as select * from range(3,4) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.5.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.5.ddl.sqlpp
index 9d983b0..da541d1 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.5.ddl.sqlpp
@@ -16,28 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: create view fails because dataset with this name already exists
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create dataset test.ds1(
+  c_custkey integer not unknown,
+  c_name string not unknown
+) primary key c_custkey;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test.ds1 as select * from range(1,2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.6.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.6.ddl.sqlpp
index 9d983b0..f6aefe9 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.6.ddl.sqlpp
@@ -16,28 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: create or replace view fails because dataset with this name already exists
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create dataset test.ds2(
+  c_custkey integer not unknown,
+  c_name string not unknown
+) primary key c_custkey;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create or replace view test.ds2 as select * from range(1,2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.7.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.7.ddl.sqlpp
index 9d983b0..56e24e7 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.7.ddl.sqlpp
@@ -16,28 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: create dataset fails because view with this name already exists
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create view test.ds1 as select * from range(1,2) r;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create dataset test.ds1(
+  c_custkey integer not unknown,
+  c_name string not unknown
+) primary key c_custkey;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.8.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.8.ddl.sqlpp
index 9d983b0..97a7709 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.8.ddl.sqlpp
@@ -16,28 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: "or replace" with "if not exists"
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create or replace view test.v1 if not exists as
+  select * from range(1,2) r;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.9.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.9.ddl.sqlpp
index 9d983b0..a9ef305 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/create-view-2-negative/create-view-2-negative.9.ddl.sqlpp
@@ -16,28 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: recursive definitions (view/view)
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create view test.v1 as
+  select * from range(1,2) r;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create view test.v2 as
+  select * from v1 r;
 
-    String toExternalVariableName(String statementParameterName);
+create or replace view test.v1 as
+  select * from v2 r;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-1/drop-dataverse-1.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-1/drop-dataverse-1.1.ddl.sqlpp
index 9d983b0..27ae6ab 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-1/drop-dataverse-1.1.ddl.sqlpp
@@ -16,28 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- test drop dataverse with views
 
-public interface IStatementRewriter {
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create view test1.v1 as
+  select r from range(0,2) r;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create view test1.v2 as
+  select v1.* from v1;
+
+drop dataverse test1;
 
-    String toExternalVariableName(String statementParameterName);
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.1.ddl.sqlpp
index 9d983b0..f3f0334 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.1.ddl.sqlpp
@@ -16,28 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Test that DROP DATAVERSE fails due to cross-dataverse dependencies
 
-public interface IStatementRewriter {
+--- View depends on view
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    String toExternalVariableName(String statementParameterName);
+create view test2.v2 as select r from range(1,2) r;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test1.v1 as select v2.* from test2.v2;
+
+drop dataverse test2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.2.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.2.ddl.sqlpp
index 9d983b0..d8f90bb 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.2.ddl.sqlpp
@@ -16,28 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Test that DROP DATAVERSE fails due to cross-dataverse dependencies
 
-public interface IStatementRewriter {
+--- Function depends on view
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    String toExternalVariableName(String statementParameterName);
+create view test2.v2 as select r from range(1,2) r;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create function test1.f1() { select v2.* from test2.v2 };
+
+drop dataverse test2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.3.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.3.ddl.sqlpp
index 9d983b0..5089a6a 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.3.ddl.sqlpp
@@ -16,28 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Test that DROP DATAVERSE fails due to cross-dataverse dependencies
 
-public interface IStatementRewriter {
+--- View depends on dataset
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    String toExternalVariableName(String statementParameterName);
+create dataset test2.ds2(c1 bigint not unknown, c2 bigint) primary key c1;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test1.v1 as select ds2.* from test2.ds2;
+
+drop dataverse test2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.4.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.4.ddl.sqlpp
index 9d983b0..8c28081 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.4.ddl.sqlpp
@@ -16,28 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Test that DROP DATAVERSE fails due to cross-dataverse dependencies
 
-public interface IStatementRewriter {
+--- View depends on function
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    String toExternalVariableName(String statementParameterName);
+create function test2.f2() { select r from range(1,2) r };
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test1.v1 as select f2.* from test2.f2() f2;
+
+drop dataverse test2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.5.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.5.ddl.sqlpp
index 9d983b0..cf055ae 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-dataverse-2-negative/drop-dataverse-2-negative.5.ddl.sqlpp
@@ -16,28 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Test that DROP DATAVERSE fails due to cross-dataverse dependencies
 
-public interface IStatementRewriter {
+--- View depends on synonym
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    String toExternalVariableName(String statementParameterName);
+create dataset test2.ds2(c1 bigint not unknown, c2 bigint) primary key c1;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create synonym test2.s3 for ds2;
+
+create view test1.v1 as select s3.* from test2.s3;
+
+drop dataverse test2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-1/drop-view-1.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-1/drop-view-1.1.ddl.sqlpp
index 9d983b0..16c1d6d 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-1/drop-view-1.1.ddl.sqlpp
@@ -16,28 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+drop dataverse test if exists;
+create dataverse test;
 
-public interface IStatementRewriter {
+drop view test.v1 if exists;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create view test.v2 as
+  select r from range(1,2) r;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+drop view test.v2 if exists;
 
-    String toExternalVariableName(String statementParameterName);
+create view test.v3 as
+  select r from range(3,4) r;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop view test.v3;
+
+create view test.v4 as
+  select r from range(3,4) r;
+
+create synonym test.s4 for v4;
+
+-- ok to drop a view if a synonym depends on it
+
+drop view test.v4;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-1/drop-view-1.2.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-1/drop-view-1.2.query.sqlpp
index 9d983b0..4c8483e 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-1/drop-view-1.2.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
-
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select count(*) cnt
+from Metadata.`Dataset`
+where DataverseName = "test" and DatasetType = "VIEW";
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.1.ddl.sqlpp
index 9d983b0..c92c33a 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.1.ddl.sqlpp
@@ -16,28 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: unknown dataverse
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop view test.v1;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.10.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.10.query.sqlpp
index 9d983b0..7aa6517 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.10.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- check that the function was not dropped
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value f2 from test2.f2() f2 order by f2.r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.11.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.11.ddl.sqlpp
index 9d983b0..009dd83 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.11.ddl.sqlpp
@@ -16,28 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: drop synonym fails if a view depends on it
 
-public interface IStatementRewriter {
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create dataset test2.ds2(
+  c_custkey integer not unknown,
+  c_name string not unknown
+) primary key c_custkey;
 
-    String toExternalVariableName(String statementParameterName);
+create synonym test2.s2 for test2.ds2;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create view test1.v1 as
+  select * from test2.s2;
+
+drop synonym test2.s2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.12.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.12.query.sqlpp
index 9d983b0..4a425b4 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.12.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- check that the synonym was not dropped
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value count(*) from test2.s2;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.13.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.13.ddl.sqlpp
index 9d983b0..27acbde 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.13.ddl.sqlpp
@@ -16,28 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: drop view fails if a view depends on it
 
-public interface IStatementRewriter {
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create view test2.v2 as
+  select * from range(1,2) r;
 
-    String toExternalVariableName(String statementParameterName);
+create view test1.v1 as
+  select * from test2.v2;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop view test2.v2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.14.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.14.query.sqlpp
index 9d983b0..f009fcf 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.14.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- check that the view was not dropped
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value v2 from test2.v2 v2 order by v2.r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.15.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.15.ddl.sqlpp
index 9d983b0..c759a13 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.15.ddl.sqlpp
@@ -16,28 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: drop view fails if a function depends on it
 
-public interface IStatementRewriter {
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create view test2.v2 as
+  select * from range(1,2) r;
 
-    String toExternalVariableName(String statementParameterName);
+create function test1.f1() {
+  select * from test2.v2
+};
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop view test2.v2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.16.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.16.query.sqlpp
index 9d983b0..f009fcf 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.16.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- check that the view was not dropped
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value v2 from test2.v2 v2 order by v2.r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.2.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.2.ddl.sqlpp
index 9d983b0..4480882 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.2.ddl.sqlpp
@@ -16,28 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: unknown view
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop view test.v1;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.3.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.3.ddl.sqlpp
index 9d983b0..2034c22 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.3.ddl.sqlpp
@@ -16,28 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: drop dataset fails if target is a view
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create view test.v1 as select r from range(1,2) r;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop dataset test.v1;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.4.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.4.query.sqlpp
index 9d983b0..1275dbe 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.4.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- check that the view was not dropped
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value r from test.v1 r order by r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.5.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.5.ddl.sqlpp
index 9d983b0..3a1fd33 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.5.ddl.sqlpp
@@ -16,28 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: drop view fails if target is a dataset
 
-public interface IStatementRewriter {
+drop dataverse test if exists;
+create dataverse test;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create dataset test.ds1(
+  c_custkey integer not unknown,
+  c_name string not unknown
+) primary key c_custkey;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop view test.ds1;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.6.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.6.query.sqlpp
index 9d983b0..12971b1 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.6.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- check that the dataset was not dropped
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value count(*) from test.ds1;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.7.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.7.ddl.sqlpp
index 9d983b0..92d2270 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.7.ddl.sqlpp
@@ -16,28 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: drop dataset fails if a view depends on it
 
-public interface IStatementRewriter {
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create dataset test2.ds2(
+  c_custkey integer not unknown,
+  c_name string not unknown
+) primary key c_custkey;
 
-    String toExternalVariableName(String statementParameterName);
+create view test1.v1 as
+  select * from test2.ds2;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop dataset test2.ds2;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.8.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.8.query.sqlpp
index 9d983b0..dd85dbe 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.8.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+-- check that the dataset was not dropped
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select value count(*) from test2.ds2;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.9.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.9.ddl.sqlpp
index 9d983b0..83d4fab 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/drop-view-2-negative/drop-view-2-negative.9.ddl.sqlpp
@@ -16,28 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+--- Negative: drop function fails if a view depends on it
 
-public interface IStatementRewriter {
+drop dataverse test1 if exists;
+create dataverse test1;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+drop dataverse test2 if exists;
+create dataverse test2;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create function test2.f2() {
+  select * from range(1,2) r
+};
 
-    String toExternalVariableName(String statementParameterName);
+create view test1.v1 as
+  select * from test2.f2() f2;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+drop function test2.f2();
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.1.ddl.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.1.ddl.sqlpp
index 9d983b0..e5a22ec 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.1.ddl.sqlpp
@@ -16,28 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+drop dataverse test1 if exists;
+create dataverse test1;
 
-public interface IStatementRewriter {
+use test1;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+create dataset ds1(
+  c1 bigint not unknown,
+  c2 bigint
+) primary key c1;
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
+create synonym s2 for ds1;
 
-    String toExternalVariableName(String statementParameterName);
+create view v3 as
+  select c1, c2 from s2;
 
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+create synonym s4 for v3;
+
+create function f5() {
+  select c1, c2 from s4
+};
+
+create view v6 as
+  select c1, c2 from f5() f5;
+
+create synonym s7 for v6;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.2.update.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.2.update.sqlpp
index 9d983b0..260b64f 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.2.update.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+use test1;
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+insert into ds1 select r c1, 9 - r c2 from range(0, 9) r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.3.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.3.query.sqlpp
index 9d983b0..6c92c4a 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.3.query.sqlpp
@@ -16,28 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+use test1;
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select s7.* from s7 order by c1;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.4.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.4.query.sqlpp
index 9d983b0..57b5010 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.4.query.sqlpp
@@ -16,28 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+select "VIEW" Kind, DatasetName Name,
+  ViewDetails.`Definition` `Definition`,
+  ViewDetails.Dependencies Dependencies
+from Metadata.`Dataset`
+where DataverseName like "test1%" and DatasetType = "VIEW"
 
-public interface IStatementRewriter {
+union all
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+select "FUNCTION" Kind, Name, `Definition`, Dependencies
+from Metadata.`Function`
+where DataverseName like "test1%"
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+order by Name;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.5.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.5.ddl.sqlpp
new file mode 100644
index 0000000..97f9ec4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.5.ddl.sqlpp
@@ -0,0 +1,74 @@
+/*
+ * 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 test2 if exists;
+create dataverse test2;
+
+use test2;
+
+create dataset ds1(
+  c1 bigint not unknown,
+  c2 bigint
+) primary key c1;
+
+create dataset ds2(
+  c1 bigint not unknown,
+  c2 bigint
+) primary key c1;
+
+create view v3 as
+  select c1, c2 from ds1
+  union all
+  select c1, c2 from ds2;
+
+create view v4 as
+  select c1, c2 from ds1
+  union all
+  select c1, c2 from ds2;
+
+create function f5() {
+  select c1, c2 from v3
+};
+
+create function f6() {
+  select c1, c2 from v4
+};
+
+create synonym s7 for ds1;
+
+create synonym s8 for ds2;
+
+create view v9 as
+  select c1, c2 from ds1
+  union all
+  select c1, c2 from ds2
+  union all
+  select c1, c2 from v3
+  union all
+  select c1, c2 from v4
+  union all
+  select c1, c2 from f5() f5
+  union all
+  select c1, c2 from f6() f6
+  union all
+  select c1, c2 from s7
+  union all
+  select c1, c2 from s8;
+
+
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.6.update.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.6.update.sqlpp
index 9d983b0..902c718 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.6.update.sqlpp
@@ -16,28 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+use test2;
 
-public interface IStatementRewriter {
+insert into ds1 select r c1, 2 - r c2 from range(0, 2) r;
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+insert into ds2 select r c1, 2 - r c2 from range(0, 2) r;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.7.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.7.query.sqlpp
index 9d983b0..762f234 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.7.query.sqlpp
@@ -16,28 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+use test2;
 
-public interface IStatementRewriter {
-
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
-
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+select count(*) c,
+  array_sort(array_agg(distinct c1)) c1,
+  array_sort(array_agg(distinct c2)) c2
+from v9;
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.8.query.sqlpp
similarity index 50%
copy from asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.8.query.sqlpp
index 9d983b0..d41ee20 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/view/view-1/view-1.8.query.sqlpp
@@ -16,28 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.lang.common.base;
 
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.metadata.declared.MetadataProvider;
+select "VIEW" Kind, DatasetName Name,
+  ViewDetails.Dependencies Dependencies
+from Metadata.`Dataset`
+where DataverseName like "test2%" and DatasetType = "VIEW"
 
-public interface IStatementRewriter {
+union all
 
-    /**
-     * Returns {@code true} if given statement kind is handled by this rewriter.
-     */
-    boolean isRewritable(Statement.Kind kind);
+select "FUNCTION" Kind, Name, Dependencies
+from Metadata.`Function`
+where DataverseName like "test2%"
 
-    /**
-     * @param statement,
-     *            a non-query statement.
-     * @param metadataProvider
-     *            a metadata provider
-     */
-    void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
-}
+order by Name;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/view_1/view_1.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/view_1/view_1.2.adm
new file mode 100644
index 0000000..00cf01e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/view_1/view_1.2.adm
@@ -0,0 +1,3 @@
+{ "r": 0 }
+{ "r": 1 }
+{ "r": 2 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/view_1/view_1.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/view_1/view_1.3.adm
new file mode 100644
index 0000000..c746a5a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/view_1/view_1.3.adm
@@ -0,0 +1,2 @@
+{ "DataverseName": "x/y", "DatasetName": "vy", "Dependencies": [ [ [ "x/z", "vz" ] ], [  ], [  ] ] }
+{ "DataverseName": "x/z", "DatasetName": "vz", "Dependencies": [ [  ], [  ], [  ] ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.11.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.11.adm
new file mode 100644
index 0000000..8d802cd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.11.adm
@@ -0,0 +1,2 @@
+{ "r": 3 }
+{ "r": 4 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.12.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.12.adm
new file mode 100644
index 0000000..42561b4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.12.adm
@@ -0,0 +1 @@
+{ "DataverseName": "test1", "DatasetName": "vA", "DatatypeDataverseName": "Metadata", "DatatypeName": "AnyObject", "ViewDetails": { "Definition": "select r from range(3,4) r", "Dependencies": [ [  ], [  ], [  ] ] } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.2.adm
new file mode 100644
index 0000000..f9bc681
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.2.adm
@@ -0,0 +1 @@
+{ "d1": 2, "s2": 2, "s1": 2, "f2": 2, "f1": 2, "v2": 3, "v1": 6 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.3.adm
new file mode 100644
index 0000000..6ceac5d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.3.adm
@@ -0,0 +1,3 @@
+{ "DataverseName": "test1", "DatasetName": "v1", "DatatypeDataverseName": "Metadata", "DatatypeName": "AnyObject", "ViewDetails": { "Definition": "select sum(r) as v1 from range(1,3) r", "Dependencies": [ [  ], [  ], [  ] ] } }
+{ "DataverseName": "test1", "DatasetName": "vA", "DatatypeDataverseName": "Metadata", "DatatypeName": "AnyObject", "ViewDetails": { "Definition": "select v1.*, v2.*, f1.*, f2.*, s1.*, s2.*, d1.*\n  from\n    v1 v1,\n    test2.v2 v2,\n    f1() f1,\n    test2.f2() f2,\n    (\n      select count(*) as s1 from DataverseSyn1\n        where DataverseName like \"te%\"\n    ) s1,\n    (\n      select count(*) as s2 from test2.DataverseSyn2\n        where DataverseName like \"tes%\"\n    ) s2,\n  [...]
+{ "DataverseName": "test2", "DatasetName": "v2", "DatatypeDataverseName": "Metadata", "DatatypeName": "AnyObject", "ViewDetails": { "Definition": "select sum(r) as v2 from range(1,2) r", "Dependencies": [ [  ], [  ], [  ] ] } }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.5.adm
new file mode 100644
index 0000000..f9bc681
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.5.adm
@@ -0,0 +1 @@
+{ "d1": 2, "s2": 2, "s1": 2, "f2": 2, "f1": 2, "v2": 3, "v1": 6 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.6.adm
new file mode 100644
index 0000000..ccb58cd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.6.adm
@@ -0,0 +1 @@
+{ "DataverseName": "test1", "DatasetName": "vA", "DatatypeDataverseName": "Metadata", "DatatypeName": "AnyObject", "ViewDetails": { "Definition": "select v1.*, v2.*, f1.*, f2.*, s1.*, s2.*, d1.*\n  from\n    v1 v1,\n    test2.v2 v2,\n    f1() f1,\n    test2.f2() f2,\n    (\n      select count(*) as s1 from DataverseSyn1\n        where DataverseName like \"te%\"\n    ) s1,\n    (\n      select count(*) as s2 from test2.DataverseSyn2\n        where DataverseName like \"tes%\"\n    ) s2,\n  [...]
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.8.adm
new file mode 100644
index 0000000..7b4ad0c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.8.adm
@@ -0,0 +1,2 @@
+{ "r": 1 }
+{ "r": 2 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.9.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.9.adm
new file mode 100644
index 0000000..991315f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/create-view-1/create-view-1.9.adm
@@ -0,0 +1 @@
+{ "DataverseName": "test1", "DatasetName": "vB", "DatatypeDataverseName": "Metadata", "DatatypeName": "AnyObject", "ViewDetails": { "Definition": "select r from range(1,2) r", "Dependencies": [ [  ], [  ], [  ] ] } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-1/drop-view-1.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-1/drop-view-1.2.adm
new file mode 100644
index 0000000..bacb60c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-1/drop-view-1.2.adm
@@ -0,0 +1 @@
+{ "cnt": 0 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.10.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.10.adm
new file mode 100644
index 0000000..7b4ad0c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.10.adm
@@ -0,0 +1,2 @@
+{ "r": 1 }
+{ "r": 2 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.12.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.12.adm
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.12.adm
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.14.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.14.adm
new file mode 100644
index 0000000..7b4ad0c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.14.adm
@@ -0,0 +1,2 @@
+{ "r": 1 }
+{ "r": 2 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.16.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.16.adm
new file mode 100644
index 0000000..7b4ad0c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.16.adm
@@ -0,0 +1,2 @@
+{ "r": 1 }
+{ "r": 2 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.4.adm
new file mode 100644
index 0000000..7b4ad0c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.4.adm
@@ -0,0 +1,2 @@
+{ "r": 1 }
+{ "r": 2 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.6.adm
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.6.adm
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.8.adm
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/drop-view-2-negative/drop-view-2-negative.8.adm
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.3.adm
new file mode 100644
index 0000000..a42eb92
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.3.adm
@@ -0,0 +1,10 @@
+{ "c1": 0, "c2": 9 }
+{ "c1": 1, "c2": 8 }
+{ "c1": 2, "c2": 7 }
+{ "c1": 3, "c2": 6 }
+{ "c1": 4, "c2": 5 }
+{ "c1": 5, "c2": 4 }
+{ "c1": 6, "c2": 3 }
+{ "c1": 7, "c2": 2 }
+{ "c1": 8, "c2": 1 }
+{ "c1": 9, "c2": 0 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.4.adm
new file mode 100644
index 0000000..0c0c564
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.4.adm
@@ -0,0 +1,3 @@
+{ "Kind": "FUNCTION", "Name": "f5", "Definition": "select c1, c2 from s4", "Dependencies": [ [  ], [  ], [  ], [ [ "test1", "s4" ] ] ] }
+{ "Kind": "VIEW", "Name": "v3", "Definition": "select c1, c2 from s2", "Dependencies": [ [  ], [  ], [  ], [ [ "test1", "s2" ] ] ] }
+{ "Kind": "VIEW", "Name": "v6", "Definition": "select c1, c2 from f5() f5", "Dependencies": [ [  ], [ [ "test1", "f5", "0" ] ], [  ] ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.7.adm
new file mode 100644
index 0000000..554bf72
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.7.adm
@@ -0,0 +1 @@
+{ "c": 36, "c1": [ 0, 1, 2 ], "c2": [ 0, 1, 2 ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.8.adm
new file mode 100644
index 0000000..98d2942
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/view/view-1/view-1.8.adm
@@ -0,0 +1,5 @@
+{ "Kind": "FUNCTION", "Name": "f5", "Dependencies": [ [ [ "test2", "v3" ] ], [  ], [  ] ] }
+{ "Kind": "FUNCTION", "Name": "f6", "Dependencies": [ [ [ "test2", "v4" ] ], [  ], [  ] ] }
+{ "Kind": "VIEW", "Name": "v3", "Dependencies": [ [ [ "test2", "ds1" ], [ "test2", "ds2" ] ], [  ], [  ] ] }
+{ "Kind": "VIEW", "Name": "v4", "Dependencies": [ [ [ "test2", "ds1" ], [ "test2", "ds2" ] ], [  ], [  ] ] }
+{ "Kind": "VIEW", "Name": "v9", "Dependencies": [ [ [ "test2", "ds1" ], [ "test2", "ds2" ], [ "test2", "v3" ], [ "test2", "v4" ] ], [ [ "test2", "f5", "0" ], [ "test2", "f6", "0" ] ], [  ], [ [ "test2", "s7" ], [ "test2", "s8" ] ] ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_it_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_it_sqlpp.xml
index 6c67216..85fe2c5 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_it_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_it_sqlpp.xml
@@ -27,7 +27,7 @@
       <compilation-unit name="bad-ext-function-ddl-1">
         <output-dir compare="Text">none</output-dir>
         <expected-error>ASX1079: Compilation error: Variable number of parameters is not supported for external functions</expected-error>
-        <expected-error>ASX1001: Syntax error: Unexpected IF NOT EXISTS (in line 25, at column 1)</expected-error>
+        <expected-error>ASX1001: Syntax error: Unexpected IF NOT EXISTS (in line 25, at column 57)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="external-library">
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 02b5721..9a92a6c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -4239,6 +4239,16 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="ddl">
+      <compilation-unit name="invalid-view-name">
+        <output-dir compare="Text">none</output-dir>
+        <expected-error>ASX1115: Invalid name for a database object: "" (in line 29, at column 1)</expected-error>
+        <expected-error>ASX1115: Invalid name for a database object: " a" (in line 29, at column 1)</expected-error>
+        <expected-error>ASX1115: Invalid name for a database object: " invalid" (in line 29, at column 1)</expected-error>
+        <expected-error>ASX1115: Invalid name for a database object: "a/b" (in line 29, at column 13)</expected-error>
+        <expected-error>ASX1115: Invalid name for a database object: "c/d" (in line 32, at column 11)</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="ddl">
       <compilation-unit name="dataset-and-index-same-dataverse">
         <output-dir compare="Text">dataset-and-index-same-dataverse</output-dir>
       </compilation-unit>
@@ -12602,7 +12612,7 @@
         <expected-error>ASX1001: Syntax error: Unexpected type declaration for parameter a in function myfn001</expected-error>
         <expected-error>ASX1001: Syntax error: Unexpected return type declaration for function myfn002</expected-error>
         <expected-error>ASX1001: Syntax error: Unexpected return type declaration for function myfn003</expected-error>
-        <expected-error>ASX1001: Syntax error: Unexpected IF NOT EXISTS (in line 29, at column 1)</expected-error>
+        <expected-error>ASX1001: Syntax error: Unexpected IF NOT EXISTS (in line 29, at column 45)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="user-defined-functions">
@@ -12628,8 +12638,8 @@
     <test-case FilePath="user-defined-functions">
       <compilation-unit name="drop-dependency-2">
         <output-dir compare="Text">drop-dependency-2</output-dir>
-        <expected-error>ASX1147: Cannot drop dataverse: dataset C.TweetMessages being used by function B.f2(2)</expected-error>
-        <expected-error>ASX1147: Cannot drop dataverse: dataset C.TweetMessages being used by function B.f3(...)</expected-error>
+        <expected-error>ASX1147: Cannot drop dataverse: dataset (or view) C.TweetMessages being used by function B.f2(2)</expected-error>
+        <expected-error>ASX1147: Cannot drop dataverse: dataset (or view) C.TweetMessages being used by function B.f3(...)</expected-error>
         <source-location>false</source-location>
       </compilation-unit>
     </test-case>
@@ -12912,14 +12922,14 @@
     <test-case FilePath="user-defined-functions">
       <compilation-unit name="udf37_recursion">
         <output-dir compare="Text">none</output-dir>
-        <expected-error>ASX1149: Illegal function recursion (in line 24, at column 1)</expected-error>
-        <expected-error>ASX1149: Illegal function recursion (in line 25, at column 1)</expected-error>
-        <expected-error>ASX1149: Illegal function recursion (in line 26, at column 1)</expected-error>
-        <expected-error>ASX1149: Illegal function recursion (in line 27, at column 1)</expected-error>
-        <expected-error>ASX1149: Illegal function recursion (in line 28, at column 1)</expected-error>
-        <expected-error>ASX1149: Illegal function recursion (in line 29, at column 1)</expected-error>
-        <expected-error>ASX1149: Illegal function recursion (in line 30, at column 1)</expected-error>
-        <expected-error>ASX1149: Illegal function recursion (in line 31, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 24, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 25, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 26, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 27, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 28, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 29, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 30, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 31, at column 1)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="user-defined-functions">
@@ -12965,6 +12975,70 @@
       </compilation-unit>
     </test-case>
   </test-group>
+  <test-group name="view">
+    <test-case FilePath="view">
+      <compilation-unit name="create-view-1">
+        <output-dir compare="Text">create-view-1</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="view">
+      <compilation-unit name="create-view-2-negative">
+        <output-dir compare="Text">none</output-dir>
+        <expected-error>ASX1063: Cannot find dataverse with name test (in line 24, at column 1)</expected-error>
+        <expected-error><![CDATA[ASX1001: Syntax error: In line 25 >>create view test.v1 as select * from range(1,2) r order by;<< Encountered ";" at column 59]]></expected-error>
+        <expected-error>ASX1081: Cannot find function with signature test.undefined_range(2) (in line 25, at column 38)</expected-error>
+        <expected-error>ASX1160: A view with this name test.v1 already exists (in line 26, at column 1)</expected-error>
+        <expected-error>ASX1072: A dataset with name ds1 already exists in dataverse test (in line 30, at column 1)</expected-error>
+        <expected-error>ASX1072: A dataset with name ds2 already exists in dataverse test (in line 30, at column 1)</expected-error>
+        <expected-error>ASX1160: A view with this name test.ds1 already exists (in line 27, at column 1)</expected-error>
+        <expected-error><![CDATA[ASX1001: Syntax error: Unexpected IF NOT EXISTS (in line 25, at column 39)]]></expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 31, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 32, at column 1)</expected-error>
+        <expected-error>ASX1149: Illegal function or view recursion (in line 33, at column 1)</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="view">
+      <compilation-unit name="drop-dataverse-1">
+        <output-dir compare="Text">none</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="view">
+      <compilation-unit name="drop-dataverse-2-negative">
+        <output-dir compare="Text">none</output-dir>
+        <expected-error>ASX1147: Cannot drop dataverse: dataset (or view) test2.v2 being used by view test1.v1</expected-error>
+        <expected-error>ASX1147: Cannot drop dataverse: dataset (or view) test2.v2 being used by function test1.f1()</expected-error>
+        <expected-error>ASX1147: Cannot drop dataverse: dataset (or view) test2.ds2 being used by view test1.v1</expected-error>
+        <expected-error>ASX1147: Cannot drop dataverse: function test2.f2() being used by view test1.v1</expected-error>
+        <expected-error>ASX1147: Cannot drop dataverse: synonym test2.s3 being used by view test1.v1</expected-error>
+        <source-location>false</source-location>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="view">
+      <compilation-unit name="drop-view-1">
+        <output-dir compare="Text">drop-view-1</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="view">
+      <compilation-unit name="drop-view-2-negative">
+        <output-dir compare="Text">drop-view-2-negative</output-dir>
+        <expected-error>ASX1063: Cannot find dataverse with name test (in line 24, at column 1)</expected-error>
+        <expected-error>ASX1159: Cannot find view with name test.v1 (in line 25, at column 1)</expected-error>
+        <expected-error>ASX1050: Cannot find dataset with name v1 in dataverse test (in line 27, at column 1)</expected-error>
+        <expected-error>ASX1159: Cannot find view with name test.ds1 (in line 30, at column 1)</expected-error>
+        <expected-error>ASX1148: Cannot drop dataset test2.ds2 being used by view test1.v1</expected-error>
+        <expected-error>ASX1148: Cannot drop function test2.f2() being used by view test1.v1</expected-error>
+        <expected-error>ASX1148: Cannot drop synonym test2.s2 being used by view test1.v1</expected-error>
+        <expected-error>ASX1148: Cannot drop view test2.v2 being used by view test1.v1</expected-error>
+        <expected-error>ASX1148: Cannot drop view test2.v2 being used by function test1.f1()</expected-error>
+        <source-location>false</source-location>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="view">
+      <compilation-unit name="view-1">
+        <output-dir compare="Text">view-1</output-dir>
+      </compilation-unit>
+    </test-case>
+  </test-group>
   <test-group name="load">
     <test-case FilePath="load">
       <compilation-unit name="load_non-empty_index">
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/DatasetConfig.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/DatasetConfig.java
index f673d24..b85c0be 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/DatasetConfig.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/DatasetConfig.java
@@ -30,7 +30,8 @@ public class DatasetConfig {
      */
     public enum DatasetType {
         INTERNAL,
-        EXTERNAL
+        EXTERNAL,
+        VIEW
     }
 
     public enum IndexType {
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index 1f25cc1..f9bcafc 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -233,7 +233,7 @@ public enum ErrorCode implements IError {
     UNKNOWN_FEED_POLICY(1146),
     CANNOT_DROP_DATAVERSE_DEPENDENT_EXISTS(1147),
     CANNOT_DROP_OBJECT_DEPENDENT_EXISTS(1148),
-    ILLEGAL_FUNCTION_RECURSION(1149),
+    ILLEGAL_FUNCTION_OR_VIEW_RECURSION(1149),
     ILLEGAL_FUNCTION_USE(1150),
     NO_AUTH_PROVIDED_ENDPOINT_REQUIRED_FOR_ANONYMOUS_ACCESS(1151),
     FULL_TEXT_CONFIG_NOT_FOUND(1152),
@@ -242,6 +242,9 @@ public enum ErrorCode implements IError {
     COMPILATION_INCOMPATIBLE_INDEX_TYPE(1155),
     FULL_TEXT_CONFIG_ALREADY_EXISTS(1156),
     FULL_TEXT_FILTER_ALREADY_EXISTS(1157),
+    COMPILATION_BAD_VIEW_DEFINITION(1158),
+    UNKNOWN_VIEW(1159),
+    VIEW_EXISTS(1160),
 
     // Feed errors
     DATAFLOW_ILLEGAL_STATE(3001),
diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index e68db6a..58e8f1f 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -235,7 +235,7 @@
 1146 = Cannot find feed policy with name %1$s
 1147 = Cannot drop dataverse: %1$s %2$s being used by %3$s %4$s
 1148 = Cannot drop %1$s %2$s being used by %3$s %4$s
-1149 = Illegal function recursion
+1149 = Illegal function or view recursion
 1150 = Illegal use of function %1$s
 1151 = No authentication credentials provided, '%1$s' field is required for anonymous access
 1152 = Full-text config %1$s not found
@@ -244,6 +244,9 @@
 1155 = Incompatible index type %1$s
 1156 = Full-text config %1$s already exists
 1157 = Full-text filter %1$s already exists
+1158 = Error compiling view %1$s. %2$s
+1159 = Cannot find view with name %1$s
+1160 = A view with this name %1$s already exists
 
 # Feed Errors
 3001 = Illegal state.
diff --git a/asterixdb/asterix-doc/src/main/grammar/sqlpp.ebnf b/asterixdb/asterix-doc/src/main/grammar/sqlpp.ebnf
index db89fe0..8dd08fa 100644
--- a/asterixdb/asterix-doc/src/main/grammar/sqlpp.ebnf
+++ b/asterixdb/asterix-doc/src/main/grammar/sqlpp.ebnf
@@ -149,6 +149,7 @@ CreateStmnt ::= CreateDataverse
               | CreateIndex
               | CreateSynonym
               | CreateFunction
+              | CreateView
 
 DataverseName ::= Identifier ("." Identifier)*
 
@@ -240,8 +241,10 @@ FunctionParameters ::=  ( Identifier ((":")? TypeExpr)? ("," Identifier ((":")?
 
 ExternalFunctionDef ::= ("RETURNS" TypeExpr)? "AS" StringLiteral ("," StringLiteral )* "AT" QualifiedName ("WITH" ObjectConstructor)?
 
+CreateView ::= "CREATE" ("OR" "REPLACE")? "VIEW" QualifiedName ("IF" "NOT" "EXISTS")? "AS" Selection
+
 DropStmnt ::= "DROP" ("DATAVERSE" DataverseName
-                     | ("TYPE" |"DATASET" | "SYNONYM") QualifiedName
+                     | ("TYPE" |"DATASET" |"SYNONYM" |"VIEW") QualifiedName
                      | "INDEX" DoubleQualifiedName
                      | "FUNCTION" FunctionSignature ) ("IF" "EXISTS")?
 
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/0_toc.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/0_toc.md
index 47ed4e7..01ea63c 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/0_toc.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/0_toc.md
@@ -81,6 +81,7 @@
 			* [Create Index](#Indices)
 			* [Create Synonym](#Synonyms)
 			* [Create Function](#Create_function)
+			* [Create View](#Create_view)
 		   * [Drop Statement](#Removal)
 		   * [Load Statement](#Load_statement)
       * [Modification Statements](#Modification_statements)
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/7_ddl_dml.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/7_ddl_dml.md
index 1569d69..967b277 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/7_ddl_dml.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/7_ddl_dml.md
@@ -451,9 +451,10 @@ The primary-key index can be identified by the fact that the `SearchKey` field i
 ##### CreateSynonym
 ![](../images/diagrams/CreateSynonym.png)
 
-The `CREATE SYNONYM` statement creates a synonym for a given dataset.
-This synonym may be used instead of the dataset name in `SELECT`, `INSERT`, `UPSERT`, `DELETE`, and `LOAD` statements.
-The target dataset does not need to exist when the synonym is created.
+The `CREATE SYNONYM` statement creates a synonym for a given dataset or a view.
+This synonym may be used instead of the dataset name in `SELECT`, `INSERT`, `UPSERT`, `DELETE`, and `LOAD` statements, 
+or instead of the view name in `SELECT` statements.
+The target dataset or view does not need to exist when the synonym is created.
 A synonym may be created for another synonym.
 
 ##### Example
@@ -519,6 +520,25 @@ would be as follows
 
     CREATE FUNCTION sentiment(a) AS "sentiment_mod", "sent_model.sentiment" AT pylib;
 
+#### <a id="Create_view">Create View</a>
+
+The `CREATE VIEW` statement creates a **named** view that can then be used in queries.
+The body of a view can be any `SELECT` statement.
+
+##### CreateView
+![](../images/diagrams/CreateView.png)
+
+##### Example
+
+    CREATE DATASET customers(customersType) PRIMARY KEY custid;
+
+    CREATE VIEW customersView AS 
+        SELECT c.custid, c.name
+        FROM customers AS c 
+        WHERE c.address.city = "Boston, MA";
+
+    SELECT * FROM customersView;
+
 ### <a id="Removal">Drop Statement</a>
 
 ##### DropStmnt
@@ -555,6 +575,8 @@ The following examples illustrate some uses of the `DROP` statement.
 
     DROP SYNONYM customersSynonym;
 
+    DROP VIEW customersView;
+
     DROP DATAVERSE CommerceData;
 
 When an artifact is dropped, it will be droppped from the current dataverse if none is specified
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 a4acbb0..4393f5e 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
@@ -215,7 +215,7 @@ The process of name resolution begins with the leftmost identifier in the name.
 The rules for resolving the leftmost identifier are:
 
 1.  _In a `FROM` clause_: Names in a `FROM` clause identify the collections over which the query block will iterate.
-    These collections may be stored datasets or may be the results of nested query blocks.
+    These collections may be stored datasets, views, synonyms, or may be the results of nested query blocks.
     A stored dataset may be in a named dataverse or in the default dataverse.
     Thus, if the two-part name `a.b` is in a `FROM` clause, a might represent a dataverse and `b` might represent a dataset in that dataverse.
     Another example of a two-part name in a `FROM` clause is `FROM orders AS o, o.items AS i`.
@@ -229,12 +229,13 @@ The rules for resolving the leftmost identifier are:
     - (1B):  Otherwise, if the identifier is the first part of a two-part name like `a.b`, the name is treated as `dataverse.dataset`.
         If the identifier stands alone as a one-part name, it is treated as the name of a dataset in the default dataverse.
         If the designated dataset exists then the identifier is resolved to that dataset,
-        otherwise if a synonym with given name exists then the identifier is resolved to the target dataset of that
+        othwerise if a view with given name exists then the identifier is resolved to that view,
+        otherwise if a synonym with given name exists then the identifier is resolved to the target dataset or the target view of that
         synonym (potentially recursively if this synonym points to another synonym). An error will result if the designated
-        dataset or a synonym with this name does not exist.
+        dataset, view, or a synonym with this name does not exist.
 
-        Datasets take precedence over synonyms, so if both a dataset and a synonym have the same name then the
-        resolution is to the dataset.
+        Datasets and views take precedence over synonyms, so if both a dataset (or a view) and a synonym have the same name then the
+        resolution is to the dataset. Note that there cannot be a dataset and a view with the same name.
 
 2.  _Elsewhere in a query block_: In clauses other than `FROM`, a name typically identifies a field of some object.
     For example, if the expression `a.b` is in a `SELECT` or `WHERE` clause, it's likely that `a` represents an object and `b` represents a field in that object.
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
index 3df490c..1645d76 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
@@ -23,7 +23,9 @@ import java.util.List;
 
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.ViewDecl;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 import org.apache.hyracks.api.exceptions.Warning;
 
@@ -38,6 +40,8 @@ public interface IParser {
     FunctionDecl parseFunctionBody(FunctionSignature signature, List<String> paramNames, boolean isStored)
             throws CompilationException;
 
+    ViewDecl parseViewBody(DatasetFullyQualifiedName viewName) throws CompilationException;
+
     /**
      * Gets the warnings generated during parsing
      */
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java
index f28de55..6099cb6 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java
@@ -25,6 +25,9 @@ import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.lang.common.expression.AbstractCallExpression;
 import org.apache.asterix.lang.common.expression.VariableExpr;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.statement.ViewDecl;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 
 public interface IQueryRewriter {
@@ -37,13 +40,12 @@ public interface IQueryRewriter {
      *          rewriting context
      * @param allowNonStoredUdfCalls
      *          whether calls to non-stored user-defined functions should be resolved
-     * @param inlineUdfs
+     * @param inlineUdfsAndViews
      *          whether user defined functions should be inlines
      * @param externalVars
-     *          statement parameters (external variables)
      */
     void rewrite(LangRewritingContext context, IReturningStatement topExpr, boolean allowNonStoredUdfCalls,
-            boolean inlineUdfs, Collection<VarIdentifier> externalVars) throws CompilationException;
+            boolean inlineUdfsAndViews, Collection<VarIdentifier> externalVars) throws CompilationException;
 
     /**
      * Find the function calls used by a given expression
@@ -55,4 +57,12 @@ public interface IQueryRewriter {
      * Find all external variables (positional and named variables) in given expression
      */
     Set<VariableExpr> getExternalVariables(Expression expr) throws CompilationException;
+
+    VarIdentifier toExternalVariableName(String statementParameterName);
+
+    String toFunctionParameterName(VarIdentifier paramVar);
+
+    Query createFunctionAccessorQuery(FunctionDecl functionDecl);
+
+    Query createViewAccessorQuery(ViewDecl viewDecl);
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
index 9d983b0..f50d040 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
@@ -19,7 +19,6 @@
 package org.apache.asterix.lang.common.base;
 
 import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 
 public interface IStatementRewriter {
@@ -36,8 +35,4 @@ public interface IStatementRewriter {
      *            a metadata provider
      */
     void rewrite(Statement statement, MetadataProvider metadataProvider) throws CompilationException;
-
-    String toExternalVariableName(String statementParameterName);
-
-    String toFunctionParameterName(VarIdentifier paramVar);
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Statement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Statement.java
index 182fc08..663074e 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Statement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Statement.java
@@ -58,6 +58,7 @@ public interface Statement extends ILangExpression {
         UPSERT,
         UPDATE,
         FUNCTION_DECL,
+        VIEW_DECL,
         LOAD,
         NODEGROUP_DECL,
         NODEGROUP_DROP,
@@ -68,6 +69,7 @@ public interface Statement extends ILangExpression {
         WRITE,
         CREATE_INDEX,
         CREATE_DATAVERSE,
+        CREATE_VIEW,
         CREATE_FULL_TEXT_FILTER,
         CREATE_FULL_TEXT_CONFIG,
         INDEX_DROP,
@@ -89,6 +91,7 @@ public interface Statement extends ILangExpression {
         LIBRARY_DROP,
         CREATE_SYNONYM,
         SYNONYM_DROP,
+        VIEW_DROP,
         COMPACT,
         EXTERNAL_DATASET_REFRESH,
         SUBSCRIBE_FEED,
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 675d0d3..95cccb0 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
@@ -18,14 +18,16 @@
  */
 package org.apache.asterix.lang.common.rewrites;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.ViewDecl;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.hyracks.algebricks.core.algebra.base.Counter;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
@@ -34,15 +36,17 @@ public final class LangRewritingContext {
     private final MetadataProvider metadataProvider;
     private final IWarningCollector warningCollector;
     private final Map<FunctionSignature, FunctionDecl> declaredFunctions;
+    private final Map<DatasetFullyQualifiedName, ViewDecl> declaredViews;
     private final Counter varCounter;
     private int systemVarCounter = 1;
     private final Map<Integer, VarIdentifier> oldVarIdToNewVarId = new HashMap<>();
 
     public LangRewritingContext(MetadataProvider metadataProvider, List<FunctionDecl> declaredFunctions,
-            IWarningCollector warningCollector, int varCounter) {
+            List<ViewDecl> declaredViews, IWarningCollector warningCollector, int varCounter) {
         this.metadataProvider = metadataProvider;
         this.warningCollector = warningCollector;
-        this.declaredFunctions = FunctionUtil.getFunctionMap(declaredFunctions);
+        this.declaredFunctions = createMap(declaredFunctions, FunctionDecl::getSignature);
+        this.declaredViews = createMap(declaredViews, ViewDecl::getViewName);
         this.varCounter = new Counter(varCounter);
     }
 
@@ -93,4 +97,19 @@ public final class LangRewritingContext {
     public Map<FunctionSignature, FunctionDecl> getDeclaredFunctions() {
         return declaredFunctions;
     }
+
+    public Map<DatasetFullyQualifiedName, ViewDecl> getDeclaredViews() {
+        return declaredViews;
+    }
+
+    private static <K, V> Map<K, V> createMap(List<V> values, java.util.function.Function<V, K> keyMapper) {
+        if (values == null || values.isEmpty()) {
+            return Collections.emptyMap();
+        }
+        Map<K, V> result = new HashMap<>();
+        for (V v : values) {
+            result.put(keyMapper.apply(v), v);
+        }
+        return Collections.unmodifiableMap(result);
+    }
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateViewStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateViewStatement.java
new file mode 100644
index 0000000..97420ea
--- /dev/null
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateViewStatement.java
@@ -0,0 +1,94 @@
+/*
+ * 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.common.statement;
+
+import static org.apache.asterix.lang.common.base.Statement.Kind.CREATE_VIEW;
+
+import java.util.Objects;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.lang.common.base.AbstractStatement;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+
+public final class CreateViewStatement extends AbstractStatement {
+
+    private final DataverseName dataverseName;
+
+    private final String viewName;
+
+    private final String viewBody;
+
+    private final Expression viewBodyExpression;
+
+    private final boolean replaceIfExists;
+
+    private final boolean ifNotExists;
+
+    public CreateViewStatement(DataverseName dataverseName, String viewName, String viewBody,
+            Expression viewBodyExpression, boolean replaceIfExists, boolean ifNotExists) {
+        this.dataverseName = dataverseName;
+        this.viewName = Objects.requireNonNull(viewName);
+        this.viewBody = Objects.requireNonNull(viewBody);
+        this.viewBodyExpression = Objects.requireNonNull(viewBodyExpression);
+        this.replaceIfExists = replaceIfExists;
+        this.ifNotExists = ifNotExists;
+    }
+
+    public DataverseName getDataverseName() {
+        return dataverseName;
+    }
+
+    public String getViewName() {
+        return viewName;
+    }
+
+    public String getViewBody() {
+        return viewBody;
+    }
+
+    public Expression getViewBodyExpression() {
+        return viewBodyExpression;
+    }
+
+    public boolean getReplaceIfExists() {
+        return replaceIfExists;
+    }
+
+    public boolean getIfNotExists() {
+        return ifNotExists;
+    }
+
+    @Override
+    public Kind getKind() {
+        return CREATE_VIEW;
+    }
+
+    @Override
+    public byte getCategory() {
+        return Category.DDL;
+    }
+
+    @Override
+    public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws CompilationException {
+        return visitor.visit(this, arg);
+    }
+}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/ViewDecl.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/ViewDecl.java
new file mode 100644
index 0000000..a3b1937
--- /dev/null
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/ViewDecl.java
@@ -0,0 +1,88 @@
+/*
+ * 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.common.statement;
+
+import java.util.Objects;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
+import org.apache.asterix.lang.common.base.AbstractStatement;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+
+public final class ViewDecl extends AbstractStatement {
+
+    private final DatasetFullyQualifiedName viewName;
+
+    private Expression viewBody;
+
+    private Expression viewBodyNormalized;
+
+    public ViewDecl(DatasetFullyQualifiedName viewName, Expression viewBody) {
+        this.viewName = Objects.requireNonNull(viewName);
+        this.viewBody = Objects.requireNonNull(viewBody);
+    }
+
+    public DatasetFullyQualifiedName getViewName() {
+        return viewName;
+    }
+
+    public Expression getViewBody() {
+        return viewBody;
+    }
+
+    public void setViewBody(Expression expr) {
+        viewBody = expr;
+        viewBodyNormalized = null;
+    }
+
+    public Expression getNormalizedViewBody() {
+        return viewBodyNormalized;
+    }
+
+    public void setNormalizedViewBody(Expression expr) {
+        viewBodyNormalized = expr;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        ViewDecl viewDecl = (ViewDecl) o;
+        return viewName.equals(viewDecl.viewName);
+    }
+
+    @Override
+    public Kind getKind() {
+        return Kind.VIEW_DECL;
+    }
+
+    @Override
+    public byte getCategory() {
+        return Category.QUERY;
+    }
+
+    @Override
+    public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws CompilationException {
+        return visitor.visit(this, arg);
+    }
+}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/ViewDropStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/ViewDropStatement.java
new file mode 100644
index 0000000..9f8577c
--- /dev/null
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/ViewDropStatement.java
@@ -0,0 +1,69 @@
+/*
+ * 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.common.statement;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.lang.common.base.AbstractStatement;
+import org.apache.asterix.lang.common.base.Statement;
+import org.apache.asterix.lang.common.struct.Identifier;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+
+public class ViewDropStatement extends AbstractStatement {
+
+    private final DataverseName dataverseName;
+
+    private final Identifier viewName;
+
+    private final boolean ifExists;
+
+    public ViewDropStatement(DataverseName dataverseName, Identifier viewName, boolean ifExists) {
+        this.dataverseName = dataverseName;
+        this.viewName = viewName;
+        this.ifExists = ifExists;
+    }
+
+    public DataverseName getDataverseName() {
+        return dataverseName;
+    }
+
+    public Identifier getViewName() {
+        return viewName;
+    }
+
+    public boolean getIfExists() {
+        return ifExists;
+    }
+
+    @Override
+    public Kind getKind() {
+        return Statement.Kind.VIEW_DROP;
+    }
+
+    @Override
+    public byte getCategory() {
+        return Category.DDL;
+    }
+
+    @Override
+    public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws CompilationException {
+        return visitor.visit(this, arg);
+    }
+}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/ExpressionUtils.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/ExpressionUtils.java
index dd21152..1fc7234 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/ExpressionUtils.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/ExpressionUtils.java
@@ -18,14 +18,24 @@
  */
 package org.apache.asterix.lang.common.util;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 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.common.metadata.DatasetFullyQualifiedName;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.lang.common.base.AbstractStatement;
 import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.base.Literal;
+import org.apache.asterix.lang.common.expression.AbstractCallExpression;
 import org.apache.asterix.lang.common.expression.FieldBinding;
 import org.apache.asterix.lang.common.expression.ListConstructor;
 import org.apache.asterix.lang.common.expression.LiteralExpr;
@@ -33,6 +43,9 @@ import org.apache.asterix.lang.common.expression.RecordConstructor;
 import org.apache.asterix.lang.common.literal.DoubleLiteral;
 import org.apache.asterix.lang.common.literal.LongIntegerLiteral;
 import org.apache.asterix.lang.common.literal.StringLiteral;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.ViewDecl;
+import org.apache.asterix.lang.common.visitor.GatherFunctionCallsVisitor;
 import org.apache.asterix.object.base.AdmArrayNode;
 import org.apache.asterix.object.base.AdmBigIntNode;
 import org.apache.asterix.object.base.AdmBooleanNode;
@@ -41,6 +54,11 @@ import org.apache.asterix.object.base.AdmNullNode;
 import org.apache.asterix.object.base.AdmObjectNode;
 import org.apache.asterix.object.base.AdmStringNode;
 import org.apache.asterix.object.base.IAdmNode;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+
+import com.google.common.graph.GraphBuilder;
+import com.google.common.graph.Graphs;
+import com.google.common.graph.MutableGraph;
 
 public class ExpressionUtils {
     private ExpressionUtils() {
@@ -113,4 +131,119 @@ public class ExpressionUtils {
         }
         return null;
     }
+
+    public static Boolean getBooleanLiteral(Expression arg) {
+        if (arg.getKind() == Expression.Kind.LITERAL_EXPRESSION) {
+            Literal item = ((LiteralExpr) arg).getValue();
+            switch (item.getLiteralType()) {
+                case TRUE:
+                    return true;
+                case FALSE:
+                    return false;
+            }
+        }
+        return null;
+    }
+
+    public static void collectDependencies(Expression expression, IQueryRewriter rewriter,
+            List<Triple<DataverseName, String, String>> outDatasetDependencies,
+            List<Triple<DataverseName, String, String>> outSynonymDependencies,
+            List<Triple<DataverseName, String, String>> outFunctionDependencies) throws CompilationException {
+        // Duplicate elimination
+        Set<DatasetFullyQualifiedName> seenDatasets = new HashSet<>();
+        Set<DatasetFullyQualifiedName> seenSynonyms = new HashSet<>();
+        Set<FunctionSignature> seenFunctions = new HashSet<>();
+        List<AbstractCallExpression> functionCalls = new ArrayList<>();
+        rewriter.getFunctionCalls(expression, functionCalls);
+
+        for (AbstractCallExpression functionCall : functionCalls) {
+            switch (functionCall.getKind()) {
+                case CALL_EXPRESSION:
+                    FunctionSignature signature = functionCall.getFunctionSignature();
+                    if (FunctionUtil.isBuiltinFunctionSignature(signature)) {
+                        if (FunctionUtil.isBuiltinDatasetFunction(signature)) {
+                            Triple<DatasetFullyQualifiedName, Boolean, DatasetFullyQualifiedName> dsArgs =
+                                    FunctionUtil.parseDatasetFunctionArguments(functionCall);
+                            DatasetFullyQualifiedName synonymReference = dsArgs.third;
+                            if (synonymReference != null) {
+                                // resolved via synonym -> store synonym name as a dependency
+                                if (seenSynonyms.add(synonymReference)) {
+                                    outSynonymDependencies.add(new Triple<>(synonymReference.getDataverseName(),
+                                            synonymReference.getDatasetName(), null));
+                                }
+                            } else {
+                                // resolved directly -> store dataset (or view) name as a dependency
+                                DatasetFullyQualifiedName datasetReference = dsArgs.first;
+                                if (seenDatasets.add(datasetReference)) {
+                                    outDatasetDependencies.add(new Triple<>(datasetReference.getDataverseName(),
+                                            datasetReference.getDatasetName(), null));
+                                }
+                            }
+                        }
+                    } else {
+                        if (seenFunctions.add(signature)) {
+                            outFunctionDependencies.add(new Triple<>(signature.getDataverseName(), signature.getName(),
+                                    Integer.toString(signature.getArity())));
+                        }
+                    }
+                    break;
+                case WINDOW_EXPRESSION:
+                    // there cannot be used-defined window functions
+                    break;
+                default:
+                    throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE,
+                            functionCall.getSourceLocation(), functionCall.getFunctionSignature().toString(false));
+            }
+        }
+    }
+
+    public static boolean hasFunctionOrViewRecursion(Map<FunctionSignature, FunctionDecl> functionDeclMap,
+            Map<DatasetFullyQualifiedName, ViewDecl> viewDeclMap,
+            java.util.function.Function<Collection<AbstractCallExpression>, GatherFunctionCallsVisitor> callVisitorFactory)
+            throws CompilationException {
+        List<AbstractCallExpression> callList = new ArrayList<>();
+        GatherFunctionCallsVisitor callVisitor = callVisitorFactory.apply(callList);
+        MutableGraph<AbstractStatement> callGraph = GraphBuilder.directed().allowsSelfLoops(true).build();
+        for (FunctionDecl from : functionDeclMap.values()) {
+            callList.clear();
+            from.getNormalizedFuncBody().accept(callVisitor, null);
+            for (AbstractCallExpression callExpr : callList) {
+                addToCallGraph(callGraph, from, callExpr, functionDeclMap, viewDeclMap);
+            }
+        }
+        for (ViewDecl from : viewDeclMap.values()) {
+            callList.clear();
+            from.getNormalizedViewBody().accept(callVisitor, null);
+            for (AbstractCallExpression callExpr : callList) {
+                addToCallGraph(callGraph, from, callExpr, functionDeclMap, viewDeclMap);
+            }
+        }
+        return Graphs.hasCycle(callGraph);
+    }
+
+    private static void addToCallGraph(MutableGraph<AbstractStatement> callGraph, AbstractStatement from,
+            AbstractCallExpression callExpr, Map<FunctionSignature, FunctionDecl> functionDeclMap,
+            Map<DatasetFullyQualifiedName, ViewDecl> viewDeclMap) throws CompilationException {
+        if (callExpr.getKind() == Expression.Kind.CALL_EXPRESSION) {
+            FunctionSignature callSignature = callExpr.getFunctionSignature();
+            if (FunctionUtil.isBuiltinFunctionSignature(callSignature)) {
+                if (FunctionUtil.isBuiltinDatasetFunction(callSignature)) {
+                    Triple<DatasetFullyQualifiedName, Boolean, DatasetFullyQualifiedName> dsArgs =
+                            FunctionUtil.parseDatasetFunctionArguments(callExpr);
+                    if (Boolean.TRUE.equals(dsArgs.second)) {
+                        DatasetFullyQualifiedName viewName = dsArgs.first;
+                        ViewDecl vdTo = viewDeclMap.get(viewName);
+                        if (vdTo != null) {
+                            callGraph.putEdge(from, vdTo);
+                        }
+                    }
+                }
+            } else {
+                FunctionDecl fdTo = functionDeclMap.get(callSignature);
+                if (fdTo != null) {
+                    callGraph.putEdge(from, fdTo);
+                }
+            }
+        }
+    }
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
index ded91af..42a35f3 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
@@ -23,12 +23,9 @@ import java.io.StringReader;
 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;
 import java.util.Objects;
-import java.util.Set;
 import java.util.function.BiFunction;
 
 import org.apache.asterix.common.exceptions.AsterixException;
@@ -36,19 +33,18 @@ import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.common.functions.FunctionConstants;
 import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.IParser;
 import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.expression.AbstractCallExpression;
-import org.apache.asterix.lang.common.expression.CallExpr;
 import org.apache.asterix.lang.common.expression.OrderedListTypeDefinition;
 import org.apache.asterix.lang.common.expression.TypeExpression;
 import org.apache.asterix.lang.common.expression.TypeReferenceExpression;
 import org.apache.asterix.lang.common.expression.UnorderedListTypeDefinition;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
-import org.apache.asterix.lang.common.visitor.GatherFunctionCallsVisitor;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.entities.BuiltinTypeMap;
 import org.apache.asterix.metadata.entities.Dataverse;
@@ -60,7 +56,6 @@ import org.apache.asterix.om.types.TypeSignature;
 import org.apache.asterix.om.utils.ConstantExpressionUtil;
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
@@ -68,10 +63,6 @@ import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 import org.apache.hyracks.api.exceptions.SourceLocation;
 
-import com.google.common.graph.GraphBuilder;
-import com.google.common.graph.Graphs;
-import com.google.common.graph.MutableGraph;
-
 public class FunctionUtil {
 
     public static final String IMPORT_PRIVATE_FUNCTIONS = "import-private-functions";
@@ -208,79 +199,22 @@ public class FunctionUtil {
         };
     }
 
-    public static void checkFunctionRecursion(Map<FunctionSignature, FunctionDecl> functionDeclMap,
-            java.util.function.Function<Collection<AbstractCallExpression>, GatherFunctionCallsVisitor> gfcFactory,
-            SourceLocation sourceLoc) throws CompilationException {
-        List<AbstractCallExpression> callList = new ArrayList<>();
-        GatherFunctionCallsVisitor gfc = gfcFactory.apply(callList);
-        MutableGraph<FunctionDecl> graph = GraphBuilder.directed().allowsSelfLoops(true).build();
-        for (FunctionDecl fdFrom : functionDeclMap.values()) {
-            callList.clear();
-            fdFrom.getNormalizedFuncBody().accept(gfc, null);
-            for (AbstractCallExpression callExpr : callList) {
-                if (callExpr.getKind() == Expression.Kind.CALL_EXPRESSION) {
-                    FunctionSignature callSignature = callExpr.getFunctionSignature();
-                    FunctionDecl fdTo = functionDeclMap.get(callSignature);
-                    if (fdTo != null) {
-                        graph.putEdge(fdFrom, fdTo);
-                    }
-                }
-            }
+    public static List<List<Triple<DataverseName, String, String>>> getFunctionDependencies(FunctionDecl fd,
+            IQueryRewriter rewriter) throws CompilationException {
+        Expression normBody = fd.getNormalizedFuncBody();
+        if (normBody == null) {
+            throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, fd.getSourceLocation(),
+                    fd.getSignature().toString());
         }
-        if (Graphs.hasCycle(graph)) {
-            throw new CompilationException(ErrorCode.ILLEGAL_FUNCTION_RECURSION, sourceLoc);
-        }
-    }
 
-    public static List<List<Triple<DataverseName, String, String>>> getFunctionDependencies(IQueryRewriter rewriter,
-            Expression expression) throws CompilationException {
-        List<AbstractCallExpression> functionCalls = new ArrayList<>();
-        rewriter.getFunctionCalls(expression, functionCalls);
-        // Duplicate elimination
-        Set<FunctionSignature> seenFunctions = new HashSet<>();
-        Set<Pair<DataverseName, String>> seenDatasets = new HashSet<>();
-        Set<Pair<DataverseName, String>> seenSynonyms = new HashSet<>();
-        //Get the List of used functions and used datasets
+        // Get the list of used functions and used datasets
         List<Triple<DataverseName, String, String>> datasetDependencies = new ArrayList<>();
+        List<Triple<DataverseName, String, String>> synonymDependencies = new ArrayList<>();
         List<Triple<DataverseName, String, String>> functionDependencies = new ArrayList<>();
+        ExpressionUtils.collectDependencies(normBody, rewriter, datasetDependencies, synonymDependencies,
+                functionDependencies);
+
         List<Triple<DataverseName, String, String>> typeDependencies = Collections.emptyList();
-        List<Triple<DataverseName, String, String>> synonymDependencies = new ArrayList<>();
-        for (AbstractCallExpression functionCall : functionCalls) {
-            switch (functionCall.getKind()) {
-                case CALL_EXPRESSION:
-                    FunctionSignature signature = functionCall.getFunctionSignature();
-                    if (isBuiltinDatasetFunction(signature)) {
-                        CallExpr callExpr = (CallExpr) functionCall;
-                        if (callExpr.getExprList().size() > 2) {
-                            // resolved via synonym -> store synonym name as a dependency
-                            Pair<DataverseName, String> synonymReference = parseDatasetFunctionArguments(callExpr, 2);
-                            if (seenSynonyms.add(synonymReference)) {
-                                synonymDependencies
-                                        .add(new Triple<>(synonymReference.first, synonymReference.second, null));
-                            }
-                        } else {
-                            // resolved directly -> store dataset name as a dependency
-                            Pair<DataverseName, String> datasetReference = parseDatasetFunctionArguments(callExpr, 0);
-                            if (seenDatasets.add(datasetReference)) {
-                                datasetDependencies
-                                        .add(new Triple<>(datasetReference.first, datasetReference.second, null));
-                            }
-                        }
-                    } else if (BuiltinFunctions.getBuiltinFunctionInfo(signature.createFunctionIdentifier()) == null) {
-                        if (seenFunctions.add(signature)) {
-                            functionDependencies.add(new Triple<>(signature.getDataverseName(), signature.getName(),
-                                    Integer.toString(signature.getArity())));
-                        }
-                    }
-                    break;
-                case WINDOW_EXPRESSION:
-                    // there cannot be used-defined window functions
-                    break;
-                default:
-                    throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, expression.getSourceLocation(),
-                            functionCall.getFunctionSignature().toString(false));
-            }
-        }
         return Function.createDependencies(datasetDependencies, functionDependencies, typeDependencies,
                 synonymDependencies);
     }
@@ -303,27 +237,27 @@ public class FunctionUtil {
                 && Objects.equals(FN_DATASET_NAME, fs.getName());
     }
 
-    public static Pair<DataverseName, String> parseDatasetFunctionArguments(CallExpr datasetFn)
-            throws CompilationException {
-        return parseDatasetFunctionArguments(datasetFn, 0);
-    }
-
-    public static Pair<DataverseName, String> parseDatasetFunctionArguments(CallExpr datasetFn, int startPos)
-            throws CompilationException {
-        return parseDatasetFunctionArguments(datasetFn.getExprList(), startPos, datasetFn.getSourceLocation(),
-                ExpressionUtils::getStringLiteral);
+    public static Triple<DatasetFullyQualifiedName, Boolean, DatasetFullyQualifiedName> parseDatasetFunctionArguments(
+            AbstractCallExpression datasetFn) throws CompilationException {
+        List<Expression> argList = datasetFn.getExprList();
+        DatasetFullyQualifiedName datasetOrViewName = parseDatasetFunctionArguments(argList, 0,
+                datasetFn.getSourceLocation(), ExpressionUtils::getStringLiteral);
+        boolean isView = argList.size() > 2 && Boolean.TRUE.equals(ExpressionUtils.getBooleanLiteral(argList.get(2)));
+        DatasetFullyQualifiedName synonymName = argList.size() > 3 ? parseDatasetFunctionArguments(argList, 3,
+                datasetFn.getSourceLocation(), ExpressionUtils::getStringLiteral) : null;
+        return new Triple<>(datasetOrViewName, isView, synonymName);
     }
 
-    public static Pair<DataverseName, String> parseDatasetFunctionArguments(AbstractFunctionCallExpression datasetFn)
+    public static DatasetFullyQualifiedName parseDatasetFunctionArguments(AbstractFunctionCallExpression datasetFn)
             throws CompilationException {
         return parseDatasetFunctionArguments(datasetFn.getArguments(), 0, datasetFn.getSourceLocation(),
                 FunctionUtil::getStringConstant);
     }
 
-    private static <T> Pair<DataverseName, String> parseDatasetFunctionArguments(List<T> datasetFnArgs, int startPos,
-            SourceLocation sourceLoc, java.util.function.Function<T, String> argExtractFunction)
+    private static <T> DatasetFullyQualifiedName parseDatasetFunctionArguments(List<T> datasetFnArgs, int startPos,
+            SourceLocation sourceLoc, java.util.function.Function<T, String> stringAccessor)
             throws CompilationException {
-        String dataverseNameArg = argExtractFunction.apply(datasetFnArgs.get(startPos));
+        String dataverseNameArg = stringAccessor.apply(datasetFnArgs.get(startPos));
         if (dataverseNameArg == null) {
             throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc, "Invalid argument to dataset()");
         }
@@ -333,11 +267,11 @@ public class FunctionUtil {
         } catch (AsterixException e) {
             throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc, e, "Invalid argument to dataset()");
         }
-        String datasetName = argExtractFunction.apply(datasetFnArgs.get(startPos + 1));
+        String datasetName = stringAccessor.apply(datasetFnArgs.get(startPos + 1));
         if (datasetName == null) {
             throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc, "Invalid argument to dataset()");
         }
-        return new Pair<>(dataverseName, datasetName);
+        return new DatasetFullyQualifiedName(dataverseName, datasetName);
     }
 
     private static String getStringConstant(Mutable<ILogicalExpression> arg) {
@@ -349,17 +283,6 @@ public class FunctionUtil {
         return (value != null) && Boolean.parseBoolean(value.toLowerCase());
     }
 
-    public static Map<FunctionSignature, FunctionDecl> getFunctionMap(List<FunctionDecl> declaredFunctions) {
-        if (declaredFunctions == null || declaredFunctions.isEmpty()) {
-            return Collections.emptyMap();
-        }
-        Map<FunctionSignature, FunctionDecl> result = new HashMap<>();
-        for (FunctionDecl fd : declaredFunctions) {
-            result.put(fd.getSignature(), fd);
-        }
-        return result;
-    }
-
     public static FunctionDecl parseStoredFunction(Function function, IParserFactory parserFactory,
             IWarningCollector warningCollector, SourceLocation sourceLoc) throws CompilationException {
         if (!function.getLanguage().equals(parserFactory.getLanguage())) {
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/ViewUtil.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/ViewUtil.java
new file mode 100644
index 0000000..446b0ad
--- /dev/null
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/ViewUtil.java
@@ -0,0 +1,82 @@
+/*
+ * 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.common.util;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.IParser;
+import org.apache.asterix.lang.common.base.IParserFactory;
+import org.apache.asterix.lang.common.base.IQueryRewriter;
+import org.apache.asterix.lang.common.statement.ViewDecl;
+import org.apache.asterix.metadata.entities.ViewDetails;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+import org.apache.hyracks.api.exceptions.IWarningCollector;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+
+public final class ViewUtil {
+
+    private ViewUtil() {
+    }
+
+    public static ViewDecl parseStoredView(DatasetFullyQualifiedName viewName, ViewDetails view,
+            IParserFactory parserFactory, IWarningCollector warningCollector, SourceLocation sourceLoc)
+            throws CompilationException {
+        IParser parser = parserFactory.createParser(new StringReader(view.getViewBody()));
+        try {
+            ViewDecl viewDecl = parser.parseViewBody(viewName);
+            viewDecl.setSourceLocation(sourceLoc);
+            if (warningCollector != null) {
+                parser.getWarnings(warningCollector);
+            }
+            return viewDecl;
+        } catch (CompilationException e) {
+            throw new CompilationException(ErrorCode.COMPILATION_BAD_VIEW_DEFINITION, e, sourceLoc, viewName,
+                    e.getMessage());
+        }
+    }
+
+    public static List<List<Triple<DataverseName, String, String>>> getViewDependencies(ViewDecl viewDecl,
+            IQueryRewriter rewriter) throws CompilationException {
+        Expression normBody = viewDecl.getNormalizedViewBody();
+        if (normBody == null) {
+            throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, viewDecl.getSourceLocation(),
+                    viewDecl.getViewName().toString());
+        }
+
+        // Get the list of used functions and used datasets
+        List<Triple<DataverseName, String, String>> datasetDependencies = new ArrayList<>();
+        List<Triple<DataverseName, String, String>> synonymDependencies = new ArrayList<>();
+        List<Triple<DataverseName, String, String>> functionDependencies = new ArrayList<>();
+        ExpressionUtils.collectDependencies(normBody, rewriter, datasetDependencies, synonymDependencies,
+                functionDependencies);
+
+        List<Triple<DataverseName, String, String>> typeDependencies = Collections.emptyList();
+        return ViewDetails.createDependencies(datasetDependencies, functionDependencies, typeDependencies,
+                synonymDependencies);
+    }
+}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java
index cba6bb5..7fe7140 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java
@@ -19,6 +19,7 @@
 package org.apache.asterix.lang.common.visitor;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -26,6 +27,7 @@ import java.util.Map;
 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.common.metadata.DatasetFullyQualifiedName;
 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;
@@ -52,6 +54,7 @@ import org.apache.asterix.lang.common.rewrites.VariableSubstitutionEnvironment;
 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.statement.ViewDecl;
 import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.struct.QuantifiedPair;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
@@ -59,6 +62,7 @@ import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.lang.common.visitor.base.AbstractQueryExpressionVisitor;
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import org.apache.hyracks.api.exceptions.SourceLocation;
 
@@ -68,12 +72,15 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
 
     protected final Map<FunctionSignature, FunctionDecl> usedUDFs;
 
+    protected final Map<DatasetFullyQualifiedName, ViewDecl> usedViews;
+
     protected final CloneAndSubstituteVariablesVisitor cloneVisitor;
 
     public AbstractInlineUdfsVisitor(LangRewritingContext context, Map<FunctionSignature, FunctionDecl> usedUDFs,
-            CloneAndSubstituteVariablesVisitor cloneVisitor) {
+            Map<DatasetFullyQualifiedName, ViewDecl> usedViews, CloneAndSubstituteVariablesVisitor cloneVisitor) {
         this.context = context;
         this.usedUDFs = usedUDFs;
+        this.usedViews = usedViews;
         this.cloneVisitor = cloneVisitor;
     }
 
@@ -89,18 +96,12 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
 
     @Override
     public Boolean visit(Query q, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(q.getBody());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(q.getBody());
         q.setBody(p.second);
         return p.first;
     }
 
     @Override
-    public Boolean visit(FunctionDecl fd, Void arg) throws CompilationException {
-        throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, fd.getSourceLocation(),
-                fd.getSignature().toString());
-    }
-
-    @Override
     public Boolean visit(ListConstructor lc, Void arg) throws CompilationException {
         Pair<Boolean, List<Expression>> p = inlineUdfsInExprList(lc.getExprList());
         lc.setExprList(p.second);
@@ -111,10 +112,10 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
     public Boolean visit(RecordConstructor rc, Void arg) throws CompilationException {
         boolean changed = false;
         for (FieldBinding b : rc.getFbList()) {
-            Pair<Boolean, Expression> leftExprInlined = inlineUdfsInExpr(b.getLeftExpr());
+            Pair<Boolean, Expression> leftExprInlined = inlineUdfsAndViewsInExpr(b.getLeftExpr());
             b.setLeftExpr(leftExprInlined.second);
             changed = changed || leftExprInlined.first;
-            Pair<Boolean, Expression> rightExprInlined = inlineUdfsInExpr(b.getRightExpr());
+            Pair<Boolean, Expression> rightExprInlined = inlineUdfsAndViewsInExpr(b.getRightExpr());
             b.setRightExpr(rightExprInlined.second);
             changed = changed || rightExprInlined.first;
         }
@@ -127,7 +128,7 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
         callExpr.setExprList(p.second);
         boolean changed = p.first;
         if (callExpr.hasAggregateFilterExpr()) {
-            Pair<Boolean, Expression> be = inlineUdfsInExpr(callExpr.getAggregateFilterExpr());
+            Pair<Boolean, Expression> be = inlineUdfsAndViewsInExpr(callExpr.getAggregateFilterExpr());
             callExpr.setAggregateFilterExpr(be.second);
             changed |= be.first;
         }
@@ -143,25 +144,25 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
 
     @Override
     public Boolean visit(FieldAccessor fa, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(fa.getExpr());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(fa.getExpr());
         fa.setExpr(p.second);
         return p.first;
     }
 
     @Override
     public Boolean visit(IndexAccessor fa, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(fa.getExpr());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(fa.getExpr());
         fa.setExpr(p.second);
         return p.first;
     }
 
     @Override
     public Boolean visit(IfExpr ifexpr, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p1 = inlineUdfsInExpr(ifexpr.getCondExpr());
+        Pair<Boolean, Expression> p1 = inlineUdfsAndViewsInExpr(ifexpr.getCondExpr());
         ifexpr.setCondExpr(p1.second);
-        Pair<Boolean, Expression> p2 = inlineUdfsInExpr(ifexpr.getThenExpr());
+        Pair<Boolean, Expression> p2 = inlineUdfsAndViewsInExpr(ifexpr.getThenExpr());
         ifexpr.setThenExpr(p2.second);
-        Pair<Boolean, Expression> p3 = inlineUdfsInExpr(ifexpr.getElseExpr());
+        Pair<Boolean, Expression> p3 = inlineUdfsAndViewsInExpr(ifexpr.getElseExpr());
         ifexpr.setElseExpr(p3.second);
         return p1.first || p2.first || p3.first;
     }
@@ -170,27 +171,27 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
     public Boolean visit(QuantifiedExpression qe, Void arg) throws CompilationException {
         boolean changed = false;
         for (QuantifiedPair t : qe.getQuantifiedList()) {
-            Pair<Boolean, Expression> p = inlineUdfsInExpr(t.getExpr());
+            Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(t.getExpr());
             t.setExpr(p.second);
             if (p.first) {
                 changed = true;
             }
         }
-        Pair<Boolean, Expression> p2 = inlineUdfsInExpr(qe.getSatisfiesExpr());
+        Pair<Boolean, Expression> p2 = inlineUdfsAndViewsInExpr(qe.getSatisfiesExpr());
         qe.setSatisfiesExpr(p2.second);
         return changed || p2.first;
     }
 
     @Override
     public Boolean visit(LetClause lc, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(lc.getBindingExpr());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(lc.getBindingExpr());
         lc.setBindingExpr(p.second);
         return p.first;
     }
 
     @Override
     public Boolean visit(WhereClause wc, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(wc.getWhereExpr());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(wc.getWhereExpr());
         wc.setWhereExpr(p.second);
         return p.first;
     }
@@ -235,12 +236,12 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
     public Boolean visit(LimitClause lc, Void arg) throws CompilationException {
         boolean changed = false;
         if (lc.hasLimitExpr()) {
-            Pair<Boolean, Expression> p1 = inlineUdfsInExpr(lc.getLimitExpr());
+            Pair<Boolean, Expression> p1 = inlineUdfsAndViewsInExpr(lc.getLimitExpr());
             lc.setLimitExpr(p1.second);
             changed = p1.first;
         }
         if (lc.hasOffset()) {
-            Pair<Boolean, Expression> p2 = inlineUdfsInExpr(lc.getOffset());
+            Pair<Boolean, Expression> p2 = inlineUdfsAndViewsInExpr(lc.getOffset());
             lc.setOffset(p2.second);
             changed |= p2.first;
         }
@@ -267,53 +268,101 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
         boolean changed = false;
         Expression returnExpression = insert.getReturnExpression();
         if (returnExpression != null) {
-            Pair<Boolean, Expression> rewrittenReturnExpr = inlineUdfsInExpr(returnExpression);
+            Pair<Boolean, Expression> rewrittenReturnExpr = inlineUdfsAndViewsInExpr(returnExpression);
             insert.setReturnExpression(rewrittenReturnExpr.second);
             changed |= rewrittenReturnExpr.first;
         }
-        Pair<Boolean, Expression> rewrittenBodyExpression = inlineUdfsInExpr(insert.getBody());
+        Pair<Boolean, Expression> rewrittenBodyExpression = inlineUdfsAndViewsInExpr(insert.getBody());
         insert.setBody(rewrittenBodyExpression.second);
         return changed || rewrittenBodyExpression.first;
     }
 
-    protected Pair<Boolean, Expression> inlineUdfsInExpr(Expression expr) throws CompilationException {
+    protected Pair<Boolean, Expression> inlineUdfsAndViewsInExpr(Expression expr) throws CompilationException {
         if (expr.getKind() != Kind.CALL_EXPRESSION) {
             boolean r = expr.accept(this, null);
             return new Pair<>(r, expr);
         }
         CallExpr f = (CallExpr) expr;
         boolean r = expr.accept(this, null);
+
+        List<LetClause> letClauses;
+        VariableSubstitutionEnvironment bodyVarSubst;
+        Expression normBodyExpr;
+
         FunctionSignature fs = f.getFunctionSignature();
         if (FunctionUtil.isBuiltinFunctionSignature(fs)) {
-            return new Pair<>(r, expr);
+            if (!FunctionUtil.isBuiltinDatasetFunction(fs)) {
+                return new Pair<>(r, expr);
+            }
+            Triple<DatasetFullyQualifiedName, Boolean, DatasetFullyQualifiedName> dsArgs =
+                    FunctionUtil.parseDatasetFunctionArguments(f);
+            if (!Boolean.TRUE.equals(dsArgs.second)) {
+                // not a view
+                return new Pair<>(r, expr);
+            }
+            DatasetFullyQualifiedName viewName = dsArgs.first;
+            ViewDecl implem = usedViews.get(viewName);
+            if (implem == null) {
+                throw new CompilationException(ErrorCode.UNKNOWN_VIEW, f.getSourceLocation(), viewName);
+            }
+            // it's one of the views we want to inline
+            letClauses = Collections.emptyList();
+            bodyVarSubst = new VariableSubstitutionEnvironment();
+            normBodyExpr = implem.getNormalizedViewBody();
+            if (normBodyExpr == null) {
+                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, f.getSourceLocation(),
+                        viewName.toString());
+            }
+        } else {
+            FunctionDecl implem = usedUDFs.get(fs);
+            if (implem == null) {
+                throw new CompilationException(ErrorCode.UNKNOWN_FUNCTION, f.getSourceLocation(), fs.toString());
+            }
+            // it's one of the functions we want to inline
+            boolean isVarargs = implem.getSignature().getArity() == FunctionIdentifier.VARARGS;
+            Pair<List<LetClause>, VariableSubstitutionEnvironment> clausesAndSubst =
+                    createFunctionParametersSubstitution(implem.getParamList(), isVarargs, f.getExprList(),
+                            f.getSourceLocation());
+            letClauses = clausesAndSubst.first;
+            bodyVarSubst = clausesAndSubst.second;
+            normBodyExpr = implem.getNormalizedFuncBody();
+            if (normBodyExpr == null) {
+                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, f.getSourceLocation(),
+                        fs.toString());
+            }
         }
+
         if (f.hasAggregateFilterExpr()) {
             throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_USE_OF_FILTER_CLAUSE, f.getSourceLocation());
         }
-        FunctionDecl implem = usedUDFs.get(fs);
-        if (implem == null) {
-            throw new CompilationException(ErrorCode.UNKNOWN_FUNCTION, f.getSourceLocation(), fs.toString());
-        }
-        // it's one of the functions we want to inline
-        List<Expression> argList = f.getExprList();
+
+        Pair<ILangExpression, VariableSubstitutionEnvironment> p2 = normBodyExpr.accept(cloneVisitor, bodyVarSubst);
+        Expression resExpr = letClauses.isEmpty() ? (Expression) p2.first
+                : generateQueryExpression(letClauses, (Expression) p2.first);
+        return new Pair<>(true, resExpr);
+    }
+
+    private Pair<List<LetClause>, VariableSubstitutionEnvironment> createFunctionParametersSubstitution(
+            List<VarIdentifier> paramList, boolean isVarargs, List<Expression> argList, SourceLocation sourceLoc)
+            throws CompilationException {
         int argCount = argList.size();
         List<LetClause> clauses = new ArrayList<>(argCount + 1);
         List<Expression> argVars = new ArrayList<>(argCount);
-        for (Expression e : f.getExprList()) {
+        for (Expression e : argList) {
             // Obs: we could do smth about passing also literals, or let
             // variable inlining to take care of this.
             VarIdentifier argVar;
             if (e.getKind() == Kind.VARIABLE_EXPRESSION) {
                 argVar = ((VariableExpr) e).getVar();
             } else {
-                SourceLocation sourceLoc = e.getSourceLocation();
+                SourceLocation argSourceLoc = e.getSourceLocation();
                 argVar = context.newVariable();
                 Pair<ILangExpression, VariableSubstitutionEnvironment> p1 =
                         e.accept(cloneVisitor, new VariableSubstitutionEnvironment());
                 VariableExpr newVRef1 = new VariableExpr(argVar);
-                newVRef1.setSourceLocation(sourceLoc);
+                newVRef1.setSourceLocation(argSourceLoc);
                 LetClause c = new LetClause(newVRef1, (Expression) p1.first);
-                c.setSourceLocation(sourceLoc);
+                c.setSourceLocation(argSourceLoc);
                 clauses.add(c);
             }
 
@@ -323,49 +372,34 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
         }
 
         VariableSubstitutionEnvironment subst = new VariableSubstitutionEnvironment();
-        List<VarIdentifier> paramList = implem.getParamList();
-        if (implem.getSignature().getArity() == FunctionIdentifier.VARARGS) {
+        if (isVarargs) {
             if (paramList.size() != 1) {
-                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, expr.getSourceLocation(),
-                        paramList.size());
+                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc, paramList.size());
             }
             VarIdentifier paramVarargs = paramList.get(0);
             CallExpr argsListExpr =
                     new CallExpr(new FunctionSignature(BuiltinFunctions.ORDERED_LIST_CONSTRUCTOR), argVars);
-            argsListExpr.setSourceLocation(expr.getSourceLocation());
+            argsListExpr.setSourceLocation(sourceLoc);
 
             VarIdentifier argsVar = context.newVariable();
             VariableExpr argsVarRef1 = new VariableExpr(argsVar);
-            argsVarRef1.setSourceLocation(expr.getSourceLocation());
+            argsVarRef1.setSourceLocation(sourceLoc);
             LetClause c = new LetClause(argsVarRef1, argsListExpr);
-            c.setSourceLocation(expr.getSourceLocation());
+            c.setSourceLocation(sourceLoc);
             clauses.add(c);
 
             VariableExpr argsVarRef2 = new VariableExpr(argsVar);
-            argsVarRef2.setSourceLocation(expr.getSourceLocation());
+            argsVarRef2.setSourceLocation(sourceLoc);
             subst.addSubstituion(new VariableExpr(paramVarargs), argsVarRef2);
         } else {
             if (paramList.size() != argCount) {
-                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, expr.getSourceLocation(),
-                        paramList.size());
+                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc, paramList.size());
             }
             for (int i = 0; i < argCount; i++) {
                 subst.addSubstituion(new VariableExpr(paramList.get(i)), argVars.get(i));
             }
         }
-
-        Expression funcBodyNorm = implem.getNormalizedFuncBody();
-        if (funcBodyNorm == null) {
-            throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, f.getSourceLocation(), fs.toString());
-        }
-        Pair<ILangExpression, VariableSubstitutionEnvironment> p2 = funcBodyNorm.accept(cloneVisitor, subst);
-        Expression resExpr;
-        if (clauses.isEmpty()) {
-            resExpr = (Expression) p2.first;
-        } else {
-            resExpr = generateQueryExpression(clauses, (Expression) p2.first);
-        }
-        return new Pair<>(true, resExpr);
+        return new Pair<>(clauses, subst);
     }
 
     protected Pair<Boolean, List<Expression>> inlineUdfsInExprList(List<Expression> exprList)
@@ -373,7 +407,7 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
         List<Expression> newList = new ArrayList<>(exprList.size());
         boolean changed = false;
         for (Expression e : exprList) {
-            Pair<Boolean, Expression> be = inlineUdfsInExpr(e);
+            Pair<Boolean, Expression> be = inlineUdfsAndViewsInExpr(e);
             newList.add(be.second);
             changed |= be.first;
         }
@@ -385,7 +419,7 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
         List<GbyVariableExpressionPair> newList = new ArrayList<>(gbyPairList.size());
         boolean changed = false;
         for (GbyVariableExpressionPair p : gbyPairList) {
-            Pair<Boolean, Expression> be = inlineUdfsInExpr(p.getExpr());
+            Pair<Boolean, Expression> be = inlineUdfsAndViewsInExpr(p.getExpr());
             newList.add(new GbyVariableExpressionPair(p.getVar(), be.second));
             changed |= be.first;
         }
@@ -397,7 +431,7 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
         List<Pair<Expression, Identifier>> newList = new ArrayList<>(fieldList.size());
         boolean changed = false;
         for (Pair<Expression, Identifier> p : fieldList) {
-            Pair<Boolean, Expression> be = inlineUdfsInExpr(p.first);
+            Pair<Boolean, Expression> be = inlineUdfsAndViewsInExpr(p.first);
             newList.add(new Pair<>(be.second, p.second));
             changed |= be.first;
         }
@@ -409,7 +443,7 @@ public abstract class AbstractInlineUdfsVisitor extends AbstractQueryExpressionV
         Map<Expression, VariableExpr> newMap = new HashMap<>();
         boolean changed = false;
         for (Map.Entry<Expression, VariableExpr> me : varMap.entrySet()) {
-            Pair<Boolean, Expression> be = inlineUdfsInExpr(me.getKey());
+            Pair<Boolean, Expression> be = inlineUdfsAndViewsInExpr(me.getKey());
             newMap.put(be.second, me.getValue());
             changed |= be.first;
         }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
index 2650ca3..12a1bd3 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
@@ -76,6 +76,7 @@ import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
 import org.apache.asterix.lang.common.statement.CreateIndexStatement;
 import org.apache.asterix.lang.common.statement.CreateLibraryStatement;
 import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
+import org.apache.asterix.lang.common.statement.CreateViewStatement;
 import org.apache.asterix.lang.common.statement.DatasetDecl;
 import org.apache.asterix.lang.common.statement.DataverseDecl;
 import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -104,6 +105,8 @@ import org.apache.asterix.lang.common.statement.SynonymDropStatement;
 import org.apache.asterix.lang.common.statement.TypeDecl;
 import org.apache.asterix.lang.common.statement.TypeDropStatement;
 import org.apache.asterix.lang.common.statement.UpdateStatement;
+import org.apache.asterix.lang.common.statement.ViewDecl;
+import org.apache.asterix.lang.common.statement.ViewDropStatement;
 import org.apache.asterix.lang.common.statement.WriteStatement;
 import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.struct.OperatorType;
@@ -957,6 +960,32 @@ public abstract class FormatPrintVisitor implements ILangVisitor<Void, Integer>
         return null;
     }
 
+    @Override
+    public Void visit(CreateViewStatement cvs, Integer step) throws CompilationException {
+        out.print(skip(step) + CREATE + generateOrReplace(cvs.getReplaceIfExists()) + " view ");
+        out.print(generateIfNotExists(cvs.getIfNotExists()));
+        out.print(generateFullName(cvs.getDataverseName(), cvs.getViewName()));
+        out.print(" as ");
+        out.print(cvs.getViewBody());
+        out.println(SEMICOLON);
+        return null;
+    }
+
+    @Override
+    public Void visit(ViewDropStatement vds, Integer step) throws CompilationException {
+        out.print(skip(step) + "drop view ");
+        out.print(generateFullName(vds.getDataverseName(), vds.getViewName()));
+        out.print(generateIfExists(vds.getIfExists()));
+        out.println(SEMICOLON);
+        return null;
+    }
+
+    @Override
+    public Void visit(ViewDecl vd, Integer arg) throws CompilationException {
+        // this statement is internal
+        return null;
+    }
+
     protected void printConfiguration(Map<String, String> properties) {
         if (properties.size() > 0) {
             out.print("(");
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
index 25f4103..b7cf7af 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
@@ -47,7 +47,6 @@ import org.apache.asterix.lang.common.expression.RecordConstructor;
 import org.apache.asterix.lang.common.expression.TypeReferenceExpression;
 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.Identifier;
@@ -242,9 +241,4 @@ public abstract class GatherFunctionCallsVisitor extends AbstractQueryExpression
         }
         return null;
     }
-
-    @Override
-    public Void visit(FunctionDecl fd, Void arg) throws CompilationException {
-        return null;
-    }
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/AbstractQueryExpressionVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/AbstractQueryExpressionVisitor.java
index 0b4f56b..91fe664 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/AbstractQueryExpressionVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/AbstractQueryExpressionVisitor.java
@@ -37,6 +37,7 @@ import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
 import org.apache.asterix.lang.common.statement.CreateIndexStatement;
 import org.apache.asterix.lang.common.statement.CreateLibraryStatement;
 import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
+import org.apache.asterix.lang.common.statement.CreateViewStatement;
 import org.apache.asterix.lang.common.statement.DatasetDecl;
 import org.apache.asterix.lang.common.statement.DataverseDecl;
 import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -63,6 +64,8 @@ import org.apache.asterix.lang.common.statement.SynonymDropStatement;
 import org.apache.asterix.lang.common.statement.TypeDecl;
 import org.apache.asterix.lang.common.statement.TypeDropStatement;
 import org.apache.asterix.lang.common.statement.UpdateStatement;
+import org.apache.asterix.lang.common.statement.ViewDecl;
+import org.apache.asterix.lang.common.statement.ViewDropStatement;
 import org.apache.asterix.lang.common.statement.WriteStatement;
 
 public abstract class AbstractQueryExpressionVisitor<R, T> implements ILangVisitor<R, T> {
@@ -291,4 +294,19 @@ public abstract class AbstractQueryExpressionVisitor<R, T> implements ILangVisit
     public R visit(LibraryDropStatement del, T arg) throws CompilationException {
         return null;
     }
+
+    @Override
+    public R visit(CreateViewStatement cvs, T arg) throws CompilationException {
+        return null;
+    }
+
+    @Override
+    public R visit(ViewDropStatement vds, T arg) throws CompilationException {
+        return null;
+    }
+
+    @Override
+    public R visit(ViewDecl vd, T arg) throws CompilationException {
+        return null;
+    }
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
index e36ec73..c2b1311 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
@@ -54,6 +54,7 @@ import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
 import org.apache.asterix.lang.common.statement.CreateIndexStatement;
 import org.apache.asterix.lang.common.statement.CreateLibraryStatement;
 import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
+import org.apache.asterix.lang.common.statement.CreateViewStatement;
 import org.apache.asterix.lang.common.statement.DatasetDecl;
 import org.apache.asterix.lang.common.statement.DataverseDecl;
 import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -80,6 +81,8 @@ import org.apache.asterix.lang.common.statement.SynonymDropStatement;
 import org.apache.asterix.lang.common.statement.TypeDecl;
 import org.apache.asterix.lang.common.statement.TypeDropStatement;
 import org.apache.asterix.lang.common.statement.UpdateStatement;
+import org.apache.asterix.lang.common.statement.ViewDecl;
+import org.apache.asterix.lang.common.statement.ViewDropStatement;
 import org.apache.asterix.lang.common.statement.WriteStatement;
 
 public interface ILangVisitor<R, T> {
@@ -207,4 +210,10 @@ public interface ILangVisitor<R, T> {
     R visit(CompactStatement del, T arg) throws CompilationException;
 
     R visit(ListSliceExpression expression, T arg) throws CompilationException;
+
+    R visit(CreateViewStatement cvs, T arg) throws CompilationException;
+
+    R visit(ViewDropStatement vds, T arg) throws CompilationException;
+
+    R visit(ViewDecl vd, T arg) throws CompilationException;
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
index 8dd206f..6287d2e 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
@@ -27,6 +27,9 @@ import org.apache.asterix.lang.common.base.IReturningStatement;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 
+/**
+ * This rewriter is used to rewrite body expression of user defined functions and views
+ */
 class SqlppFunctionBodyRewriter extends SqlppQueryRewriter {
 
     public SqlppFunctionBodyRewriter(IParserFactory parserFactory) {
@@ -35,15 +38,15 @@ class SqlppFunctionBodyRewriter extends SqlppQueryRewriter {
 
     @Override
     public void rewrite(LangRewritingContext context, IReturningStatement topStatement, boolean allowNonStoredUdfCalls,
-            boolean inlineUdfs, Collection<VarIdentifier> externalVars) throws CompilationException {
-        if (inlineUdfs) {
-            // When rewriting function body we do not inline UDFs into it.
+            boolean inlineUdfsAndViews, Collection<VarIdentifier> externalVars) throws CompilationException {
+        if (inlineUdfsAndViews) {
+            // When rewriting function or view body we do not inline UDFs or views into it.
             // The main query rewriter will inline everything later, when it processes the query
-            throw new CompilationException(ErrorCode.ILLEGAL_STATE, topStatement.getSourceLocation(), "inlineUdfs");
+            throw new CompilationException(ErrorCode.ILLEGAL_STATE, topStatement.getSourceLocation(), "");
         }
 
         // Sets up parameters.
-        setup(context, topStatement, externalVars, allowNonStoredUdfCalls, inlineUdfs);
+        setup(context, topStatement, externalVars, allowNonStoredUdfCalls, inlineUdfsAndViews);
 
         // Resolves function calls
         resolveFunctionCalls();
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriterFactory.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriterFactory.java
deleted file mode 100644
index bf27464..0000000
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriterFactory.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.sqlpp.rewrites;
-
-import org.apache.asterix.lang.common.base.IParserFactory;
-import org.apache.asterix.lang.common.base.IQueryRewriter;
-import org.apache.asterix.lang.common.base.IRewriterFactory;
-import org.apache.asterix.lang.common.base.IStatementRewriter;
-
-class SqlppFunctionBodyRewriterFactory implements IRewriterFactory {
-
-    private final IParserFactory parserFactory;
-
-    public SqlppFunctionBodyRewriterFactory(IParserFactory parserFactory) {
-        this.parserFactory = parserFactory;
-    }
-
-    @Override
-    public IQueryRewriter createQueryRewriter() {
-        return new SqlppFunctionBodyRewriter(parserFactory);
-    }
-
-    @Override
-    public IStatementRewriter createStatementRewriter() {
-        throw new IllegalStateException("There could not be non-query statements inside a function definition.");
-    }
-
-}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
index a3ff1c6..f07e614 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
@@ -24,24 +24,35 @@ import java.util.Collections;
 import java.util.Deque;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 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.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.lang.common.base.AbstractExpression;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.base.IReturningStatement;
 import org.apache.asterix.lang.common.expression.AbstractCallExpression;
+import org.apache.asterix.lang.common.expression.CallExpr;
+import org.apache.asterix.lang.common.expression.FieldAccessor;
+import org.apache.asterix.lang.common.expression.LiteralExpr;
 import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.literal.MissingLiteral;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.statement.ViewDecl;
+import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
+import org.apache.asterix.lang.common.util.ExpressionUtils;
 import org.apache.asterix.lang.common.util.FunctionUtil;
+import org.apache.asterix.lang.common.util.ViewUtil;
 import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
 import org.apache.asterix.lang.sqlpp.rewrites.visitor.GenerateColumnNameVisitor;
 import org.apache.asterix.lang.sqlpp.rewrites.visitor.InlineColumnAliasVisitor;
@@ -66,9 +77,16 @@ import org.apache.asterix.lang.sqlpp.rewrites.visitor.VariableCheckAndRewriteVis
 import org.apache.asterix.lang.sqlpp.util.SqlppAstPrintUtil;
 import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
 import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Dataverse;
 import org.apache.asterix.metadata.entities.Function;
+import org.apache.asterix.metadata.entities.ViewDetails;
+import org.apache.asterix.metadata.utils.DatasetUtil;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.api.exceptions.SourceLocation;
 import org.apache.hyracks.util.LogRedactionUtil;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -80,13 +98,13 @@ public class SqlppQueryRewriter implements IQueryRewriter {
     public static final String INLINE_WITH_OPTION = "inline_with";
     private static final boolean INLINE_WITH_OPTION_DEFAULT = true;
     private final IParserFactory parserFactory;
-    private SqlppFunctionBodyRewriter functionBodyRewriter;
+    private SqlppFunctionBodyRewriter functionAndViewBodyRewriter;
     private IReturningStatement topStatement;
     private LangRewritingContext context;
     private MetadataProvider metadataProvider;
     private Collection<VarIdentifier> externalVars;
     private boolean allowNonStoredUdfCalls;
-    private boolean inlineUdfs;
+    private boolean inlineUdfsAndViews;
     private boolean isLogEnabled;
 
     public SqlppQueryRewriter(IParserFactory parserFactory) {
@@ -94,24 +112,24 @@ public class SqlppQueryRewriter implements IQueryRewriter {
     }
 
     protected void setup(LangRewritingContext context, IReturningStatement topStatement,
-            Collection<VarIdentifier> externalVars, boolean allowNonStoredUdfCalls, boolean inlineUdfs)
+            Collection<VarIdentifier> externalVars, boolean allowNonStoredUdfCalls, boolean inlineUdfsAndViews)
             throws CompilationException {
         this.context = context;
         this.metadataProvider = context.getMetadataProvider();
         this.topStatement = topStatement;
         this.externalVars = externalVars != null ? externalVars : Collections.emptyList();
         this.allowNonStoredUdfCalls = allowNonStoredUdfCalls;
-        this.inlineUdfs = inlineUdfs;
+        this.inlineUdfsAndViews = inlineUdfsAndViews;
         this.isLogEnabled = LOGGER.isTraceEnabled();
         logExpression("Starting AST rewrites on", "");
     }
 
     @Override
     public void rewrite(LangRewritingContext context, IReturningStatement topStatement, boolean allowNonStoredUdfCalls,
-            boolean inlineUdfs, Collection<VarIdentifier> externalVars) throws CompilationException {
+            boolean inlineUdfsAndViews, Collection<VarIdentifier> externalVars) throws CompilationException {
 
         // Sets up parameters.
-        setup(context, topStatement, externalVars, allowNonStoredUdfCalls, inlineUdfs);
+        setup(context, topStatement, externalVars, allowNonStoredUdfCalls, inlineUdfsAndViews);
 
         // Resolves function calls
         resolveFunctionCalls();
@@ -162,8 +180,8 @@ public class SqlppQueryRewriter implements IQueryRewriter {
         // Rewrites RIGHT OUTER JOINs into LEFT OUTER JOINs if possible
         rewriteRightJoins();
 
-        // Inlines functions.
-        loadAndInlineDeclaredUdfs();
+        // Inlines functions and views
+        loadAndInlineUdfsAndViews();
 
         // Rewrites SQL++ core aggregate function names into internal names
         rewriteSpecialFunctionNames();
@@ -289,12 +307,21 @@ public class SqlppQueryRewriter implements IQueryRewriter {
         rewriteTopExpr(visitor, null);
     }
 
-    protected void loadAndInlineDeclaredUdfs() throws CompilationException {
-        Map<FunctionSignature, FunctionDecl> udfs = fetchUserDefinedSqlppFunctions(topStatement);
-        FunctionUtil.checkFunctionRecursion(udfs, SqlppGatherFunctionCallsVisitor::new,
-                topStatement.getSourceLocation());
-        if (!udfs.isEmpty() && inlineUdfs) {
-            SqlppInlineUdfsVisitor visitor = new SqlppInlineUdfsVisitor(context, udfs);
+    protected void loadAndInlineUdfsAndViews() throws CompilationException {
+        Pair<Map<FunctionSignature, FunctionDecl>, Map<DatasetFullyQualifiedName, ViewDecl>> udfAndViewDecls =
+                loadUdfsAndViews(topStatement);
+        Map<FunctionSignature, FunctionDecl> udfs = udfAndViewDecls.first;
+        Map<DatasetFullyQualifiedName, ViewDecl> views = udfAndViewDecls.second;
+        if (udfs.isEmpty() && views.isEmpty()) {
+            // nothing to do
+            return;
+        }
+        if (ExpressionUtils.hasFunctionOrViewRecursion(udfs, views, SqlppGatherFunctionCallsVisitor::new)) {
+            throw new CompilationException(ErrorCode.ILLEGAL_FUNCTION_OR_VIEW_RECURSION,
+                    topStatement.getSourceLocation());
+        }
+        if (inlineUdfsAndViews) {
+            SqlppInlineUdfsVisitor visitor = new SqlppInlineUdfsVisitor(context, udfs, views);
             while (rewriteTopExpr(visitor, null)) {
                 // loop until no more changes
             }
@@ -332,14 +359,24 @@ public class SqlppQueryRewriter implements IQueryRewriter {
         return extVars;
     }
 
-    private Map<FunctionSignature, FunctionDecl> fetchUserDefinedSqlppFunctions(IReturningStatement topExpr)
-            throws CompilationException {
-        Map<FunctionSignature, FunctionDecl> udfs = new LinkedHashMap<>();
+    @Override
+    public VarIdentifier toExternalVariableName(String statementParameterName) {
+        return SqlppVariableUtil.toExternalVariableIdentifier(statementParameterName);
+    }
 
+    @Override
+    public String toFunctionParameterName(VarIdentifier paramVar) {
+        return SqlppVariableUtil.toUserDefinedName(paramVar.getValue());
+    }
+
+    private Pair<Map<FunctionSignature, FunctionDecl>, Map<DatasetFullyQualifiedName, ViewDecl>> loadUdfsAndViews(
+            IReturningStatement topExpr) throws CompilationException {
+        Map<FunctionSignature, FunctionDecl> udfs = new LinkedHashMap<>();
+        Map<DatasetFullyQualifiedName, ViewDecl> views = new LinkedHashMap<>();
         Deque<AbstractCallExpression> workQueue = new ArrayDeque<>();
-        SqlppGatherFunctionCallsVisitor gfc = new SqlppGatherFunctionCallsVisitor(workQueue);
+        SqlppGatherFunctionCallsVisitor callVisitor = new SqlppGatherFunctionCallsVisitor(workQueue);
         for (Expression expr : topExpr.getDirectlyEnclosedExpressions()) {
-            expr.accept(gfc, null);
+            expr.accept(callVisitor, null);
         }
         AbstractCallExpression fnCall;
         while ((fnCall = workQueue.poll()) != null) {
@@ -351,31 +388,30 @@ public class SqlppQueryRewriter implements IQueryRewriter {
                         throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, fnCall.getSourceLocation(),
                                 fs);
                     }
-                    if (FunctionUtil.isBuiltinFunctionSignature(fs) || udfs.containsKey(fs)) {
-                        continue;
-                    }
-                    FunctionDecl fd = context.getDeclaredFunctions().get(fs);
-                    if (fd == null) {
-                        Function function;
-                        try {
-                            function = metadataProvider.lookupUserDefinedFunction(fs);
-                        } catch (AlgebricksException e) {
-                            throw new CompilationException(ErrorCode.UNKNOWN_FUNCTION, fnCall.getSourceLocation(),
-                                    fs.toString());
-                        }
-                        if (function == null) {
-                            throw new CompilationException(ErrorCode.UNKNOWN_FUNCTION, fnCall.getSourceLocation(),
-                                    fs.toString());
+                    if (FunctionUtil.isBuiltinFunctionSignature(fs)) {
+                        if (FunctionUtil.isBuiltinDatasetFunction(fs)) {
+                            Triple<DatasetFullyQualifiedName, Boolean, DatasetFullyQualifiedName> dsArgs =
+                                    FunctionUtil.parseDatasetFunctionArguments(fnCall);
+                            if (Boolean.TRUE.equals(dsArgs.second)) {
+                                DatasetFullyQualifiedName viewName = dsArgs.first;
+                                if (!views.containsKey(viewName)) {
+                                    ViewDecl viewDecl = fetchViewDecl(viewName, fnCall.getSourceLocation());
+                                    if (viewDecl != null) {
+                                        views.put(viewName, viewDecl);
+                                        viewDecl.getNormalizedViewBody().accept(callVisitor, null);
+                                    }
+                                }
+                            }
                         }
-                        if (function.isExternal()) {
-                            continue;
+                    } else {
+                        if (!udfs.containsKey(fs)) {
+                            FunctionDecl fd = fetchFunctionDecl(fs, fnCall.getSourceLocation());
+                            if (fd != null) {
+                                udfs.put(fs, fd);
+                                fd.getNormalizedFuncBody().accept(callVisitor, null);
+                            }
                         }
-                        fd = FunctionUtil.parseStoredFunction(function, parserFactory, context.getWarningCollector(),
-                                fnCall.getSourceLocation());
                     }
-                    prepareFunction(fd);
-                    udfs.put(fs, fd);
-                    fd.getNormalizedFuncBody().accept(gfc, null);
                     break;
                 case WINDOW_EXPRESSION:
                     // there cannot be used-defined window functions
@@ -385,54 +421,145 @@ public class SqlppQueryRewriter implements IQueryRewriter {
                             fnCall.getFunctionSignature().toString(false));
             }
         }
-        return udfs;
+        return new Pair<>(udfs, views);
+    }
+
+    private FunctionDecl fetchFunctionDecl(FunctionSignature fs, SourceLocation sourceLoc) throws CompilationException {
+        FunctionDecl fd = context.getDeclaredFunctions().get(fs);
+        if (fd == null) {
+            Function function;
+            try {
+                function = metadataProvider.lookupUserDefinedFunction(fs);
+            } catch (AlgebricksException e) {
+                throw new CompilationException(ErrorCode.UNKNOWN_FUNCTION, sourceLoc, fs.toString());
+            }
+            if (function == null) {
+                throw new CompilationException(ErrorCode.UNKNOWN_FUNCTION, sourceLoc, fs.toString());
+            }
+            if (function.isExternal()) {
+                return null;
+            }
+            fd = FunctionUtil.parseStoredFunction(function, parserFactory, context.getWarningCollector(), sourceLoc);
+        }
+        Expression normBody = fd.getNormalizedFuncBody();
+        if (normBody == null) {
+            normBody = rewriteFunctionBody(fd);
+            fd.setNormalizedFuncBody(normBody);
+        }
+        return fd;
     }
 
-    private void prepareFunction(FunctionDecl fd) throws CompilationException {
-        Expression fnNormBody = fd.getNormalizedFuncBody();
-        if (fnNormBody == null) {
-            fnNormBody = rewriteFunctionBody(fd);
-            fd.setNormalizedFuncBody(fnNormBody);
+    private ViewDecl fetchViewDecl(DatasetFullyQualifiedName viewName, SourceLocation sourceLoc)
+            throws CompilationException {
+        ViewDecl viewDecl = context.getDeclaredViews().get(viewName);
+        if (viewDecl == null) {
+            Dataset dataset;
+            try {
+                dataset = metadataProvider.findDataset(viewName.getDataverseName(), viewName.getDatasetName(), true);
+            } catch (AlgebricksException e) {
+                throw new CompilationException(ErrorCode.UNKNOWN_VIEW, e, sourceLoc, viewName);
+            }
+            if (dataset == null || DatasetUtil.isNotView(dataset)) {
+                throw new CompilationException(ErrorCode.UNKNOWN_VIEW, sourceLoc, viewName);
+            }
+            ViewDetails viewDetails = (ViewDetails) dataset.getDatasetDetails();
+            viewDecl = ViewUtil.parseStoredView(viewName, viewDetails, parserFactory, context.getWarningCollector(),
+                    sourceLoc);
         }
+        Expression normBody = viewDecl.getNormalizedViewBody();
+        if (normBody == null) {
+            normBody = rewriteViewBody(viewDecl);
+            viewDecl.setNormalizedViewBody(normBody);
+        }
+        return viewDecl;
     }
 
     private Expression rewriteFunctionBody(FunctionDecl fnDecl) throws CompilationException {
-        DataverseName fnDataverseName = fnDecl.getSignature().getDataverseName();
+        FunctionSignature fs = fnDecl.getSignature();
+        return rewriteFunctionOrViewBody(fs.getDataverseName(), fs, fnDecl.getFuncBody(), fnDecl.getParamList(),
+                !fnDecl.isStored(), fnDecl.getSourceLocation());
+    }
+
+    private Expression rewriteViewBody(ViewDecl viewDecl) throws CompilationException {
+        DatasetFullyQualifiedName viewName = viewDecl.getViewName();
+        return rewriteFunctionOrViewBody(viewName.getDataverseName(), viewName, viewDecl.getViewBody(),
+                Collections.emptyList(), false, viewDecl.getSourceLocation());
+    }
+
+    private Expression rewriteFunctionOrViewBody(DataverseName entityDataverseName, Object entityDisplayName,
+            Expression bodyExpr, List<VarIdentifier> externalVars, boolean allowNonStoredUdfCalls,
+            SourceLocation sourceLoc) throws CompilationException {
         Dataverse defaultDataverse = metadataProvider.getDefaultDataverse();
-        Dataverse fnDataverse;
-        if (fnDataverseName == null || fnDataverseName.equals(defaultDataverse.getDataverseName())) {
-            fnDataverse = defaultDataverse;
+        Dataverse targetDataverse;
+        if (entityDataverseName == null || entityDataverseName.equals(defaultDataverse.getDataverseName())) {
+            targetDataverse = defaultDataverse;
         } else {
             try {
-                fnDataverse = metadataProvider.findDataverse(fnDataverseName);
+                targetDataverse = metadataProvider.findDataverse(entityDataverseName);
             } catch (AlgebricksException e) {
-                throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, e, fnDecl.getSourceLocation(),
-                        fnDataverseName);
+                throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, e, sourceLoc, entityDataverseName);
             }
         }
 
-        metadataProvider.setDefaultDataverse(fnDataverse);
+        metadataProvider.setDefaultDataverse(targetDataverse);
         try {
-            Query wrappedQuery = new Query(false);
-            wrappedQuery.setSourceLocation(fnDecl.getSourceLocation());
-            wrappedQuery.setBody(fnDecl.getFuncBody());
-            wrappedQuery.setTopLevel(false);
-            boolean allowNonStoredUdfCalls = !fnDecl.isStored();
-            getFunctionBodyRewriter().rewrite(context, wrappedQuery, allowNonStoredUdfCalls, false,
-                    fnDecl.getParamList());
+            Query wrappedQuery = createWrappedQuery(bodyExpr, sourceLoc);
+            getFunctionAndViewBodyRewriter().rewrite(context, wrappedQuery, allowNonStoredUdfCalls, false,
+                    externalVars);
             return wrappedQuery.getBody();
         } catch (CompilationException e) {
-            throw new CompilationException(ErrorCode.COMPILATION_BAD_FUNCTION_DEFINITION, e, fnDecl.getSignature(),
-                    e.getMessage());
+            throw new CompilationException(ErrorCode.COMPILATION_BAD_FUNCTION_DEFINITION, e,
+                    entityDisplayName.toString(), e.getMessage());
         } finally {
             metadataProvider.setDefaultDataverse(defaultDataverse);
         }
     }
 
-    protected SqlppFunctionBodyRewriter getFunctionBodyRewriter() {
-        if (functionBodyRewriter == null) {
-            functionBodyRewriter = new SqlppFunctionBodyRewriter(parserFactory);
+    protected SqlppFunctionBodyRewriter getFunctionAndViewBodyRewriter() {
+        if (functionAndViewBodyRewriter == null) {
+            functionAndViewBodyRewriter = new SqlppFunctionBodyRewriter(parserFactory);
         }
-        return functionBodyRewriter;
+        return functionAndViewBodyRewriter;
+    }
+
+    @Override
+    public Query createFunctionAccessorQuery(FunctionDecl functionDecl) {
+        // dataverse_name.function_name(MISSING, ... MISSING)
+        FunctionSignature functionSignature = functionDecl.getSignature();
+        int arity = functionSignature.getArity();
+        List<Expression> args = arity == FunctionIdentifier.VARARGS ? Collections.emptyList()
+                : Collections.nCopies(arity, new LiteralExpr(MissingLiteral.INSTANCE));
+        CallExpr fcall = new CallExpr(functionSignature, args);
+        fcall.setSourceLocation(functionDecl.getSourceLocation());
+
+        return createWrappedQuery(fcall, functionDecl.getSourceLocation());
+    }
+
+    @Override
+    public Query createViewAccessorQuery(ViewDecl viewDecl) {
+        // dataverse_name.view_name
+        DataverseName dataverseName = viewDecl.getViewName().getDataverseName();
+        String viewName = viewDecl.getViewName().getDatasetName();
+        SourceLocation sourceLoc = viewDecl.getSourceLocation();
+        List<String> dataverseNameParts = dataverseName.getParts();
+        AbstractExpression vAccessExpr = null;
+        for (int i = 0, n = dataverseNameParts.size(); i < n; i++) {
+            String part = dataverseNameParts.get(i);
+            vAccessExpr = i == 0 ? new VariableExpr(new VarIdentifier(SqlppVariableUtil.toInternalVariableName(part)))
+                    : new FieldAccessor(vAccessExpr, new Identifier(part));
+            vAccessExpr.setSourceLocation(sourceLoc);
+        }
+        vAccessExpr = new FieldAccessor(vAccessExpr, new Identifier(viewName));
+        vAccessExpr.setSourceLocation(sourceLoc);
+
+        return createWrappedQuery(vAccessExpr, viewDecl.getSourceLocation());
+    }
+
+    private static Query createWrappedQuery(Expression expr, SourceLocation sourceLoc) {
+        Query wrappedQuery = new Query(false);
+        wrappedQuery.setSourceLocation(sourceLoc);
+        wrappedQuery.setBody(expr);
+        wrappedQuery.setTopLevel(false);
+        return wrappedQuery;
     }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
index a9caacb..f9b0e7a 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
@@ -21,8 +21,6 @@ package org.apache.asterix.lang.sqlpp.rewrites;
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.lang.common.base.IStatementRewriter;
 import org.apache.asterix.lang.common.base.Statement;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
 import org.apache.asterix.lang.sqlpp.visitor.SqlppDeleteRewriteVisitor;
 import org.apache.asterix.lang.sqlpp.visitor.SqlppSynonymRewriteVisitor;
 import org.apache.asterix.metadata.declared.MetadataProvider;
@@ -49,14 +47,4 @@ class SqlppStatementRewriter implements IStatementRewriter {
             stmt.accept(SqlppDeleteRewriteVisitor.INSTANCE, metadataProvider);
         }
     }
-
-    @Override
-    public String toExternalVariableName(String statementParameterName) {
-        return SqlppVariableUtil.toExternalVariableName(statementParameterName);
-    }
-
-    @Override
-    public String toFunctionParameterName(VarIdentifier paramVar) {
-        return SqlppVariableUtil.toUserDefinedName(paramVar.getValue());
-    }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java
index 5200b94..56fdd19 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java
@@ -24,12 +24,14 @@ import java.util.Map;
 
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.lang.common.base.AbstractClause;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.clause.LetClause;
 import org.apache.asterix.lang.common.expression.ListSliceExpression;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.ViewDecl;
 import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.visitor.AbstractInlineUdfsVisitor;
 import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
@@ -61,9 +63,12 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
      *            manages ids of variables and guarantees uniqueness of variables.
      * @param usedUDFs,
      *            user defined functions used by this query.
+     * @param usedViews,
+     *            views used by this query.
      */
-    public SqlppInlineUdfsVisitor(LangRewritingContext context, Map<FunctionSignature, FunctionDecl> usedUDFs) {
-        super(context, usedUDFs, new SqlppCloneAndSubstituteVariablesVisitor(context));
+    public SqlppInlineUdfsVisitor(LangRewritingContext context, Map<FunctionSignature, FunctionDecl> usedUDFs,
+            Map<DatasetFullyQualifiedName, ViewDecl> usedViews) {
+        super(context, usedUDFs, usedViews, new SqlppCloneAndSubstituteVariablesVisitor(context));
     }
 
     @Override
@@ -85,7 +90,7 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
     @Override
     public Boolean visit(FromTerm fromTerm, Void arg) throws CompilationException {
         boolean changed = false;
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(fromTerm.getLeftExpression());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(fromTerm.getLeftExpression());
         fromTerm.setLeftExpression(p.second);
         changed |= p.first;
         for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
@@ -96,18 +101,18 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
 
     @Override
     public Boolean visit(JoinClause joinClause, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p1 = inlineUdfsInExpr(joinClause.getRightExpression());
+        Pair<Boolean, Expression> p1 = inlineUdfsAndViewsInExpr(joinClause.getRightExpression());
         joinClause.setRightExpression(p1.second);
-        Pair<Boolean, Expression> p2 = inlineUdfsInExpr(joinClause.getConditionExpression());
+        Pair<Boolean, Expression> p2 = inlineUdfsAndViewsInExpr(joinClause.getConditionExpression());
         joinClause.setConditionExpression(p2.second);
         return p1.first || p2.first;
     }
 
     @Override
     public Boolean visit(NestClause nestClause, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p1 = inlineUdfsInExpr(nestClause.getRightExpression());
+        Pair<Boolean, Expression> p1 = inlineUdfsAndViewsInExpr(nestClause.getRightExpression());
         nestClause.setRightExpression(p1.second);
-        Pair<Boolean, Expression> p2 = inlineUdfsInExpr(nestClause.getConditionExpression());
+        Pair<Boolean, Expression> p2 = inlineUdfsAndViewsInExpr(nestClause.getConditionExpression());
         nestClause.setConditionExpression(p2.second);
         return p1.first || p2.first;
     }
@@ -117,7 +122,7 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
         if (projection.star()) {
             return false;
         }
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(projection.getExpression());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(projection.getExpression());
         projection.setExpression(p.second);
         return p.first;
     }
@@ -158,7 +163,7 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
 
     @Override
     public Boolean visit(SelectElement selectElement, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(selectElement.getExpression());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(selectElement.getExpression());
         selectElement.setExpression(p.second);
         return p.first;
     }
@@ -202,21 +207,21 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
 
     @Override
     public Boolean visit(UnnestClause unnestClause, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(unnestClause.getRightExpression());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(unnestClause.getRightExpression());
         unnestClause.setRightExpression(p.second);
         return p.first;
     }
 
     @Override
     public Boolean visit(HavingClause havingClause, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> p = inlineUdfsInExpr(havingClause.getFilterExpression());
+        Pair<Boolean, Expression> p = inlineUdfsAndViewsInExpr(havingClause.getFilterExpression());
         havingClause.setFilterExpression(p.second);
         return p.first;
     }
 
     @Override
     public Boolean visit(CaseExpression caseExpr, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> result = inlineUdfsInExpr(caseExpr.getConditionExpr());
+        Pair<Boolean, Expression> result = inlineUdfsAndViewsInExpr(caseExpr.getConditionExpr());
         caseExpr.setConditionExpr(result.second);
         boolean inlined = result.first;
 
@@ -228,7 +233,7 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
         inlined = inlined || inlinedList.first;
         caseExpr.setThenExprs(inlinedList.second);
 
-        result = inlineUdfsInExpr(caseExpr.getElseExpr());
+        result = inlineUdfsAndViewsInExpr(caseExpr.getElseExpr());
         caseExpr.setElseExpr(result.second);
         return inlined || result.first;
     }
@@ -247,12 +252,12 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
             inlined |= inlinedList.first;
         }
         if (winExpr.hasFrameStartExpr()) {
-            Pair<Boolean, Expression> inlinedExpr = inlineUdfsInExpr(winExpr.getFrameStartExpr());
+            Pair<Boolean, Expression> inlinedExpr = inlineUdfsAndViewsInExpr(winExpr.getFrameStartExpr());
             winExpr.setFrameStartExpr(inlinedExpr.second);
             inlined |= inlinedExpr.first;
         }
         if (winExpr.hasFrameEndExpr()) {
-            Pair<Boolean, Expression> inlinedExpr = inlineUdfsInExpr(winExpr.getFrameEndExpr());
+            Pair<Boolean, Expression> inlinedExpr = inlineUdfsAndViewsInExpr(winExpr.getFrameEndExpr());
             winExpr.setFrameEndExpr(inlinedExpr.second);
             inlined |= inlinedExpr.first;
         }
@@ -263,7 +268,7 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
             inlined |= inlinedList.first;
         }
         if (winExpr.hasAggregateFilterExpr()) {
-            Pair<Boolean, Expression> inlinedExpr = inlineUdfsInExpr(winExpr.getAggregateFilterExpr());
+            Pair<Boolean, Expression> inlinedExpr = inlineUdfsAndViewsInExpr(winExpr.getAggregateFilterExpr());
             winExpr.setAggregateFilterExpr(inlinedExpr.second);
             inlined |= inlinedExpr.first;
         }
@@ -275,17 +280,19 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor implements
 
     @Override
     public Boolean visit(ListSliceExpression expression, Void arg) throws CompilationException {
-        Pair<Boolean, Expression> expressionResult = inlineUdfsInExpr(expression.getExpr());
+        Pair<Boolean, Expression> expressionResult = inlineUdfsAndViewsInExpr(expression.getExpr());
         expression.setExpr(expressionResult.second);
         boolean inlined = expressionResult.first;
 
-        Pair<Boolean, Expression> startIndexExpressResult = inlineUdfsInExpr(expression.getStartIndexExpression());
+        Pair<Boolean, Expression> startIndexExpressResult =
+                inlineUdfsAndViewsInExpr(expression.getStartIndexExpression());
         expression.setStartIndexExpression(startIndexExpressResult.second);
         inlined |= startIndexExpressResult.first;
 
         // End index expression can be null (optional)
         if (expression.hasEndExpression()) {
-            Pair<Boolean, Expression> endIndexExpressionResult = inlineUdfsInExpr(expression.getEndIndexExpression());
+            Pair<Boolean, Expression> endIndexExpressionResult =
+                    inlineUdfsAndViewsInExpr(expression.getEndIndexExpression());
             expression.setEndIndexExpression(endIndexExpressionResult.second);
             inlined |= endIndexExpressionResult.first;
         }
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 bbf1a46..4b0caca 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
@@ -25,10 +25,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.asterix.common.config.DatasetConfig;
 import org.apache.asterix.common.exceptions.AsterixException;
 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.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.Expression.Kind;
@@ -38,8 +40,11 @@ import org.apache.asterix.lang.common.expression.CallExpr;
 import org.apache.asterix.lang.common.expression.FieldAccessor;
 import org.apache.asterix.lang.common.expression.LiteralExpr;
 import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.literal.FalseLiteral;
 import org.apache.asterix.lang.common.literal.StringLiteral;
+import org.apache.asterix.lang.common.literal.TrueLiteral;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
+import org.apache.asterix.lang.common.statement.ViewDecl;
 import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.asterix.lang.sqlpp.expression.WindowExpression;
@@ -169,15 +174,30 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
             return null;
         }
         SourceLocation sourceLoc = varExpr.getSourceLocation();
-        Pair<Dataset, Boolean> datasetSynonymPair = findDataset(dataverseName, datasetName, sourceLoc);
-        if (datasetSynonymPair == null) {
-            throw createUnresolvableError(dataverseName, datasetName, sourceLoc);
+        DataverseName resolvedDataverseName;
+        String resolvedDatasetName;
+        boolean viaSynonym, isView;
+        ViewDecl viewDecl = findDeclaredView(dataverseName, datasetName);
+        if (viewDecl != null) {
+            resolvedDataverseName = viewDecl.getViewName().getDataverseName();
+            resolvedDatasetName = viewDecl.getViewName().getDatasetName();
+            viaSynonym = false;
+            isView = true;
+        } else {
+            Pair<Dataset, Boolean> p = findDataset(dataverseName, datasetName, true, sourceLoc);
+            if (p == null) {
+                throw createUnresolvableError(dataverseName, datasetName, sourceLoc);
+            }
+            Dataset resolvedDataset = p.first;
+            resolvedDataverseName = resolvedDataset.getDataverseName();
+            resolvedDatasetName = resolvedDataset.getDatasetName();
+            viaSynonym = p.second;
+            isView = resolvedDataset.getDatasetType() == DatasetConfig.DatasetType.VIEW;
         }
-        Dataset dataset = datasetSynonymPair.first;
-        boolean viaSynonym = datasetSynonymPair.second;
-        List<Expression> argList = new ArrayList<>(4);
-        argList.add(new LiteralExpr(new StringLiteral(dataset.getDataverseName().getCanonicalForm())));
-        argList.add(new LiteralExpr(new StringLiteral(dataset.getDatasetName())));
+        List<Expression> argList = new ArrayList<>(3 + (viaSynonym ? 2 : 0));
+        argList.add(new LiteralExpr(new StringLiteral(resolvedDataverseName.getCanonicalForm())));
+        argList.add(new LiteralExpr(new StringLiteral(resolvedDatasetName)));
+        argList.add(new LiteralExpr(isView ? TrueLiteral.INSTANCE : FalseLiteral.INSTANCE));
         if (viaSynonym) {
             argList.add(new LiteralExpr(new StringLiteral(dataverseName.getCanonicalForm())));
             argList.add(new LiteralExpr(new StringLiteral(datasetName)));
@@ -241,24 +261,30 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi
                 dataverseName == null ? defaultDataverseName : dataverseName);
     }
 
-    private Pair<Dataset, Boolean> findDataset(DataverseName dataverseName, String datasetName,
+    private Pair<Dataset, Boolean> findDataset(DataverseName dataverseName, String datasetName, boolean includingViews,
             SourceLocation sourceLoc) throws CompilationException {
         try {
             Boolean viaSynonym = false;
             Triple<DataverseName, String, Boolean> dsName =
-                    metadataProvider.resolveDatasetNameUsingSynonyms(dataverseName, datasetName);
+                    metadataProvider.resolveDatasetNameUsingSynonyms(dataverseName, datasetName, includingViews);
             if (dsName != null) {
                 dataverseName = dsName.first;
                 datasetName = dsName.second;
                 viaSynonym = dsName.third;
             }
-            Dataset dataset = metadataProvider.findDataset(dataverseName, datasetName);
+            Dataset dataset = metadataProvider.findDataset(dataverseName, datasetName, includingViews);
             return dataset == null ? null : new Pair<>(dataset, viaSynonym);
         } catch (AlgebricksException e) {
             throw new CompilationException(ErrorCode.COMPILATION_ERROR, e, sourceLoc, e.getMessage());
         }
     }
 
+    private ViewDecl findDeclaredView(DataverseName dataverseName, String viewName) {
+        Map<DatasetFullyQualifiedName, ViewDecl> declaredViews = context.getDeclaredViews();
+        return declaredViews.isEmpty() ? null
+                : declaredViews.get(new DatasetFullyQualifiedName(dataverseName, viewName));
+    }
+
     @Override
     public Expression visit(CallExpr callExpr, ILangExpression arg) throws CompilationException {
         // skip variables inside SQL-92 aggregates (they will be resolved by SqlppGroupByAggregationSugarVisitor)
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 26f2a35..9d50160 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
@@ -103,6 +103,10 @@ public class SqlppVariableUtil {
         return EXTERNAL_VAR_PREFIX + varName;
     }
 
+    public static VarIdentifier toExternalVariableIdentifier(String idName) {
+        return new VarIdentifier(toExternalVariableName(idName));
+    }
+
     public static boolean isPositionalVariableIdentifier(VarIdentifier varId) {
         try {
             Integer.parseInt(toUserDefinedName(varId.getValue()));
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
index 083015b..efb9446 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
@@ -22,10 +22,10 @@ import java.io.PrintWriter;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.lang.common.base.AbstractClause;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.clause.GroupbyClause;
@@ -59,6 +59,7 @@ import org.apache.asterix.lang.sqlpp.expression.WindowExpression;
 import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
 import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
 import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.algebricks.common.utils.Triple;
 
 public class SqlppAstPrintVisitor extends QueryPrintVisitor implements ISqlppVisitor<Void, Integer> {
 
@@ -252,8 +253,10 @@ public class SqlppAstPrintVisitor extends QueryPrintVisitor implements ISqlppVis
         FunctionSignature functionSignature = callExpr.getFunctionSignature();
         //TODO(MULTI_PART_DATAVERSE_NAME):temporary workaround to preserve AST reference results
         if (FunctionUtil.isBuiltinDatasetFunction(functionSignature)) {
-            String singleArg = callExpr.getExprList().stream().map(LiteralExpr.class::cast).map(LiteralExpr::getValue)
-                    .map(StringLiteral.class::cast).map(StringLiteral::getValue).collect(Collectors.joining("."));
+            Triple<DatasetFullyQualifiedName, Boolean, DatasetFullyQualifiedName> dsArgs =
+                    FunctionUtil.parseDatasetFunctionArguments(callExpr);
+            String singleArg =
+                    String.join(".", dsArgs.first.getDataverseName().getParts()) + "." + dsArgs.first.getDatasetName();
             printFunctionCall(functionSignature, 1,
                     Collections.singletonList(new LiteralExpr(new StringLiteral(singleArg))),
                     callExpr.getAggregateFilterExpr(), step);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSynonymRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSynonymRewriteVisitor.java
index a0ffdf2..b47eb6e 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSynonymRewriteVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSynonymRewriteVisitor.java
@@ -44,7 +44,7 @@ public class SqlppSynonymRewriteVisitor extends AbstractSqlppAstVisitor<Void, Me
     @Override
     public Void visit(LoadStatement loadStmt, MetadataProvider metadataProvider) throws CompilationException {
         Triple<DataverseName, String, Boolean> dsName = resolveDatasetNameUsingSynonyms(metadataProvider,
-                loadStmt.getDataverseName(), loadStmt.getDatasetName(), loadStmt.getSourceLocation());
+                loadStmt.getDataverseName(), loadStmt.getDatasetName(), false, loadStmt.getSourceLocation());
         if (dsName != null) {
             loadStmt.setDataverseName(dsName.first);
             loadStmt.setDatasetName(dsName.second);
@@ -55,7 +55,7 @@ public class SqlppSynonymRewriteVisitor extends AbstractSqlppAstVisitor<Void, Me
     @Override
     public Void visit(InsertStatement insertStmt, MetadataProvider metadataProvider) throws CompilationException {
         Triple<DataverseName, String, Boolean> dsName = resolveDatasetNameUsingSynonyms(metadataProvider,
-                insertStmt.getDataverseName(), insertStmt.getDatasetName(), insertStmt.getSourceLocation());
+                insertStmt.getDataverseName(), insertStmt.getDatasetName(), false, insertStmt.getSourceLocation());
         if (dsName != null) {
             insertStmt.setDataverseName(dsName.first);
             insertStmt.setDatasetName(dsName.second);
@@ -66,7 +66,7 @@ public class SqlppSynonymRewriteVisitor extends AbstractSqlppAstVisitor<Void, Me
     @Override
     public Void visit(DeleteStatement deleteStmt, MetadataProvider metadataProvider) throws CompilationException {
         Triple<DataverseName, String, Boolean> dsName = resolveDatasetNameUsingSynonyms(metadataProvider,
-                deleteStmt.getDataverseName(), deleteStmt.getDatasetName(), deleteStmt.getSourceLocation());
+                deleteStmt.getDataverseName(), deleteStmt.getDatasetName(), false, deleteStmt.getSourceLocation());
         if (dsName != null) {
             deleteStmt.setDataverseName(dsName.first);
             deleteStmt.setDatasetName(dsName.second);
@@ -75,9 +75,10 @@ public class SqlppSynonymRewriteVisitor extends AbstractSqlppAstVisitor<Void, Me
     }
 
     private Triple<DataverseName, String, Boolean> resolveDatasetNameUsingSynonyms(MetadataProvider metadataProvider,
-            DataverseName dataverseName, String datasetName, SourceLocation sourceLoc) throws CompilationException {
+            DataverseName dataverseName, String datasetName, boolean includingViews, SourceLocation sourceLoc)
+            throws CompilationException {
         try {
-            return metadataProvider.resolveDatasetNameUsingSynonyms(dataverseName, datasetName);
+            return metadataProvider.resolveDatasetNameUsingSynonyms(dataverseName, datasetName, includingViews);
         } catch (AlgebricksException e) {
             throw new CompilationException(ErrorCode.COMPILATION_ERROR, e, sourceLoc, e.getMessage());
         }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index c4c86f4..cae5400 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -74,6 +74,7 @@ import org.apache.asterix.common.exceptions.WarningCollector;
 import org.apache.asterix.common.functions.FunctionConstants;
 import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.lang.common.base.AbstractClause;
 import org.apache.asterix.lang.common.base.AbstractLangExpression;
 import org.apache.asterix.lang.common.base.AbstractStatement;
@@ -135,6 +136,7 @@ import org.apache.asterix.lang.common.statement.CreateIndexStatement;
 import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
 import org.apache.asterix.lang.common.statement.CreateFullTextFilterStatement;
 import org.apache.asterix.lang.common.statement.CreateFullTextConfigStatement;
+import org.apache.asterix.lang.common.statement.CreateViewStatement;
 import org.apache.asterix.lang.common.statement.DatasetDecl;
 import org.apache.asterix.lang.common.statement.DataverseDecl;
 import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -162,6 +164,8 @@ import org.apache.asterix.lang.common.statement.TypeDecl;
 import org.apache.asterix.lang.common.statement.TypeDropStatement;
 import org.apache.asterix.lang.common.statement.UpdateStatement;
 import org.apache.asterix.lang.common.statement.UpsertStatement;
+import org.apache.asterix.lang.common.statement.ViewDecl;
+import org.apache.asterix.lang.common.statement.ViewDropStatement;
 import org.apache.asterix.lang.common.statement.WriteStatement;
 import org.apache.asterix.lang.common.struct.Identifier;
 import org.apache.asterix.lang.common.struct.OperatorType;
@@ -414,6 +418,22 @@ class SQLPPParser extends ScopeChecker implements IParser {
         });
     }
 
+    @Override
+    public ViewDecl parseViewBody(DatasetFullyQualifiedName viewName) throws CompilationException {
+        return parseImpl(new ParseFunction<ViewDecl>() {
+            @Override
+            public ViewDecl parse() throws ParseException {
+                DataverseName dataverse = defaultDataverse;
+                defaultDataverse = viewName.getDataverseName();
+                createNewScope();
+                Expression viewBodyExpr = SQLPPParser.this.ViewBody();
+                removeCurrentScope();
+                defaultDataverse = dataverse;
+                return new ViewDecl(viewName, viewBodyExpr);
+            }
+        });
+    }
+
     private <T> T parseImpl(ParseFunction<T> parseFunction) throws CompilationException {
         warningCollector.clear();
         hintCollector.clear();
@@ -796,6 +816,7 @@ Statement CreateStatement() throws ParseException:
     | stmt = CreateFeedStatement(startToken)
     | stmt = CreateFeedPolicyStatement(startToken)
     | stmt = CreateFullTextStatement(startToken)
+    | stmt = CreateViewStatement(startToken, false)
   )
   {
     return stmt;
@@ -811,6 +832,7 @@ Statement CreateOrReplaceStatement(Token startStmtToken) throws ParseException:
   <OR> <IDENTIFIER> { replaceToken = token; }
   (
     stmt = CreateFunctionStatement(startStmtToken, true)
+    | stmt = CreateViewStatement(startStmtToken, true)
   )
   {
     // check expected token here to make the grammar extension plugin happy
@@ -1381,6 +1403,65 @@ CreateAdapterStatement AdapterSpecification(Token startStmtToken) throws ParseEx
   }
 }
 
+CreateViewStatement CreateViewStatement(Token startStmtToken, boolean orReplace) throws ParseException:
+{
+  CreateViewStatement stmt = null;
+}
+{
+  <VIEW> stmt = ViewSpecification(startStmtToken, orReplace)
+  {
+    return stmt;
+  }
+}
+
+CreateViewStatement ViewSpecification(Token startStmtToken, boolean orReplace) throws ParseException:
+{
+  Pair<DataverseName, Identifier> nameComponents = null;
+  boolean ifNotExists = false;
+  Token beginPos = null, endPos = null;
+  Expression viewBodyExpr = null;
+  DataverseName currentDataverse = defaultDataverse;
+}
+{
+  nameComponents = QualifiedName()
+  ifNotExists = IfNotExists()
+  {
+    if (orReplace && ifNotExists) {
+      throw new SqlppParseException(getSourceLocation(token), "Unexpected IF NOT EXISTS");
+    }
+  }
+  <AS>
+  {
+    beginPos = token;
+    createNewScope();
+    if (nameComponents.first != null) {
+      defaultDataverse = nameComponents.first;
+    }
+  }
+  viewBodyExpr = ViewBody()
+  {
+    endPos = token;
+    String viewBody = extractFragment(beginPos.beginLine, beginPos.beginColumn + 1, endPos.endLine,
+      endPos.endColumn + 1);
+    removeCurrentScope();
+    defaultDataverse = currentDataverse;
+    CreateViewStatement stmt = new CreateViewStatement(nameComponents.first, nameComponents.second.getValue(), viewBody,
+      viewBodyExpr, orReplace, ifNotExists);
+    return addSourceLocation(stmt, startStmtToken);
+  }
+}
+
+Expression ViewBody() throws ParseException:
+{
+  Expression viewBodyExpr = null;
+}
+{
+  viewBodyExpr = SelectExpression(true)
+  {
+    return viewBodyExpr;
+  }
+}
+
 CreateFunctionStatement CreateFunctionStatement(Token startStmtToken, boolean orReplace) throws ParseException:
 {
   CreateFunctionStatement stmt = null;
@@ -1421,6 +1502,11 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken, boolean orRe
     signature = new FunctionSignature(fctName.dataverse, fctName.function, arity);
   }
   ifNotExists = IfNotExists()
+  {
+    if (orReplace && ifNotExists) {
+      throw new SqlppParseException(getSourceLocation(token), "Unexpected IF NOT EXISTS");
+    }
+  }
   returnType = FunctionReturnType()
   (
     (
@@ -1457,9 +1543,6 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken, boolean orRe
     )
   )
   {
-    if (orReplace && ifNotExists) {
-      throw new SqlppParseException(getSourceLocation(startStmtToken), "Unexpected IF NOT EXISTS");
-    }
     defaultDataverse = currentDataverse;
     return addSourceLocation(stmt, startStmtToken);
   }
@@ -1852,6 +1935,7 @@ Statement DropStatement() throws ParseException:
     | stmt = DropFeedPolicyStatement(startToken)
     | stmt = DropSynonymStatement(startToken)
     | stmt = DropFullTextStatement(startToken)
+    | stmt = DropViewStatement(startToken)
   )
   {
     return stmt;
@@ -1882,6 +1966,30 @@ DropDatasetStatement DropDatasetSpecification(Token startStmtToken) throws Parse
   }
 }
 
+ViewDropStatement DropViewStatement(Token startStmtToken) throws ParseException:
+{
+  ViewDropStatement stmt = null;
+}
+{
+  <VIEW> stmt = DropViewSpecification(startStmtToken)
+  {
+    return stmt;
+  }
+}
+
+ViewDropStatement DropViewSpecification(Token startStmtToken) throws ParseException:
+{
+  Pair<DataverseName,Identifier> pairId = null;
+  boolean ifExists = false;
+}
+{
+  pairId = QualifiedName() ifExists = IfExists()
+  {
+    ViewDropStatement stmt = new ViewDropStatement(pairId.first, pairId.second, ifExists);
+    return addSourceLocation(stmt, startStmtToken);
+  }
+}
+
 IndexDropStatement DropIndexStatement(Token startStmtToken) throws ParseException:
 {
   IndexDropStatement stmt = null;
@@ -4988,6 +5096,7 @@ TOKEN [IGNORE_CASE]:
   | <USING : "using">
   | <VALUE : "value">
   | <VALUED : "valued">
+  | <VIEW : "view">
   | <WHEN : "when">
   | <WHERE : "where">
   | <WITH : "with">
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
index 9975f4c..a5dda0d 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
@@ -20,7 +20,6 @@
 package org.apache.asterix.metadata;
 
 import static org.apache.asterix.common.api.IIdentifierMapper.Modifier.PLURAL;
-import static org.apache.asterix.common.exceptions.ErrorCode.FULL_TEXT_DEFAULT_CONFIG_CANNOT_BE_DELETED_OR_CREATED;
 import static org.apache.asterix.common.utils.IdentifierUtil.dataset;
 
 import java.rmi.RemoteException;
@@ -68,6 +67,7 @@ import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.DatasourceAdapter;
 import org.apache.asterix.metadata.entities.Datatype;
 import org.apache.asterix.metadata.entities.Dataverse;
+import org.apache.asterix.metadata.entities.DependencyKind;
 import org.apache.asterix.metadata.entities.Feed;
 import org.apache.asterix.metadata.entities.FeedConnection;
 import org.apache.asterix.metadata.entities.FeedPolicyEntity;
@@ -80,6 +80,7 @@ import org.apache.asterix.metadata.entities.Library;
 import org.apache.asterix.metadata.entities.Node;
 import org.apache.asterix.metadata.entities.NodeGroup;
 import org.apache.asterix.metadata.entities.Synonym;
+import org.apache.asterix.metadata.entities.ViewDetails;
 import org.apache.asterix.metadata.entitytupletranslators.CompactionPolicyTupleTranslator;
 import org.apache.asterix.metadata.entitytupletranslators.DatasetTupleTranslator;
 import org.apache.asterix.metadata.entitytupletranslators.DatasourceAdapterTupleTranslator;
@@ -772,15 +773,16 @@ public class MetadataNode implements IMetadataNode {
     @Override
     public void dropDataset(TxnId txnId, DataverseName dataverseName, String datasetName, boolean force)
             throws AlgebricksException {
-        if (!force) {
-            confirmDatasetCanBeDeleted(txnId, dataverseName, datasetName);
-        }
-
         Dataset dataset = getDataset(txnId, dataverseName, datasetName);
         if (dataset == null) {
             throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE,
                     datasetName, dataverseName);
         }
+        if (!force) {
+            String datasetTypeDisplayName = DatasetUtil.getDatasetTypeDisplayName(dataset.getDatasetType());
+            confirmDatasetCanBeDeleted(txnId, datasetTypeDisplayName, dataverseName, datasetName);
+        }
+
         try {
             // Delete entry from the 'datasets' dataset.
             ITupleReference searchKey = createTuple(dataverseName, datasetName);
@@ -790,25 +792,37 @@ public class MetadataNode implements IMetadataNode {
             try {
                 datasetTuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.DATASET_DATASET, searchKey);
 
-                // Delete entry(s) from the 'indexes' dataset.
-                List<Index> datasetIndexes = getDatasetIndexes(txnId, dataverseName, datasetName);
-                if (datasetIndexes != null) {
-                    for (Index index : datasetIndexes) {
-                        dropIndex(txnId, dataverseName, datasetName, index.getIndexName());
-                    }
-                }
-
-                if (dataset.getDatasetType() == DatasetType.EXTERNAL) {
-                    // Delete External Files
-                    // As a side effect, acquires an S lock on the 'ExternalFile' dataset
-                    // on behalf of txnId.
-                    List<ExternalFile> datasetFiles = getExternalFiles(txnId, dataset);
-                    if (datasetFiles != null && !datasetFiles.isEmpty()) {
-                        // Drop all external files in this dataset.
-                        for (ExternalFile file : datasetFiles) {
-                            dropExternalFile(txnId, dataverseName, file.getDatasetName(), file.getFileNumber());
+                switch (dataset.getDatasetType()) {
+                    case INTERNAL:
+                        // Delete entry(s) from the 'indexes' dataset.
+                        List<Index> datasetIndexes = getDatasetIndexes(txnId, dataverseName, datasetName);
+                        if (datasetIndexes != null) {
+                            for (Index index : datasetIndexes) {
+                                dropIndex(txnId, dataverseName, datasetName, index.getIndexName());
+                            }
                         }
-                    }
+                        break;
+                    case EXTERNAL:
+                        // Delete entry(s) from the 'indexes' dataset.
+                        datasetIndexes = getDatasetIndexes(txnId, dataverseName, datasetName);
+                        if (datasetIndexes != null) {
+                            for (Index index : datasetIndexes) {
+                                dropIndex(txnId, dataverseName, datasetName, index.getIndexName());
+                            }
+                        }
+                        // Delete External Files
+                        // As a side effect, acquires an S lock on the 'ExternalFile' dataset
+                        // on behalf of txnId.
+                        List<ExternalFile> datasetFiles = getExternalFiles(txnId, dataset);
+                        if (datasetFiles != null && !datasetFiles.isEmpty()) {
+                            // Drop all external files in this dataset.
+                            for (ExternalFile file : datasetFiles) {
+                                dropExternalFile(txnId, dataverseName, file.getDatasetName(), file.getFileNumber());
+                            }
+                        }
+                        break;
+                    case VIEW:
+                        break;
                 }
             } catch (HyracksDataException hde) {
                 // ignore this exception and continue deleting all relevant
@@ -1124,44 +1138,60 @@ public class MetadataNode implements IMetadataNode {
         // uses a type from this dataverse
         // throw an error
         List<Dataset> datasets = getAllDatasets(txnId);
-        for (Dataset set : datasets) {
-            if (set.getDataverseName().equals(dataverseName)) {
+        for (Dataset dataset : datasets) {
+            if (dataset.getDataverseName().equals(dataverseName)) {
                 continue;
             }
-            if (set.getItemTypeDataverseName().equals(dataverseName)) {
+            if (dataset.getItemTypeDataverseName().equals(dataverseName)) {
                 throw new AsterixException(
                         org.apache.asterix.common.exceptions.ErrorCode.CANNOT_DROP_DATAVERSE_DEPENDENT_EXISTS, "type",
-                        TypeUtil.getFullyQualifiedDisplayName(set.getItemTypeDataverseName(), set.getItemTypeName()),
-                        dataset(), DatasetUtil.getFullyQualifiedDisplayName(set));
+                        TypeUtil.getFullyQualifiedDisplayName(dataset.getItemTypeDataverseName(),
+                                dataset.getItemTypeName()),
+                        dataset(), DatasetUtil.getFullyQualifiedDisplayName(dataset));
             }
-            if (set.getMetaItemTypeDataverseName() != null
-                    && set.getMetaItemTypeDataverseName().equals(dataverseName)) {
+            if (dataset.hasMetaPart() && dataset.getMetaItemTypeDataverseName().equals(dataverseName)) {
                 throw new AsterixException(
                         org.apache.asterix.common.exceptions.ErrorCode.CANNOT_DROP_DATAVERSE_DEPENDENT_EXISTS, "type",
-                        TypeUtil.getFullyQualifiedDisplayName(set.getMetaItemTypeDataverseName(),
-                                set.getMetaItemTypeName()),
-                        dataset(), DatasetUtil.getFullyQualifiedDisplayName(set));
+                        TypeUtil.getFullyQualifiedDisplayName(dataset.getMetaItemTypeDataverseName(),
+                                dataset.getMetaItemTypeName()),
+                        dataset(), DatasetUtil.getFullyQualifiedDisplayName(dataset));
+            }
+            if (dataset.getDatasetType() == DatasetType.VIEW) {
+                ViewDetails viewDetails = (ViewDetails) dataset.getDatasetDetails();
+                List<DependencyKind> dependenciesSchema = ViewDetails.DEPENDENCIES_SCHEMA;
+                List<List<Triple<DataverseName, String, String>>> dependencies = viewDetails.getDependencies();
+                for (int i = 0, n = dependencies.size(); i < n; i++) {
+                    for (Triple<DataverseName, String, String> dependency : dependencies.get(i)) {
+                        if (dependency.first.equals(dataverseName)) {
+                            DependencyKind dependencyKind = dependenciesSchema.get(i);
+                            throw new AsterixException(
+                                    org.apache.asterix.common.exceptions.ErrorCode.CANNOT_DROP_DATAVERSE_DEPENDENT_EXISTS,
+                                    dependencyKind, dependencyKind.getDependencyDisplayName(dependency), "view",
+                                    DatasetUtil.getFullyQualifiedDisplayName(dataset));
+                        }
+                    }
+                }
             }
         }
 
         // If a function from a DIFFERENT dataverse
         // uses datasets, functions, datatypes, or synonyms from this dataverse
         // throw an error
-        Function.FunctionDependencyKind[] functionDependencyKinds = Function.FunctionDependencyKind.values();
         List<Function> functions = getAllFunctions(txnId);
         for (Function function : functions) {
             if (function.getDataverseName().equals(dataverseName)) {
                 continue;
             }
+            List<DependencyKind> dependenciesSchema = Function.DEPENDENCIES_SCHEMA;
             List<List<Triple<DataverseName, String, String>>> dependencies = function.getDependencies();
             for (int i = 0, n = dependencies.size(); i < n; i++) {
                 for (Triple<DataverseName, String, String> dependency : dependencies.get(i)) {
                     if (dependency.first.equals(dataverseName)) {
-                        Function.FunctionDependencyKind functionDependencyKind = functionDependencyKinds[i];
+                        DependencyKind dependencyKind = dependenciesSchema.get(i);
                         throw new AsterixException(
                                 org.apache.asterix.common.exceptions.ErrorCode.CANNOT_DROP_DATAVERSE_DEPENDENT_EXISTS,
-                                functionDependencyKind, functionDependencyKind.getDependencyDisplayName(dependency),
-                                "function", function.getSignature());
+                                dependencyKind, dependencyKind.getDependencyDisplayName(dependency), "function",
+                                function.getSignature());
                     }
                 }
             }
@@ -1186,6 +1216,7 @@ public class MetadataNode implements IMetadataNode {
     }
 
     private void confirmFunctionCanBeDeleted(TxnId txnId, FunctionSignature signature) throws AlgebricksException {
+        confirmFunctionIsUnusedByViews(txnId, signature);
         confirmFunctionIsUnusedByFunctions(txnId, signature);
 
         // if any other feed connection uses this function, throw an error
@@ -1200,18 +1231,34 @@ public class MetadataNode implements IMetadataNode {
         }
     }
 
+    private void confirmFunctionIsUnusedByViews(TxnId txnId, FunctionSignature signature) throws AlgebricksException {
+        confirmObjectIsUnusedByViews(txnId, "function", DependencyKind.FUNCTION, signature.getDataverseName(),
+                signature.getName(), Integer.toString(signature.getArity()));
+    }
+
     private void confirmFunctionIsUnusedByFunctions(TxnId txnId, FunctionSignature signature)
             throws AlgebricksException {
-        confirmObjectIsUnusedByFunctions(txnId, Function.FunctionDependencyKind.FUNCTION, signature.getDataverseName(),
+        confirmObjectIsUnusedByFunctions(txnId, "function", DependencyKind.FUNCTION, signature.getDataverseName(),
                 signature.getName(), Integer.toString(signature.getArity()));
     }
 
-    private void confirmObjectIsUnusedByFunctions(TxnId txnId, Function.FunctionDependencyKind dependencyKind,
-            DataverseName dataverseName, String objectName, String objectArg) throws AlgebricksException {
+    private void confirmObjectIsUnusedByFunctions(TxnId txnId, String objectKindDisplayName,
+            DependencyKind dependencyKind, DataverseName dataverseName, String objectName, String objectArg)
+            throws AlgebricksException {
         // If any function uses this object, throw an error
-        int functionDependencyIdx = dependencyKind.ordinal();
         List<Function> functions = getAllFunctions(txnId);
-        for (Function function : functions) {
+        confirmObjectIsUnusedByFunctionsImpl(functions, objectKindDisplayName, dependencyKind, dataverseName,
+                objectName, objectArg);
+    }
+
+    private void confirmObjectIsUnusedByFunctionsImpl(List<Function> allFunctions, String objectKindDisplayName,
+            DependencyKind dependencyKind, DataverseName dataverseName, String objectName, String objectArg)
+            throws AlgebricksException {
+        int functionDependencyIdx = Function.DEPENDENCIES_SCHEMA.indexOf(dependencyKind);
+        if (functionDependencyIdx < 0) {
+            throw new AlgebricksException(ErrorCode.ILLEGAL_STATE);
+        }
+        for (Function function : allFunctions) {
             List<List<Triple<DataverseName, String, String>>> functionDependencies = function.getDependencies();
             if (functionDependencyIdx < functionDependencies.size()) {
                 List<Triple<DataverseName, String, String>> functionObjectDependencies =
@@ -1222,9 +1269,46 @@ public class MetadataNode implements IMetadataNode {
                                 && (objectArg == null || objectArg.equals(dependency.third))) {
                             throw new AsterixException(
                                     org.apache.asterix.common.exceptions.ErrorCode.CANNOT_DROP_OBJECT_DEPENDENT_EXISTS,
-                                    dependencyKind.toString().toLowerCase(),
-                                    dependencyKind.getDependencyDisplayName(dependency), "function",
-                                    function.getSignature());
+                                    objectKindDisplayName, dependencyKind.getDependencyDisplayName(dependency),
+                                    "function", function.getSignature());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void confirmObjectIsUnusedByViews(TxnId txnId, String objectKindDisplayName, DependencyKind dependencyKind,
+            DataverseName dataverseName, String objectName, String objectArg) throws AlgebricksException {
+        // If any function uses this object, throw an error
+        List<Dataset> datasets = getAllDatasets(txnId);
+        confirmObjectIsUnusedByViewsImpl(datasets, objectKindDisplayName, dependencyKind, dataverseName, objectName,
+                objectArg);
+    }
+
+    private void confirmObjectIsUnusedByViewsImpl(List<Dataset> allDatasets, String objectKindDisplayName,
+            DependencyKind dependencyKind, DataverseName dataverseName, String objectName, String objectArg)
+            throws AlgebricksException {
+        int viewDependencyIdx = ViewDetails.DEPENDENCIES_SCHEMA.indexOf(dependencyKind);
+        if (viewDependencyIdx < 0) {
+            throw new AlgebricksException(ErrorCode.ILLEGAL_STATE);
+        }
+        for (Dataset dataset : allDatasets) {
+            if (dataset.getDatasetType() == DatasetType.VIEW) {
+                ViewDetails viewDetails = (ViewDetails) dataset.getDatasetDetails();
+                List<List<Triple<DataverseName, String, String>>> viewDependencies = viewDetails.getDependencies();
+                if (viewDependencyIdx < viewDependencies.size()) {
+                    List<Triple<DataverseName, String, String>> viewObjectDependencies =
+                            viewDependencies.get(viewDependencyIdx);
+                    if (viewObjectDependencies != null) {
+                        for (Triple<DataverseName, String, String> dependency : viewObjectDependencies) {
+                            if (dependency.first.equals(dataverseName) && dependency.second.equals(objectName)
+                                    && (objectArg == null || objectArg.equals(dependency.third))) {
+                                throw new AsterixException(
+                                        org.apache.asterix.common.exceptions.ErrorCode.CANNOT_DROP_OBJECT_DEPENDENT_EXISTS,
+                                        objectKindDisplayName, dependencyKind.getDependencyDisplayName(dependency),
+                                        "view", DatasetUtil.getFullyQualifiedDisplayName(dataset));
+                            }
                         }
                     }
                 }
@@ -1235,7 +1319,8 @@ public class MetadataNode implements IMetadataNode {
     private void confirmFullTextConfigCanBeDeleted(TxnId txnId, DataverseName dataverseNameFullTextConfig,
             String configName) throws AlgebricksException {
         if (Strings.isNullOrEmpty(configName)) {
-            throw new MetadataException(FULL_TEXT_DEFAULT_CONFIG_CANNOT_BE_DELETED_OR_CREATED);
+            throw new MetadataException(
+                    org.apache.asterix.common.exceptions.ErrorCode.FULL_TEXT_DEFAULT_CONFIG_CANNOT_BE_DELETED_OR_CREATED);
         }
 
         // If any index uses this full-text config, throw an error
@@ -1263,14 +1348,21 @@ public class MetadataNode implements IMetadataNode {
         }
     }
 
-    private void confirmDatasetCanBeDeleted(TxnId txnId, DataverseName dataverseName, String datasetName)
-            throws AlgebricksException {
-        confirmDatasetIsUnusedByFunctions(txnId, dataverseName, datasetName);
+    private void confirmDatasetCanBeDeleted(TxnId txnId, String datasetTypeDisplayName, DataverseName dataverseName,
+            String datasetName) throws AlgebricksException {
+        confirmDatasetIsUnusedByFunctions(txnId, datasetTypeDisplayName, dataverseName, datasetName);
+        confirmDatasetIsUnusedByViews(txnId, datasetTypeDisplayName, dataverseName, datasetName);
     }
 
-    private void confirmDatasetIsUnusedByFunctions(TxnId txnId, DataverseName dataverseName, String datasetName)
-            throws AlgebricksException {
-        confirmObjectIsUnusedByFunctions(txnId, Function.FunctionDependencyKind.DATASET, dataverseName, datasetName,
+    private void confirmDatasetIsUnusedByFunctions(TxnId txnId, String datasetKindDisplayName,
+            DataverseName dataverseName, String datasetName) throws AlgebricksException {
+        confirmObjectIsUnusedByFunctions(txnId, datasetKindDisplayName, DependencyKind.DATASET, dataverseName,
+                datasetName, null);
+    }
+
+    private void confirmDatasetIsUnusedByViews(TxnId txnId, String datasetKindDisplayName, DataverseName dataverseName,
+            String datasetName) throws AlgebricksException {
+        confirmObjectIsUnusedByViews(txnId, datasetKindDisplayName, DependencyKind.DATASET, dataverseName, datasetName,
                 null);
     }
 
@@ -1320,14 +1412,21 @@ public class MetadataNode implements IMetadataNode {
             throws AlgebricksException {
         // If any dataset uses this type, throw an error
         List<Dataset> datasets = getAllDatasets(txnId);
-        for (Dataset set : datasets) {
-            if (set.getItemTypeName().equals(datatypeName) && set.getItemTypeDataverseName().equals(dataverseName)) {
+        for (Dataset dataset : datasets) {
+            if ((dataset.getItemTypeName().equals(datatypeName)
+                    && dataset.getItemTypeDataverseName().equals(dataverseName))
+                    || ((dataset.hasMetaPart() && dataset.getMetaItemTypeName().equals(datatypeName)
+                            && dataset.getMetaItemTypeDataverseName().equals(dataverseName)))) {
                 throw new AsterixException(
                         org.apache.asterix.common.exceptions.ErrorCode.CANNOT_DROP_OBJECT_DEPENDENT_EXISTS, "type",
                         TypeUtil.getFullyQualifiedDisplayName(dataverseName, datatypeName), dataset(),
-                        DatasetUtil.getFullyQualifiedDisplayName(set));
+                        DatasetUtil.getFullyQualifiedDisplayName(dataset));
             }
         }
+
+        // additionally, if a view uses this type, throw an error
+        // Note: for future use. currently views don't have any type dependencies
+        confirmObjectIsUnusedByViewsImpl(datasets, null, DependencyKind.TYPE, dataverseName, datatypeName, null);
     }
 
     private void confirmDatatypeIsUnusedByDatatypes(TxnId txnId, DataverseName dataverseName, String datatypeName)
@@ -1357,8 +1456,7 @@ public class MetadataNode implements IMetadataNode {
 
     private void confirmDatatypeIsUnusedByFunctions(TxnId txnId, DataverseName dataverseName, String dataTypeName)
             throws AlgebricksException {
-        confirmObjectIsUnusedByFunctions(txnId, Function.FunctionDependencyKind.TYPE, dataverseName, dataTypeName,
-                null);
+        confirmObjectIsUnusedByFunctions(txnId, "datatype", DependencyKind.TYPE, dataverseName, dataTypeName, null);
     }
 
     private void confirmFullTextFilterCanBeDeleted(TxnId txnId, DataverseName dataverseName, String fullTextFilterName)
@@ -2300,12 +2398,17 @@ public class MetadataNode implements IMetadataNode {
     private void confirmSynonymCanBeDeleted(TxnId txnId, DataverseName dataverseName, String synonymName)
             throws AlgebricksException {
         confirmSynonymIsUnusedByFunctions(txnId, dataverseName, synonymName);
+        confirmSynonymIsUnusedByViews(txnId, dataverseName, synonymName);
     }
 
     private void confirmSynonymIsUnusedByFunctions(TxnId txnId, DataverseName dataverseName, String synonymName)
             throws AlgebricksException {
-        confirmObjectIsUnusedByFunctions(txnId, Function.FunctionDependencyKind.SYNONYM, dataverseName, synonymName,
-                null);
+        confirmObjectIsUnusedByFunctions(txnId, "synonym", DependencyKind.SYNONYM, dataverseName, synonymName, null);
+    }
+
+    private void confirmSynonymIsUnusedByViews(TxnId txnId, DataverseName dataverseName, String synonymName)
+            throws AlgebricksException {
+        confirmObjectIsUnusedByViews(txnId, "synonym", DependencyKind.SYNONYM, dataverseName, synonymName, null);
     }
 
     @Override
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
index 125db21..fd0d30b 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
@@ -507,6 +507,10 @@ public class MetadataBootstrap {
 
     private static void recoverDataset(MetadataTransactionContext mdTxnCtx, Dataset dataset)
             throws AlgebricksException {
+        if (dataset.getDatasetType() == DatasetType.VIEW) {
+            // Views don't need any recovery and cannot be in a pending state
+            return;
+        }
         if (dataset.getPendingOp() != MetadataUtil.PENDING_NO_OP) {
             // drop pending dataset
             MetadataManager.INSTANCE.dropDataset(mdTxnCtx, dataset.getDataverseName(), dataset.getDatasetName(), true);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
index 2e75319..ef9f5d7 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
@@ -107,6 +107,7 @@ public final class MetadataRecordTypes {
     public static final String FIELD_NAME_TYPE = "Type";
     public static final String FIELD_NAME_UNORDERED_LIST = "UnorderedList";
     public static final String FIELD_NAME_VALUE = "Value";
+    public static final String FIELD_NAME_VIEW_DETAILS = "ViewDetails";
     public static final String FIELD_NAME_WORKING_MEMORY_SIZE = "WorkingMemorySize";
     public static final String FIELD_NAME_APPLIED_FUNCTIONS = "AppliedFunctions";
     public static final String FIELD_NAME_WHERE_CLAUSE = "WhereClause";
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
index 1376008..ee629b1 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
@@ -18,14 +18,13 @@
  */
 package org.apache.asterix.metadata.declared;
 
-import static org.apache.asterix.common.utils.IdentifierUtil.dataset;
 import static org.apache.asterix.common.utils.IdentifierUtil.dataverse;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.asterix.common.cluster.IClusterStateManager;
-import org.apache.asterix.common.config.DatasetConfig.DatasetType;
+import org.apache.asterix.common.config.DatasetConfig;
 import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.common.metadata.DataverseName;
@@ -103,17 +102,25 @@ public class MetadataManagerUtil {
         return adapter;
     }
 
-    public static Dataset findDataset(MetadataTransactionContext mdTxnCtx, DataverseName dataverseName, String dataset)
-            throws AlgebricksException {
-        return MetadataManager.INSTANCE.getDataset(mdTxnCtx, dataverseName, dataset);
+    public static Dataset findDataset(MetadataTransactionContext mdTxnCtx, DataverseName dataverseName,
+            String datasetName, boolean includingViews) throws AlgebricksException {
+        Dataset dataset = MetadataManager.INSTANCE.getDataset(mdTxnCtx, dataverseName, datasetName);
+        if (!includingViews && dataset != null && dataset.getDatasetType() == DatasetConfig.DatasetType.VIEW) {
+            return null;
+        }
+        return dataset;
+    }
+
+    public static Dataset findDataset(MetadataTransactionContext mdTxnCtx, DataverseName dataverseName,
+            String datasetName) throws AlgebricksException {
+        return findDataset(mdTxnCtx, dataverseName, datasetName, false);
     }
 
     public static Dataset findExistingDataset(MetadataTransactionContext mdTxnCtx, DataverseName dataverseName,
             String datasetName) throws AlgebricksException {
         Dataset dataset = findDataset(mdTxnCtx, dataverseName, datasetName);
         if (dataset == null) {
-            throw new AlgebricksException(
-                    "Unknown " + dataset() + " " + datasetName + " in " + dataverse() + " " + dataverseName);
+            throw new AsterixException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, datasetName, dataverseName);
         }
         return dataset;
     }
@@ -185,13 +192,25 @@ public class MetadataManagerUtil {
             MetadataTransactionContext mdTxnCtx, DataSourceId id) throws AlgebricksException {
         Dataset dataset = findDataset(mdTxnCtx, id.getDataverseName(), id.getDatasourceName());
         if (dataset == null) {
-            throw new AlgebricksException("Datasource with id " + id + " was not found.");
+            throw new AsterixException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, id.getDatasourceName(),
+                    id.getDataverseName());
         }
+        byte datasourceType;
+        switch (dataset.getDatasetType()) {
+            case INTERNAL:
+                datasourceType = DataSource.Type.INTERNAL_DATASET;
+                break;
+            case EXTERNAL:
+                datasourceType = DataSource.Type.EXTERNAL_DATASET;
+                break;
+            default:
+                throw new AsterixException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, id.getDatasourceName(),
+                        id.getDataverseName());
+        }
+
         IAType itemType = findType(mdTxnCtx, dataset.getItemTypeDataverseName(), dataset.getItemTypeName());
         IAType metaItemType = findType(mdTxnCtx, dataset.getMetaItemTypeDataverseName(), dataset.getMetaItemTypeName());
         INodeDomain domain = findNodeDomain(clusterStateManager, mdTxnCtx, dataset.getNodeGroupName());
-        byte datasourceType = dataset.getDatasetType().equals(DatasetType.EXTERNAL) ? DataSource.Type.EXTERNAL_DATASET
-                : DataSource.Type.INTERNAL_DATASET;
         return new DatasetDataSource(id, dataset, itemType, metaItemType, datasourceType, dataset.getDatasetDetails(),
                 domain);
     }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
index d970b3a..6f91572 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
@@ -20,7 +20,6 @@ package org.apache.asterix.metadata.declared;
 
 import static org.apache.asterix.common.api.IIdentifierMapper.Modifier.PLURAL;
 import static org.apache.asterix.common.utils.IdentifierUtil.dataset;
-import static org.apache.asterix.common.utils.IdentifierUtil.dataverse;
 import static org.apache.asterix.metadata.utils.MetadataConstants.METADATA_OBJECT_NAME_INVALID_CHARS;
 
 import java.io.File;
@@ -360,13 +359,18 @@ public class MetadataProvider implements IMetadataProvider<DataSourceId, String>
     }
 
     public Dataset findDataset(DataverseName dataverseName, String datasetName) throws AlgebricksException {
+        return findDataset(dataverseName, datasetName, false);
+    }
+
+    public Dataset findDataset(DataverseName dataverseName, String datasetName, boolean includingViews)
+            throws AlgebricksException {
         DataverseName dvName = getActiveDataverseName(dataverseName);
         if (dvName == null) {
             return null;
         }
         appCtx.getMetadataLockManager().acquireDataverseReadLock(locks, dvName);
         appCtx.getMetadataLockManager().acquireDatasetReadLock(locks, dvName, datasetName);
-        return MetadataManagerUtil.findDataset(mdTxnCtx, dvName, datasetName);
+        return MetadataManagerUtil.findDataset(mdTxnCtx, dvName, datasetName, includingViews);
     }
 
     public INodeDomain findNodeDomain(String nodeGroupName) throws AlgebricksException {
@@ -436,13 +440,13 @@ public class MetadataProvider implements IMetadataProvider<DataSourceId, String>
     }
 
     public Triple<DataverseName, String, Boolean> resolveDatasetNameUsingSynonyms(DataverseName dataverseName,
-            String datasetName) throws AlgebricksException {
+            String datasetName, boolean includingViews) throws AlgebricksException {
         DataverseName dvName = getActiveDataverseName(dataverseName);
         if (dvName == null) {
             return null;
         }
         Synonym synonym = null;
-        while (MetadataManagerUtil.findDataset(mdTxnCtx, dvName, datasetName) == null) {
+        while (MetadataManagerUtil.findDataset(mdTxnCtx, dvName, datasetName, includingViews) == null) {
             synonym = findSynonym(dvName, datasetName);
             if (synonym == null) {
                 return null;
@@ -986,11 +990,11 @@ public class MetadataProvider implements IMetadataProvider<DataSourceId, String>
             List<LogicalVariable> primaryKeys, LogicalVariable payload, List<LogicalVariable> filterKeys,
             List<LogicalVariable> additionalNonFilterFields, RecordDescriptor recordDesc, JobGenContext context,
             JobSpecification spec) throws AlgebricksException {
+        DataverseName dataverseName = dataSource.getId().getDataverseName();
         String datasetName = dataSource.getId().getDatasourceName();
-        Dataset dataset = findDataset(dataSource.getId().getDataverseName(), datasetName);
+        Dataset dataset = findDataset(dataverseName, datasetName);
         if (dataset == null) {
-            throw new AlgebricksException("Unknown " + dataset() + " " + datasetName + " in " + dataverse() + " "
-                    + dataSource.getId().getDataverseName());
+            throw new AsterixException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, datasetName, dataverseName);
         }
         int numKeys = primaryKeys.size();
         int numFilterFields = DatasetUtil.getFilterField(dataset) == null ? 0 : 1;
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Dataset.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Dataset.java
index 34e0c41..37e22ed 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Dataset.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Dataset.java
@@ -389,7 +389,7 @@ public class Dataset implements IMetadataEntity<Dataset>, IDataset {
             mdTxnCtx.setValue(MetadataManager.INSTANCE.beginTransaction());
             bActiveTxn.setValue(true);
             metadataProvider.setMetadataTxnContext(mdTxnCtx.getValue());
-        } else {
+        } else if (getDatasetType() == DatasetType.EXTERNAL) {
             // External dataset
             ExternalDatasetsRegistry.INSTANCE.removeDatasetInfo(this);
             // #. prepare jobs to drop the datatset and the indexes in NC
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/DependencyKind.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/DependencyKind.java
new file mode 100644
index 0000000..19939f9
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/DependencyKind.java
@@ -0,0 +1,54 @@
+/*
+ * 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.metadata.entities;
+
+import static org.apache.asterix.common.utils.IdentifierUtil.dataset;
+
+import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.metadata.utils.DatasetUtil;
+import org.apache.asterix.metadata.utils.MetadataUtil;
+import org.apache.asterix.metadata.utils.TypeUtil;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+
+public enum DependencyKind {
+    DATASET(dependency -> DatasetUtil.getFullyQualifiedDisplayName(dependency.first, dependency.second)),
+    FUNCTION(
+            dependency -> new FunctionSignature(dependency.first, dependency.second, Integer.parseInt(dependency.third))
+                    .toString()),
+    TYPE(dependency -> TypeUtil.getFullyQualifiedDisplayName(dependency.first, dependency.second)),
+    SYNONYM(dependency -> MetadataUtil.getFullyQualifiedDisplayName(dependency.first, dependency.second));
+
+    private final java.util.function.Function<Triple<DataverseName, String, String>, String> dependencyDisplayNameAccessor;
+
+    DependencyKind(
+            java.util.function.Function<Triple<DataverseName, String, String>, String> dependencyDisplayNameAccessor) {
+        this.dependencyDisplayNameAccessor = dependencyDisplayNameAccessor;
+    }
+
+    public String getDependencyDisplayName(Triple<DataverseName, String, String> dependency) {
+        return dependencyDisplayNameAccessor.apply(dependency);
+    }
+
+    @Override
+    public String toString() {
+        return this == DATASET ? dataset() + " (or view)" : name().toLowerCase();
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
index a9fa024..8853c02 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
@@ -18,8 +18,6 @@
  */
 package org.apache.asterix.metadata.entities;
 
-import static org.apache.asterix.common.utils.IdentifierUtil.dataset;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -30,9 +28,6 @@ import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.metadata.MetadataCache;
 import org.apache.asterix.metadata.api.IMetadataEntity;
-import org.apache.asterix.metadata.utils.DatasetUtil;
-import org.apache.asterix.metadata.utils.MetadataUtil;
-import org.apache.asterix.metadata.utils.TypeUtil;
 import org.apache.asterix.om.types.TypeSignature;
 import org.apache.hyracks.algebricks.common.utils.Triple;
 
@@ -166,12 +161,15 @@ public class Function implements IMetadataEntity<Function> {
         return cache.dropFunction(this);
     }
 
+    public static List<DependencyKind> DEPENDENCIES_SCHEMA =
+            Arrays.asList(DependencyKind.DATASET, DependencyKind.FUNCTION, DependencyKind.TYPE, DependencyKind.SYNONYM);
+
     public static List<List<Triple<DataverseName, String, String>>> createDependencies(
             List<Triple<DataverseName, String, String>> datasetDependencies,
             List<Triple<DataverseName, String, String>> functionDependencies,
             List<Triple<DataverseName, String, String>> typeDependencies,
             List<Triple<DataverseName, String, String>> synonymDependencies) {
-        List<List<Triple<DataverseName, String, String>>> depList = new ArrayList<>(4);
+        List<List<Triple<DataverseName, String, String>>> depList = new ArrayList<>(DEPENDENCIES_SCHEMA.size());
         depList.add(datasetDependencies);
         depList.add(functionDependencies);
         depList.add(typeDependencies);
@@ -180,29 +178,4 @@ public class Function implements IMetadataEntity<Function> {
         }
         return depList;
     }
-
-    public enum FunctionDependencyKind {
-        DATASET(dependency -> DatasetUtil.getFullyQualifiedDisplayName(dependency.first, dependency.second)),
-        FUNCTION(
-                dependency -> new FunctionSignature(dependency.first, dependency.second,
-                        Integer.parseInt(dependency.third)).toString()),
-        TYPE(dependency -> TypeUtil.getFullyQualifiedDisplayName(dependency.first, dependency.second)),
-        SYNONYM(dependency -> MetadataUtil.getFullyQualifiedDisplayName(dependency.first, dependency.second));
-
-        private final java.util.function.Function<Triple<DataverseName, String, String>, String> dependencyDisplayNameAccessor;
-
-        FunctionDependencyKind(
-                java.util.function.Function<Triple<DataverseName, String, String>, String> dependencyDisplayNameAccessor) {
-            this.dependencyDisplayNameAccessor = dependencyDisplayNameAccessor;
-        }
-
-        public String getDependencyDisplayName(Triple<DataverseName, String, String> dependency) {
-            return dependencyDisplayNameAccessor.apply(dependency);
-        }
-
-        @Override
-        public String toString() {
-            return this == DATASET ? dataset() : name().toLowerCase();
-        }
-    }
 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/ViewDetails.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/ViewDetails.java
new file mode 100644
index 0000000..5c884d9
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/ViewDetails.java
@@ -0,0 +1,153 @@
+/*
+ * 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.metadata.entities;
+
+import static org.apache.asterix.om.types.AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE;
+
+import java.io.DataOutput;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.asterix.builders.IARecordBuilder;
+import org.apache.asterix.builders.OrderedListBuilder;
+import org.apache.asterix.builders.RecordBuilder;
+import org.apache.asterix.common.config.DatasetConfig;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
+import org.apache.asterix.metadata.IDatasetDetails;
+import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.entitytupletranslators.AbstractTupleTranslator;
+import org.apache.asterix.om.base.AMutableString;
+import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.utils.RecordUtil;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+
+public class ViewDetails implements IDatasetDetails {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String viewBody;
+
+    private final List<List<Triple<DataverseName, String, String>>> dependencies;
+
+    public ViewDetails(String viewBody, List<List<Triple<DataverseName, String, String>>> dependencies) {
+        this.viewBody = Objects.requireNonNull(viewBody);
+        this.dependencies = Objects.requireNonNull(dependencies);
+    }
+
+    public String getViewBody() {
+        return viewBody;
+    }
+
+    public List<List<Triple<DataverseName, String, String>>> getDependencies() {
+        return dependencies;
+    }
+
+    @Override
+    public DatasetConfig.DatasetType getDatasetType() {
+        return DatasetConfig.DatasetType.VIEW;
+    }
+
+    @Override
+    public void writeDatasetDetailsRecordType(DataOutput out) throws HyracksDataException {
+        IARecordBuilder viewRecordBuilder = new RecordBuilder();
+        viewRecordBuilder.reset(RecordUtil.FULLY_OPEN_RECORD_TYPE);
+
+        ArrayBackedValueStorage fieldName = new ArrayBackedValueStorage();
+        ArrayBackedValueStorage fieldValue = new ArrayBackedValueStorage();
+        ArrayBackedValueStorage itemValue = new ArrayBackedValueStorage();
+
+        AMutableString aString = new AMutableString("");
+        ISerializerDeserializer<AString> stringSerde =
+                SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ASTRING);
+
+        // write field 'Definition'
+        fieldName.reset();
+        aString.setValue(MetadataRecordTypes.FIELD_NAME_DEFINITION);
+        stringSerde.serialize(aString, fieldName.getDataOutput());
+        fieldValue.reset();
+        aString.setValue(viewBody);
+        stringSerde.serialize(aString, fieldValue.getDataOutput());
+        viewRecordBuilder.addField(fieldName, fieldValue);
+
+        // write field 'Dependencies'
+        if (!dependencies.isEmpty()) {
+            fieldName.reset();
+            aString.setValue(MetadataRecordTypes.FIELD_NAME_DEPENDENCIES);
+            stringSerde.serialize(aString, fieldName.getDataOutput());
+
+            OrderedListBuilder dependenciesListBuilder = new OrderedListBuilder();
+            OrderedListBuilder dependencyListBuilder = new OrderedListBuilder();
+            OrderedListBuilder dependencyNameListBuilder = new OrderedListBuilder();
+            List<String> dependencySubnames = new ArrayList<>(3);
+
+            dependenciesListBuilder.reset(FULL_OPEN_ORDEREDLIST_TYPE);
+            for (List<Triple<DataverseName, String, String>> dependenciesList : dependencies) {
+                dependencyListBuilder.reset(FULL_OPEN_ORDEREDLIST_TYPE);
+                for (Triple<DataverseName, String, String> dependency : dependenciesList) {
+                    dependencyNameListBuilder.reset(FULL_OPEN_ORDEREDLIST_TYPE);
+                    dependencySubnames.clear();
+                    AbstractTupleTranslator.getDependencySubNames(dependency, dependencySubnames);
+                    for (String subName : dependencySubnames) {
+                        itemValue.reset();
+                        aString.setValue(subName);
+                        stringSerde.serialize(aString, itemValue.getDataOutput());
+                        dependencyNameListBuilder.addItem(itemValue);
+                    }
+                    itemValue.reset();
+                    dependencyNameListBuilder.write(itemValue.getDataOutput(), true);
+                    dependencyListBuilder.addItem(itemValue);
+                }
+                itemValue.reset();
+                dependencyListBuilder.write(itemValue.getDataOutput(), true);
+                dependenciesListBuilder.addItem(itemValue);
+            }
+            fieldValue.reset();
+            dependenciesListBuilder.write(fieldValue.getDataOutput(), true);
+            viewRecordBuilder.addField(fieldName, fieldValue);
+        }
+
+        viewRecordBuilder.write(out, true);
+    }
+
+    public static List<DependencyKind> DEPENDENCIES_SCHEMA =
+            Arrays.asList(DependencyKind.DATASET, DependencyKind.FUNCTION, DependencyKind.TYPE, DependencyKind.SYNONYM);
+
+    public static List<List<Triple<DataverseName, String, String>>> createDependencies(
+            List<Triple<DataverseName, String, String>> datasetDependencies,
+            List<Triple<DataverseName, String, String>> functionDependencies,
+            List<Triple<DataverseName, String, String>> typeDependencies,
+            List<Triple<DataverseName, String, String>> synonymDependencies) {
+        List<List<Triple<DataverseName, String, String>>> depList = new ArrayList<>(DEPENDENCIES_SCHEMA.size());
+        depList.add(datasetDependencies);
+        depList.add(functionDependencies);
+        depList.add(typeDependencies);
+        if (!synonymDependencies.isEmpty()) {
+            depList.add(synonymDependencies);
+        }
+        return depList;
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/AbstractTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/AbstractTupleTranslator.java
index a35246f..c4f1377 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/AbstractTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/AbstractTupleTranslator.java
@@ -22,9 +22,11 @@ package org.apache.asterix.metadata.entitytupletranslators;
 import java.io.ByteArrayInputStream;
 import java.io.DataInput;
 import java.io.DataInputStream;
+import java.util.Collection;
 
 import org.apache.asterix.builders.IARecordBuilder;
 import org.apache.asterix.builders.RecordBuilder;
+import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
 import org.apache.asterix.metadata.api.IMetadataEntityTupleTranslator;
 import org.apache.asterix.metadata.api.IMetadataIndex;
@@ -33,11 +35,13 @@ import org.apache.asterix.om.base.AInt32;
 import org.apache.asterix.om.base.AInt64;
 import org.apache.asterix.om.base.AMutableString;
 import org.apache.asterix.om.base.ANull;
+import org.apache.asterix.om.base.AOrderedList;
 import org.apache.asterix.om.base.ARecord;
 import org.apache.asterix.om.base.AString;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.BuiltinType;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
@@ -113,4 +117,30 @@ public abstract class AbstractTupleTranslator<T> implements IMetadataEntityTuple
 
     protected abstract T createMetadataEntityFromARecord(ARecord aRecord)
             throws HyracksDataException, AlgebricksException;
+
+    public static void getDependencySubNames(Triple<DataverseName, String, String> dependency,
+            Collection<? super String> outSubnames) {
+        outSubnames.add(dependency.first.getCanonicalForm());
+        if (dependency.second != null) {
+            outSubnames.add(dependency.second);
+        }
+        if (dependency.third != null) {
+            outSubnames.add(dependency.third);
+        }
+    }
+
+    public static Triple<DataverseName, String, String> getDependency(AOrderedList dependencySubnames)
+            throws AlgebricksException {
+        String dataverseCanonicalName = ((AString) dependencySubnames.getItem(0)).getStringValue();
+        DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
+        String second = null, third = null;
+        int ln = dependencySubnames.size();
+        if (ln > 1) {
+            second = ((AString) dependencySubnames.getItem(1)).getStringValue();
+            if (ln > 2) {
+                third = ((AString) dependencySubnames.getItem(2)).getStringValue();
+            }
+        }
+        return new Triple<>(dataverseName, second, third);
+    }
 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslator.java
index 19722ef..51753f2 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslator.java
@@ -44,6 +44,7 @@ import org.apache.asterix.metadata.entities.ExternalDatasetDetails;
 import org.apache.asterix.metadata.entities.InternalDatasetDetails;
 import org.apache.asterix.metadata.entities.InternalDatasetDetails.FileStructure;
 import org.apache.asterix.metadata.entities.InternalDatasetDetails.PartitioningStrategy;
+import org.apache.asterix.metadata.entities.ViewDetails;
 import org.apache.asterix.metadata.utils.DatasetUtil;
 import org.apache.asterix.om.base.ABoolean;
 import org.apache.asterix.om.base.ADateTime;
@@ -67,6 +68,7 @@ import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.runtime.compression.CompressionManager;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
 import org.apache.hyracks.dataflow.common.data.accessors.ITupleReference;
@@ -200,7 +202,7 @@ public class DatasetTupleTranslator extends AbstractTupleTranslator<Dataset> {
                 break;
             }
 
-            case EXTERNAL:
+            case EXTERNAL: {
                 ARecord datasetDetailsRecord = (ARecord) datasetRecord
                         .getValueByPos(MetadataRecordTypes.DATASET_ARECORD_EXTERNALDETAILS_FIELD_INDEX);
                 String adapter = ((AString) datasetDetailsRecord
@@ -229,6 +231,41 @@ public class DatasetTupleTranslator extends AbstractTupleTranslator<Dataset> {
                                 .getIntegerValue()];
 
                 datasetDetails = new ExternalDatasetDetails(adapter, properties, timestamp, state);
+                break;
+            }
+            case VIEW: {
+                int datasetDetailsFieldPos =
+                        datasetRecord.getType().getFieldIndex(MetadataRecordTypes.FIELD_NAME_VIEW_DETAILS);
+                ARecord datasetDetailsRecord = (ARecord) datasetRecord.getValueByPos(datasetDetailsFieldPos);
+
+                // Definition
+                int definitionFieldPos =
+                        datasetDetailsRecord.getType().getFieldIndex(MetadataRecordTypes.FIELD_NAME_DEFINITION);
+                String definition = ((AString) datasetDetailsRecord.getValueByPos(definitionFieldPos)).getStringValue();
+
+                // Dependencies
+                List<List<Triple<DataverseName, String, String>>> dependencies = Collections.emptyList();
+                int dependenciesFieldPos =
+                        datasetDetailsRecord.getType().getFieldIndex(MetadataRecordTypes.FIELD_NAME_DEPENDENCIES);
+                if (dependenciesFieldPos >= 0) {
+                    dependencies = new ArrayList<>();
+                    IACursor dependenciesCursor =
+                            ((AOrderedList) datasetDetailsRecord.getValueByPos(dependenciesFieldPos)).getCursor();
+                    while (dependenciesCursor.next()) {
+                        List<Triple<DataverseName, String, String>> dependencyList = new ArrayList<>();
+                        IACursor qualifiedDependencyCursor = ((AOrderedList) dependenciesCursor.get()).getCursor();
+                        while (qualifiedDependencyCursor.next()) {
+                            Triple<DataverseName, String, String> dependency =
+                                    getDependency((AOrderedList) qualifiedDependencyCursor.get());
+                            dependencyList.add(dependency);
+                        }
+                        dependencies.add(dependencyList);
+                    }
+                }
+
+                datasetDetails = new ViewDetails(definition, dependencies);
+                break;
+            }
         }
 
         Map<String, String> hints = getDatasetHints(datasetRecord);
@@ -359,8 +396,19 @@ public class DatasetTupleTranslator extends AbstractTupleTranslator<Dataset> {
                 dataset.getCompactionPolicyProperties(), listBuilder, itemValue);
 
         // write field 8/9
-        fieldValue.reset();
-        writeDatasetDetailsRecordType(recordBuilder, dataset, fieldValue.getDataOutput());
+        switch (dataset.getDatasetType()) {
+            case INTERNAL:
+                fieldValue.reset();
+                dataset.getDatasetDetails().writeDatasetDetailsRecordType(fieldValue.getDataOutput());
+                recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_INTERNALDETAILS_FIELD_INDEX, fieldValue);
+                break;
+            case EXTERNAL:
+                fieldValue.reset();
+                dataset.getDatasetDetails().writeDatasetDetailsRecordType(fieldValue.getDataOutput());
+                recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_EXTERNALDETAILS_FIELD_INDEX, fieldValue);
+                break;
+            // VIEW details are written later by {@code writeOpenFields()}
+        }
 
         // write field 10
         UnorderedListBuilder uListBuilder = new UnorderedListBuilder();
@@ -441,6 +489,19 @@ public class DatasetTupleTranslator extends AbstractTupleTranslator<Dataset> {
         writeMetaPart(dataset);
         writeRebalanceCount(dataset);
         writeBlockLevelStorageCompression(dataset);
+        writeOpenDetails(dataset);
+    }
+
+    private void writeOpenDetails(Dataset dataset) throws HyracksDataException {
+        if (dataset.getDatasetType() == DatasetType.VIEW) {
+            // write ViewDetails field
+            fieldName.reset();
+            aString.setValue(MetadataRecordTypes.FIELD_NAME_VIEW_DETAILS);
+            stringSerde.serialize(aString, fieldName.getDataOutput());
+            fieldValue.reset();
+            dataset.getDatasetDetails().writeDatasetDetailsRecordType(fieldValue.getDataOutput());
+            recordBuilder.addField(fieldName, fieldValue);
+        }
     }
 
     private void writeMetaPart(Dataset dataset) throws HyracksDataException {
@@ -500,20 +561,6 @@ public class DatasetTupleTranslator extends AbstractTupleTranslator<Dataset> {
         }
     }
 
-    protected void writeDatasetDetailsRecordType(IARecordBuilder recordBuilder, Dataset dataset, DataOutput dataOutput)
-            throws HyracksDataException {
-        dataset.getDatasetDetails().writeDatasetDetailsRecordType(dataOutput);
-        switch (dataset.getDatasetType()) {
-            case INTERNAL:
-                recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_INTERNALDETAILS_FIELD_INDEX, fieldValue);
-                break;
-            case EXTERNAL:
-                recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_EXTERNALDETAILS_FIELD_INDEX, fieldValue);
-                break;
-        }
-
-    }
-
     protected Map<String, String> getDatasetHints(ARecord datasetRecord) {
         Map<String, String> hints = new HashMap<>();
         String key;
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
index ccae8a4..ef9c143 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
@@ -244,21 +244,6 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         return new TypeSignature(typeDataverseName, typeName);
     }
 
-    private Triple<DataverseName, String, String> getDependency(AOrderedList dependencySubnames)
-            throws AlgebricksException {
-        String dataverseCanonicalName = ((AString) dependencySubnames.getItem(0)).getStringValue();
-        DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String second = null, third = null;
-        int ln = dependencySubnames.size();
-        if (ln > 1) {
-            second = ((AString) dependencySubnames.getItem(1)).getStringValue();
-            if (ln > 2) {
-                third = ((AString) dependencySubnames.getItem(2)).getStringValue();
-            }
-        }
-        return new Triple<>(dataverseName, second, third);
-    }
-
     private Map<String, String> getResources(ARecord functionRecord, String resourcesFieldName) {
         Map<String, String> adaptorConfiguration = null;
         final ARecordType functionType = functionRecord.getType();
@@ -381,11 +366,14 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         dependenciesListBuilder.reset((AOrderedListType) MetadataRecordTypes.FUNCTION_RECORDTYPE
                 .getFieldTypes()[MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEPENDENCIES_FIELD_INDEX]);
         List<List<Triple<DataverseName, String, String>>> dependenciesList = function.getDependencies();
+        List<String> subNames = new ArrayList<>();
         for (List<Triple<DataverseName, String, String>> dependencies : dependenciesList) {
             dependencyListBuilder.reset(listOfLists);
             for (Triple<DataverseName, String, String> dependency : dependencies) {
                 dependencyNameListBuilder.reset(stringList);
-                for (String subName : getDependencySubNames(dependency)) {
+                subNames.clear();
+                getDependencySubNames(dependency, subNames);
+                for (String subName : subNames) {
                     itemValue.reset();
                     aString.setValue(subName);
                     stringSerde.serialize(aString, itemValue.getDataOutput());
@@ -611,18 +599,6 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         propertyRecordBuilder.write(out, true);
     }
 
-    private List<String> getDependencySubNames(Triple<DataverseName, String, String> dependency) {
-        dependencySubnames.clear();
-        dependencySubnames.add(dependency.first.getCanonicalForm());
-        if (dependency.second != null) {
-            dependencySubnames.add(dependency.second);
-        }
-        if (dependency.third != null) {
-            dependencySubnames.add(dependency.third);
-        }
-        return dependencySubnames;
-    }
-
     // back-compat
     private static List<String> decodeExternalIdentifierBackCompat(String encodedValue,
             ExternalFunctionLanguage language) throws AlgebricksException {
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
index 158efb2..143dc4c 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
@@ -39,6 +39,7 @@ import org.apache.asterix.common.context.TransactionSubsystemProvider;
 import org.apache.asterix.common.dataflow.ICcApplicationContext;
 import org.apache.asterix.common.exceptions.ACIDException;
 import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.common.transactions.IRecoveryManager;
 import org.apache.asterix.external.indexing.IndexingConstants;
@@ -369,8 +370,7 @@ public class DatasetUtil {
         DataverseName dataverseName = dataverse.getDataverseName();
         Dataset dataset = metadataProvider.findDataset(dataverseName, datasetName);
         if (dataset == null) {
-            throw new AsterixException(
-                    "Could not find " + dataset() + " " + datasetName + " in " + dataverse() + " " + dataverseName);
+            throw new AsterixException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, datasetName, dataverseName);
         }
         JobSpecification spec = RuntimeUtils.createJobSpecification(metadataProvider.getApplicationContext());
         Pair<IFileSplitProvider, AlgebricksPartitionConstraint> splitsAndConstraint =
@@ -621,4 +621,11 @@ public class DatasetUtil {
         return nodeGroup;
     }
 
+    public static String getDatasetTypeDisplayName(DatasetType datasetType) {
+        return datasetType == DatasetType.VIEW ? "view" : dataset();
+    }
+
+    public static boolean isNotView(Dataset dataset) {
+        return dataset.getDatasetType() != DatasetType.VIEW;
+    }
 }