[NO ISSUE][API][MTD] Refactor query service servlet

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
Refactor query service servlet in addition to some code
clean-ups.

Change-Id: Idbc81219cbe2f337b3c4aaf4a242ef2ebeb165c5
Reviewed-on: https://asterix-gerrit.ics.uci.edu/3038
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java
index e34775f..45a5ae1 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java
@@ -128,8 +128,8 @@
     public static final String FORMAT_QUOTE_RECORD = "quote-record";
 
     // Output format.
-    private final OutputFormat fmt;
-    private final PlanFormat planFormat;
+    private OutputFormat fmt;
+    private PlanFormat planFormat;
 
     // Standard execution flags.
     private final boolean executeQuery;
@@ -160,8 +160,6 @@
      *            Whether to execute the query or not.
      * @param generateJobSpec
      *            Whether to generate the Hyracks job specification (if
-     * @param lpfmt
-     *            Plan format for logical plan.
      */
     public SessionConfig(OutputFormat fmt, boolean optimize, boolean executeQuery, boolean generateJobSpec) {
         this(fmt, optimize, executeQuery, generateJobSpec, PlanFormat.STRING);
@@ -184,6 +182,10 @@
         return this.fmt;
     }
 
+    public void setFmt(OutputFormat fmt) {
+        this.fmt = fmt;
+    }
+
     /**
      * Retrieve the PlanFormat for this execution.
      */
@@ -191,6 +193,10 @@
         return this.planFormat;
     }
 
+    public void setPlanFormat(PlanFormat planFormat) {
+        this.planFormat = planFormat;
+    }
+
     /**
      * Retrieve the value of the "execute query" flag.
      */
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionOutput.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionOutput.java
index f7031a4..97125f0 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionOutput.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionOutput.java
@@ -35,7 +35,7 @@
 
     private final SessionOutput.ResultDecorator preResultDecorator;
     private final SessionOutput.ResultDecorator postResultDecorator;
-    private final SessionOutput.ResultAppender handleAppender;
+    private SessionOutput.ResultAppender handleAppender;
     private final SessionOutput.ResultAppender statusAppender;
 
     public SessionOutput(SessionConfig config, PrintWriter out) {
@@ -59,6 +59,10 @@
         return this.bufferedOut != null ? this.bufferedOut : this.out;
     }
 
+    public void setHandleAppender(SessionOutput.ResultAppender handleAppender) {
+        this.handleAppender = handleAppender;
+    }
+
     /**
      * buffer the data provided to the PrintWriter returned by out() to be able to set the status of the response
      * message when it can be determined. This is a no-op, if data is already buffered.
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
index 765ba9c..b33bba5 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
@@ -115,19 +115,7 @@
 
     @Override
     protected void post(IServletRequest request, IServletResponse response) {
-        try {
-            handleRequest(request, response);
-        } catch (IOException e) {
-            // Servlet methods should not throw exceptions
-            // http://cwe.mitre.org/data/definitions/600.html
-            GlobalConfig.ASTERIX_LOGGER.log(Level.ERROR, e.getMessage(), e);
-        } catch (Throwable th) {// NOSONAR: Logging and re-throwing
-            try {
-                GlobalConfig.ASTERIX_LOGGER.log(Level.ERROR, th.getMessage(), th);
-            } catch (Throwable ignored) { // NOSONAR: Logging failure
-            }
-            throw th;
-        }
+        handleRequest(request, response);
     }
 
     @Override
@@ -209,7 +197,7 @@
         private ResultStatus resultStatus = ResultStatus.SUCCESS;
         private HttpResponseStatus httpResponseStatus = HttpResponseStatus.OK;
 
-        void setStatus(ResultStatus resultStatus, HttpResponseStatus httpResponseStatus) {
+        public void setStatus(ResultStatus resultStatus, HttpResponseStatus httpResponseStatus) {
             this.resultStatus = resultStatus;
             this.httpResponseStatus = httpResponseStatus;
         }
@@ -281,29 +269,12 @@
         return SessionConfig.OutputFormat.CLEAN_JSON;
     }
 
-    private static SessionOutput createSessionOutput(QueryServiceRequestParameters param, String handleUrl,
-            PrintWriter resultWriter) {
+    private static SessionOutput createSessionOutput(PrintWriter resultWriter) {
         SessionOutput.ResultDecorator resultPrefix = ResultUtil.createPreResultDecorator();
         SessionOutput.ResultDecorator resultPostfix = ResultUtil.createPostResultDecorator();
-        SessionOutput.ResultAppender appendHandle = ResultUtil.createResultHandleAppender(handleUrl);
         SessionOutput.ResultAppender appendStatus = ResultUtil.createResultStatusAppender();
-
-        SessionConfig.OutputFormat format = getFormat(param.getFormat());
-        final SessionConfig.PlanFormat planFormat = SessionConfig.PlanFormat.get(param.getPlanFormat(),
-                param.getPlanFormat(), SessionConfig.PlanFormat.JSON, LOGGER);
-        SessionConfig sessionConfig = new SessionConfig(format, planFormat);
-        sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, true);
-        sessionConfig.set(SessionConfig.OOB_EXPR_TREE, param.isExpressionTree());
-        sessionConfig.set(SessionConfig.OOB_REWRITTEN_EXPR_TREE, param.isRewrittenExpressionTree());
-        sessionConfig.set(SessionConfig.OOB_LOGICAL_PLAN, param.isLogicalPlan());
-        sessionConfig.set(SessionConfig.OOB_OPTIMIZED_LOGICAL_PLAN, param.isOptimizedLogicalPlan());
-        sessionConfig.set(SessionConfig.OOB_HYRACKS_JOB, param.isJob());
-        sessionConfig.set(SessionConfig.FORMAT_INDENT_JSON, param.isPretty());
-        sessionConfig.set(SessionConfig.FORMAT_QUOTE_RECORD,
-                format != SessionConfig.OutputFormat.CLEAN_JSON && format != SessionConfig.OutputFormat.LOSSLESS_JSON);
-        sessionConfig.set(SessionConfig.FORMAT_CSV_HEADER, format == SessionConfig.OutputFormat.CSV
-                && "present".equals(getParameterValue(param.getFormat(), Attribute.HEADER.str())));
-        return new SessionOutput(sessionConfig, resultWriter, resultPrefix, resultPostfix, appendHandle, appendStatus);
+        SessionConfig sessionConfig = new SessionConfig(SessionConfig.OutputFormat.CLEAN_JSON);
+        return new SessionOutput(sessionConfig, resultWriter, resultPrefix, resultPostfix, null, appendStatus);
     }
 
     private static void printClientContextID(PrintWriter pw, QueryServiceRequestParameters params) {
@@ -411,62 +382,67 @@
         return result;
     }
 
-    private QueryServiceRequestParameters getRequestParameters(IServletRequest request) throws IOException {
-        final String contentType = HttpUtil.getContentTypeOnly(request);
-        QueryServiceRequestParameters param = new QueryServiceRequestParameters();
+    protected void setRequestParam(IServletRequest request, QueryServiceRequestParameters param)
+            throws IOException, AlgebricksException {
         param.setHost(host(request));
         param.setPath(servletPath(request));
+        String contentType = HttpUtil.getContentTypeOnly(request);
         if (HttpUtil.ContentType.APPLICATION_JSON.equals(contentType)) {
             try {
-                JsonNode jsonRequest = OBJECT_MAPPER.readTree(HttpUtil.getRequestBody(request));
-                final String statementParam = Parameter.STATEMENT.str();
-                if (jsonRequest.has(statementParam)) {
-                    param.setStatement(jsonRequest.get(statementParam).asText());
-                }
-                param.setFormat(toLower(getOptText(jsonRequest, Parameter.FORMAT.str())));
-                param.setPretty(getOptBoolean(jsonRequest, Parameter.PRETTY.str(), false));
-                param.setMode(toLower(getOptText(jsonRequest, Parameter.MODE.str())));
-                param.setClientContextID(getOptText(jsonRequest, Parameter.CLIENT_ID.str()));
-                param.setTimeout(getOptText(jsonRequest, Parameter.TIMEOUT.str()));
-                param.setMaxResultReads(getOptText(jsonRequest, Parameter.MAX_RESULT_READS.str()));
-                param.setPlanFormat(getOptText(jsonRequest, Parameter.PLAN_FORMAT.str()));
-                param.setExpressionTree(getOptBoolean(jsonRequest, Parameter.EXPRESSION_TREE.str(), false));
-                param.setRewrittenExpressionTree(
-                        getOptBoolean(jsonRequest, Parameter.REWRITTEN_EXPRESSION_TREE.str(), false));
-                param.setLogicalPlan(getOptBoolean(jsonRequest, Parameter.LOGICAL_PLAN.str(), false));
-                param.setOptimizedLogicalPlan(
-                        getOptBoolean(jsonRequest, Parameter.OPTIMIZED_LOGICAL_PLAN.str(), false));
-                param.setJob(getOptBoolean(jsonRequest, Parameter.JOB.str(), false));
-                param.setSignature(getOptBoolean(jsonRequest, Parameter.SIGNATURE.str(), true));
-                param.setStatementParams(
-                        getOptStatementParameters(jsonRequest, jsonRequest.fieldNames(), JsonNode::get, v -> v));
-                param.setMultiStatement(getOptBoolean(jsonRequest, Parameter.MULTI_STATEMENT.str(), true));
+                setParamFromJSON(request, param);
             } catch (JsonParseException | JsonMappingException e) {
                 // if the JSON parsing fails, the statement is empty and we get an empty statement error
                 GlobalConfig.ASTERIX_LOGGER.log(Level.ERROR, e.getMessage(), e);
             }
         } else {
-            param.setStatement(request.getParameter(Parameter.STATEMENT.str()));
-            if (param.getStatement() == null) {
-                param.setStatement(HttpUtil.getRequestBody(request));
-            }
-            param.setFormat(toLower(request.getParameter(Parameter.FORMAT.str())));
-            param.setPretty(Boolean.parseBoolean(request.getParameter(Parameter.PRETTY.str())));
-            param.setMode(toLower(request.getParameter(Parameter.MODE.str())));
-            param.setClientContextID(request.getParameter(Parameter.CLIENT_ID.str()));
-            param.setTimeout(request.getParameter(Parameter.TIMEOUT.str()));
-            param.setMaxResultReads(request.getParameter(Parameter.MAX_RESULT_READS.str()));
-            param.setPlanFormat(request.getParameter(Parameter.PLAN_FORMAT.str()));
-            final String multiStatementParam = request.getParameter(Parameter.MULTI_STATEMENT.str());
-            param.setMultiStatement(multiStatementParam == null || Boolean.parseBoolean(multiStatementParam));
-            try {
-                param.setStatementParams(getOptStatementParameters(request, request.getParameterNames().iterator(),
-                        IServletRequest::getParameter, OBJECT_MAPPER::readTree));
-            } catch (JsonParseException | JsonMappingException e) {
-                GlobalConfig.ASTERIX_LOGGER.log(Level.ERROR, e.getMessage(), e);
-            }
+            setParamFromRequest(request, param);
         }
-        return param;
+    }
+
+    private void setParamFromJSON(IServletRequest request, QueryServiceRequestParameters param) throws IOException {
+        JsonNode jsonRequest = OBJECT_MAPPER.readTree(HttpUtil.getRequestBody(request));
+        param.setFormat(toLower(getOptText(jsonRequest, Parameter.FORMAT.str())));
+        param.setPretty(getOptBoolean(jsonRequest, Parameter.PRETTY.str(), false));
+        param.setMode(toLower(getOptText(jsonRequest, Parameter.MODE.str())));
+        param.setClientContextID(getOptText(jsonRequest, Parameter.CLIENT_ID.str()));
+        param.setTimeout(getOptText(jsonRequest, Parameter.TIMEOUT.str()));
+        param.setMaxResultReads(getOptText(jsonRequest, Parameter.MAX_RESULT_READS.str()));
+        param.setPlanFormat(getOptText(jsonRequest, Parameter.PLAN_FORMAT.str()));
+        param.setExpressionTree(getOptBoolean(jsonRequest, Parameter.EXPRESSION_TREE.str(), false));
+        param.setRewrittenExpressionTree(getOptBoolean(jsonRequest, Parameter.REWRITTEN_EXPRESSION_TREE.str(), false));
+        param.setLogicalPlan(getOptBoolean(jsonRequest, Parameter.LOGICAL_PLAN.str(), false));
+        param.setOptimizedLogicalPlan(getOptBoolean(jsonRequest, Parameter.OPTIMIZED_LOGICAL_PLAN.str(), false));
+        param.setJob(getOptBoolean(jsonRequest, Parameter.JOB.str(), false));
+        param.setSignature(getOptBoolean(jsonRequest, Parameter.SIGNATURE.str(), true));
+        param.setStatementParams(
+                getOptStatementParameters(jsonRequest, jsonRequest.fieldNames(), JsonNode::get, v -> v));
+        param.setMultiStatement(getOptBoolean(jsonRequest, Parameter.MULTI_STATEMENT.str(), true));
+        String statementParam = Parameter.STATEMENT.str();
+        if (jsonRequest.has(statementParam)) {
+            param.setStatement(jsonRequest.get(statementParam).asText());
+        }
+    }
+
+    private void setParamFromRequest(IServletRequest request, QueryServiceRequestParameters param) throws IOException {
+        param.setStatement(request.getParameter(Parameter.STATEMENT.str()));
+        if (param.getStatement() == null) {
+            param.setStatement(HttpUtil.getRequestBody(request));
+        }
+        param.setFormat(toLower(request.getParameter(Parameter.FORMAT.str())));
+        param.setPretty(Boolean.parseBoolean(request.getParameter(Parameter.PRETTY.str())));
+        param.setMode(toLower(request.getParameter(Parameter.MODE.str())));
+        param.setClientContextID(request.getParameter(Parameter.CLIENT_ID.str()));
+        param.setTimeout(request.getParameter(Parameter.TIMEOUT.str()));
+        param.setMaxResultReads(request.getParameter(Parameter.MAX_RESULT_READS.str()));
+        param.setPlanFormat(request.getParameter(Parameter.PLAN_FORMAT.str()));
+        final String multiStatementParam = request.getParameter(Parameter.MULTI_STATEMENT.str());
+        param.setMultiStatement(multiStatementParam == null || Boolean.parseBoolean(multiStatementParam));
+        try {
+            param.setStatementParams(getOptStatementParameters(request, request.getParameterNames().iterator(),
+                    IServletRequest::getParameter, OBJECT_MAPPER::readTree));
+        } catch (JsonParseException | JsonMappingException e) {
+            GlobalConfig.ASTERIX_LOGGER.log(Level.ERROR, e.getMessage(), e);
+        }
     }
 
     private static ResultDelivery parseResultDelivery(String mode) {
@@ -508,35 +484,31 @@
         return "http://" + host + path + handlePath(delivery);
     }
 
-    private void handleRequest(IServletRequest request, IServletResponse response) throws IOException {
-        QueryServiceRequestParameters param = getRequestParameters(request);
-        LOGGER.info("handleRequest: {}", param);
+    private void handleRequest(IServletRequest request, IServletResponse response) {
         long elapsedStart = System.nanoTime();
-        final PrintWriter httpWriter = response.writer();
-
-        ResultDelivery delivery = parseResultDelivery(param.getMode());
-
-        final ResultProperties resultProperties = param.getMaxResultReads() == null ? new ResultProperties(delivery)
-                : new ResultProperties(delivery, Long.parseLong(param.getMaxResultReads()));
-
-        String handleUrl = getHandleUrl(param.getHost(), param.getPath(), delivery);
-        SessionOutput sessionOutput = createSessionOutput(param, handleUrl, httpWriter);
-        SessionConfig sessionConfig = sessionOutput.config();
-        HttpUtil.setContentType(response, HttpUtil.ContentType.APPLICATION_JSON, HttpUtil.Encoding.UTF8);
-
+        long errorCount = 1;
         Stats stats = new Stats();
         RequestExecutionState execution = new RequestExecutionState();
-
-        // buffer the output until we are ready to set the status of the response message correctly
-        sessionOutput.hold();
-        sessionOutput.out().print("{\n");
-        printRequestId(sessionOutput.out());
-        printClientContextID(sessionOutput.out(), param);
-        printSignature(sessionOutput.out(), param);
-        printType(sessionOutput.out(), sessionConfig);
-        long errorCount = 1; // so far we just return 1 error
-        List<ExecutionWarning> warnings = Collections.emptyList(); // we don't have any warnings yet
+        List<ExecutionWarning> warnings = Collections.emptyList();
+        PrintWriter httpWriter = response.writer();
+        SessionOutput sessionOutput = createSessionOutput(httpWriter);
+        QueryServiceRequestParameters param = new QueryServiceRequestParameters();
         try {
+            // buffer the output until we are ready to set the status of the response message correctly
+            sessionOutput.hold();
+            sessionOutput.out().print("{\n");
+            HttpUtil.setContentType(response, HttpUtil.ContentType.APPLICATION_JSON, HttpUtil.Encoding.UTF8);
+            setRequestParam(request, param);
+            LOGGER.info("handleRequest: {}", param);
+            ResultDelivery delivery = parseResultDelivery(param.getMode());
+            setSessionConfig(sessionOutput, param, delivery);
+            ResultProperties resultProperties = param.getMaxResultReads() == null ? new ResultProperties(delivery)
+                    : new ResultProperties(delivery, Long.parseLong(param.getMaxResultReads()));
+            printAdditionalResultFields(sessionOutput.out());
+            printRequestId(sessionOutput.out());
+            printClientContextID(sessionOutput.out(), param);
+            printSignature(sessionOutput.out(), param);
+            printType(sessionOutput.out(), sessionOutput.config());
             if (param.getStatement() == null || param.getStatement().isEmpty()) {
                 throw new RuntimeDataException(ErrorCode.NO_STATEMENT_PROVIDED);
             }
@@ -643,11 +615,38 @@
         }
     }
 
+    private void setSessionConfig(SessionOutput sessionOutput, QueryServiceRequestParameters param,
+            ResultDelivery delivery) {
+        String handleUrl = getHandleUrl(param.getHost(), param.getPath(), delivery);
+        sessionOutput.setHandleAppender(ResultUtil.createResultHandleAppender(handleUrl));
+        SessionConfig sessionConfig = sessionOutput.config();
+        SessionConfig.OutputFormat format = getFormat(param.getFormat());
+        SessionConfig.PlanFormat planFormat = SessionConfig.PlanFormat.get(param.getPlanFormat(), param.getPlanFormat(),
+                SessionConfig.PlanFormat.JSON, LOGGER);
+        sessionConfig.setFmt(format);
+        sessionConfig.setPlanFormat(planFormat);
+        sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, true);
+        sessionConfig.set(SessionConfig.OOB_EXPR_TREE, param.isExpressionTree());
+        sessionConfig.set(SessionConfig.OOB_REWRITTEN_EXPR_TREE, param.isRewrittenExpressionTree());
+        sessionConfig.set(SessionConfig.OOB_LOGICAL_PLAN, param.isLogicalPlan());
+        sessionConfig.set(SessionConfig.OOB_OPTIMIZED_LOGICAL_PLAN, param.isOptimizedLogicalPlan());
+        sessionConfig.set(SessionConfig.OOB_HYRACKS_JOB, param.isJob());
+        sessionConfig.set(SessionConfig.FORMAT_INDENT_JSON, param.isPretty());
+        sessionConfig.set(SessionConfig.FORMAT_QUOTE_RECORD,
+                format != SessionConfig.OutputFormat.CLEAN_JSON && format != SessionConfig.OutputFormat.LOSSLESS_JSON);
+        sessionConfig.set(SessionConfig.FORMAT_CSV_HEADER, format == SessionConfig.OutputFormat.CSV
+                && "present".equals(getParameterValue(param.getFormat(), Attribute.HEADER.str())));
+    }
+
     protected void printError(PrintWriter sessionOut, Throwable throwable) {
         ResultUtil.printError(sessionOut, throwable);
     }
 
-    protected void printWarnings(PrintWriter pw, List<ExecutionWarning> warnings) {
+    protected void printAdditionalResultFields(PrintWriter sessionOut) {
+        // do nothing
+    }
+
+    private void printWarnings(PrintWriter pw, List<ExecutionWarning> warnings) {
         ResultUtil.printWarnings(pw, warnings);
     }
 
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index 9f4f248..bd7510f 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -64,6 +64,7 @@
 import org.apache.asterix.common.api.Duration;
 import org.apache.asterix.common.config.GlobalConfig;
 import org.apache.asterix.common.utils.Servlets;
+import org.apache.asterix.lang.sqlpp.util.SqlppStatementUtil;
 import org.apache.asterix.runtime.evaluators.common.NumberUtils;
 import org.apache.asterix.test.server.ITestServer;
 import org.apache.asterix.test.server.TestServerProvider;
@@ -1785,7 +1786,7 @@
                 if (json != null) {
                     String dvName = json.get("DataverseName").asText();
                     if (!dvName.equals("Metadata") && !dvName.equals("Default")) {
-                        toBeDropped.add(dvName);
+                        toBeDropped.add(SqlppStatementUtil.enclose(dvName));
                     }
                 }
             }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppStatementUtil.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppStatementUtil.java
new file mode 100644
index 0000000..f1278ec
--- /dev/null
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppStatementUtil.java
@@ -0,0 +1,142 @@
+/*
+ * 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.util;
+
+public class SqlppStatementUtil {
+
+    private static final String IF_EXISTS = " IF EXISTS ";
+    private static final String IF_NOT_EXISTS = " IF NOT EXISTS ";
+    private static final String CREATE_DATAVERSE = "CREATE DATAVERSE ";
+    public static final String CREATE_DATASET = "CREATE DATASET ";
+    private static final String DROP_DATASET = "DROP DATASET ";
+    private static final String CREATE_INDEX = "CREATE INDEX ";
+    private static final String CREATE_PRIMARY_INDEX = "CREATE PRIMARY INDEX ";
+    private static final String DROP_INDEX = "DROP INDEX ";
+    public static final String ON = " ON ";
+    public static final String WHERE = " WHERE ";
+    public static final char SEMI_COLON = ';';
+    public static final char DOT = '.';
+    public static final char COLON = ':';
+    public static final char COMMA = ',';
+    public static final char L_PARENTHESIS = '(';
+    public static final char R_PARENTHESIS = ')';
+    public static final char L_BRACE = '{';
+    public static final char R_BRACE = '}';
+    private static final char QUOTE = '\"';
+    private static final char BACK_TICK = '`';
+
+    private SqlppStatementUtil() {
+    }
+
+    public static StringBuilder getCreateDataverseStatement(StringBuilder stringBuilder, String dataverseName,
+            boolean ifNotExists, int version) {
+        stringBuilder.append(CREATE_DATAVERSE);
+        enclose(stringBuilder, dataverseName);
+        return ifNotExists(stringBuilder, ifNotExists).append(SEMI_COLON);
+    }
+
+    public static StringBuilder getDropDatasetStatement(StringBuilder stringBuilder, String dataverseName,
+            String datasetName, boolean ifExists, int version) {
+        stringBuilder.append(DROP_DATASET);
+        enclose(stringBuilder, dataverseName, datasetName);
+        return ifExists(stringBuilder, ifExists).append(SEMI_COLON);
+    }
+
+    public static StringBuilder getCreateIndexStatement(StringBuilder stringBuilder, String dataverseName,
+            String datasetName, String indexName, String fields, int version) {
+        stringBuilder.append(CREATE_INDEX);
+        enclose(stringBuilder, indexName).append(ON);
+        return enclose(stringBuilder, dataverseName, datasetName).append(fields).append(SEMI_COLON);
+    }
+
+    public static StringBuilder getCreatePrimaryIndexStatement(StringBuilder stringBuilder, String dataverseName,
+            String datasetName, String indexName, int version) {
+        stringBuilder.append(CREATE_PRIMARY_INDEX);
+        enclose(stringBuilder, indexName).append(ON);
+        return enclose(stringBuilder, dataverseName, datasetName).append(SEMI_COLON);
+    }
+
+    public static StringBuilder getDropIndexStatement(StringBuilder stringBuilder, String dataverseName,
+            String datasetName, String indexName, boolean ifExists, int version) {
+        stringBuilder.append(DROP_INDEX);
+        enclose(stringBuilder, dataverseName, datasetName, indexName);
+        return ifExists(stringBuilder, ifExists).append(SEMI_COLON);
+    }
+
+    private static StringBuilder ifExists(StringBuilder stringBuilder, boolean ifExists) {
+        return ifExists ? stringBuilder.append(IF_EXISTS) : stringBuilder;
+    }
+
+    private static StringBuilder ifNotExists(StringBuilder stringBuilder, boolean ifNotExists) {
+        return ifNotExists ? stringBuilder.append(IF_NOT_EXISTS) : stringBuilder;
+    }
+
+    /**
+     * Encloses the {@param identifier} in back-ticks.
+     * @param stringBuilder where the identifier will be appended
+     * @param identifier an identifier which could be a valid identifier or one that needs to be delimited
+     * @return {@param stringBuilder} with the <i>delimited</i> identifier appended
+     */
+    public static StringBuilder enclose(StringBuilder stringBuilder, String identifier) {
+        return stringBuilder.append(BACK_TICK).append(identifier).append(BACK_TICK);
+    }
+
+    /**
+     * Same as {@link SqlppStatementUtil#enclose(StringBuilder, String)} but for a qualified identifier.
+     * @param stringBuilder where the identifier will be appended
+     * @param identifier1 the qualifying identifier
+     * @param identifier2 the qualified identifier
+     * @return {@param stringBuilder} with the <i>delimited</i> qualified identifier appended
+     */
+    public static StringBuilder enclose(StringBuilder stringBuilder, String identifier1, String identifier2) {
+        return stringBuilder.append(BACK_TICK).append(identifier1).append(BACK_TICK).append(DOT).append(BACK_TICK)
+                .append(identifier2).append(BACK_TICK);
+    }
+
+    /**
+     * Same as {@link SqlppStatementUtil#enclose(StringBuilder, String)} but for a double qualified identifier.
+     * @param stringBuilder where the identifier will be appended
+     * @param identifier1 the 1st qualifying identifier
+     * @param identifier2 the 2nd qualifying identifier
+     * @param identifier3 the qualified identifier
+     * @return {@param stringBuilder} with the <i>delimited</i> qualified identifier appended
+     */
+    public static StringBuilder enclose(StringBuilder stringBuilder, String identifier1, String identifier2,
+            String identifier3) {
+        return stringBuilder.append(BACK_TICK).append(identifier1).append(BACK_TICK).append(DOT).append(BACK_TICK)
+                .append(identifier2).append(BACK_TICK).append(DOT).append(BACK_TICK).append(identifier3)
+                .append(BACK_TICK);
+    }
+
+    public static String enclose(String identifier) {
+        return BACK_TICK + identifier + BACK_TICK;
+    }
+
+    public static String enclose(String identifier1, String identifier2) {
+        return BACK_TICK + identifier1 + BACK_TICK + DOT + BACK_TICK + identifier2 + BACK_TICK;
+    }
+
+    public static StringBuilder quote(StringBuilder stringBuilder, String text) {
+        return stringBuilder.append(QUOTE).append(text).append(QUOTE);
+    }
+
+    public static String quote(String text) {
+        return QUOTE + text + QUOTE;
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
index d2a4b1c..5377c9d 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
@@ -34,33 +34,33 @@
     public static final MetadataIndexImmutableProperties PROPERTIES_METADATA =
             new MetadataIndexImmutableProperties(MetadataConstants.METADATA_DATAVERSE_NAME, 0, 0);
     public static final MetadataIndexImmutableProperties PROPERTIES_DATAVERSE =
-            new MetadataIndexImmutableProperties("Dataverse", 1, 1);
+            new MetadataIndexImmutableProperties(MetadataConstants.DATAVERSE_DATASET_NAME, 1, 1);
     public static final MetadataIndexImmutableProperties PROPERTIES_DATASET =
-            new MetadataIndexImmutableProperties("Dataset", 2, 2);
+            new MetadataIndexImmutableProperties(MetadataConstants.DATASET_DATASET_NAME, 2, 2);
     public static final MetadataIndexImmutableProperties PROPERTIES_DATATYPE =
-            new MetadataIndexImmutableProperties("Datatype", 3, 3);
+            new MetadataIndexImmutableProperties(MetadataConstants.DATATYPE_DATASET_NAME, 3, 3);
     public static final MetadataIndexImmutableProperties PROPERTIES_INDEX =
-            new MetadataIndexImmutableProperties("Index", 4, 4);
+            new MetadataIndexImmutableProperties(MetadataConstants.INDEX_DATASET_NAME, 4, 4);
     public static final MetadataIndexImmutableProperties PROPERTIES_NODE =
-            new MetadataIndexImmutableProperties("Node", 5, 5);
+            new MetadataIndexImmutableProperties(MetadataConstants.NODE_DATASET_NAME, 5, 5);
     public static final MetadataIndexImmutableProperties PROPERTIES_NODEGROUP =
-            new MetadataIndexImmutableProperties("Nodegroup", 6, 6);
+            new MetadataIndexImmutableProperties(MetadataConstants.NODEGROUP_DATASET_NAME, 6, 6);
     public static final MetadataIndexImmutableProperties PROPERTIES_FUNCTION =
-            new MetadataIndexImmutableProperties("Function", 7, 7);
+            new MetadataIndexImmutableProperties(MetadataConstants.FUNCTION_DATASET_NAME, 7, 7);
     public static final MetadataIndexImmutableProperties PROPERTIES_DATASOURCE_ADAPTER =
-            new MetadataIndexImmutableProperties("DatasourceAdapter", 8, 8);
+            new MetadataIndexImmutableProperties(MetadataConstants.DATASOURCE_ADAPTER_DATASET_NAME, 8, 8);
     public static final MetadataIndexImmutableProperties PROPERTIES_LIBRARY =
-            new MetadataIndexImmutableProperties("Library", 9, 9);
+            new MetadataIndexImmutableProperties(MetadataConstants.LIBRARY_DATASET_NAME, 9, 9);
     public static final MetadataIndexImmutableProperties PROPERTIES_FEED =
-            new MetadataIndexImmutableProperties("Feed", 10, 10);
+            new MetadataIndexImmutableProperties(MetadataConstants.FEED_DATASET_NAME, 10, 10);
     public static final MetadataIndexImmutableProperties PROPERTIES_FEED_CONNECTION =
-            new MetadataIndexImmutableProperties("FeedConnection", 11, 11);
+            new MetadataIndexImmutableProperties(MetadataConstants.FEED_CONNECTION_DATASET_NAME, 11, 11);
     public static final MetadataIndexImmutableProperties PROPERTIES_FEED_POLICY =
-            new MetadataIndexImmutableProperties("FeedPolicy", 12, 12);
+            new MetadataIndexImmutableProperties(MetadataConstants.FEED_POLICY_DATASET_NAME, 12, 12);
     public static final MetadataIndexImmutableProperties PROPERTIES_COMPACTION_POLICY =
-            new MetadataIndexImmutableProperties("CompactionPolicy", 13, 13);
+            new MetadataIndexImmutableProperties(MetadataConstants.COMPACTION_POLICY_DATASET_NAME, 13, 13);
     public static final MetadataIndexImmutableProperties PROPERTIES_EXTERNAL_FILE =
-            new MetadataIndexImmutableProperties("ExternalFile", 14, 14);
+            new MetadataIndexImmutableProperties(MetadataConstants.EXTERNAL_FILE_DATASET_NAME, 14, 14);
 
     public static final IMetadataIndex DATAVERSE_DATASET =
             new MetadataIndex(PROPERTIES_DATAVERSE, 2, new IAType[] { BuiltinType.ASTRING },
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
index 6769770..8446154 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
@@ -26,10 +26,24 @@
 
     // Name of the dataverse the metadata lives in.
     public static final String METADATA_DATAVERSE_NAME = "Metadata";
-
     // Name of the node group where metadata is stored on.
     public static final String METADATA_NODEGROUP_NAME = "MetadataGroup";
 
+    public static final String DATAVERSE_DATASET_NAME = "Dataverse";
+    public static final String DATASET_DATASET_NAME = "Dataset";
+    public static final String INDEX_DATASET_NAME = "Index";
+    public static final String DATATYPE_DATASET_NAME = "Datatype";
+    public static final String NODE_DATASET_NAME = "Node";
+    public static final String NODEGROUP_DATASET_NAME = "Nodegroup";
+    public static final String FUNCTION_DATASET_NAME = "Function";
+    public static final String DATASOURCE_ADAPTER_DATASET_NAME = "DatasourceAdapter";
+    public static final String LIBRARY_DATASET_NAME = "Library";
+    public static final String FEED_DATASET_NAME = "Feed";
+    public static final String FEED_CONNECTION_DATASET_NAME = "FeedConnection";
+    public static final String FEED_POLICY_DATASET_NAME = "FeedPolicy";
+    public static final String COMPACTION_POLICY_DATASET_NAME = "CompactionPolicy";
+    public static final String EXTERNAL_FILE_DATASET_NAME = "ExternalFile";
+
     private MetadataConstants() {
     }
 }
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/ConstantMergePolicyFactory.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/ConstantMergePolicyFactory.java
index 75eaf83..906b89a 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/ConstantMergePolicyFactory.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/ConstantMergePolicyFactory.java
@@ -18,8 +18,7 @@
  */
 package org.apache.hyracks.storage.am.lsm.common.impls;
 
-import java.util.Arrays;
-import java.util.HashSet;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 
@@ -35,12 +34,13 @@
 public class ConstantMergePolicyFactory implements ILSMMergePolicyFactory {
 
     private static final long serialVersionUID = 1L;
+    public static final String NAME = "constant";
     public static final String NUM_COMPONENTS = "num-components";
-    private static final Set<String> PROPERTIES_NAMES = new HashSet<>(Arrays.asList(NUM_COMPONENTS));
+    public static final Set<String> PROPERTIES_NAMES = Collections.singleton(NUM_COMPONENTS);
 
     @Override
     public String getName() {
-        return "constant";
+        return NAME;
     }
 
     @Override
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/NoMergePolicyFactory.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/NoMergePolicyFactory.java
index 3d07a67..b6b343e 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/NoMergePolicyFactory.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/NoMergePolicyFactory.java
@@ -19,8 +19,7 @@
 
 package org.apache.hyracks.storage.am.lsm.common.impls;
 
-import java.util.Arrays;
-import java.util.HashSet;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 
@@ -36,8 +35,7 @@
 public class NoMergePolicyFactory implements ILSMMergePolicyFactory {
 
     private static final long serialVersionUID = 1L;
-    private static final String[] SET_VALUES = new String[] {};
-    private static final Set<String> PROPERTIES_NAMES = new HashSet<>(Arrays.asList(SET_VALUES));
+    public static final Set<String> PROPERTIES_NAMES = Collections.emptySet();
     public static final String NAME = "no-merge";
 
     @Override
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/PrefixMergePolicyFactory.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/PrefixMergePolicyFactory.java
index 3480eaf..0ac16fb 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/PrefixMergePolicyFactory.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/impls/PrefixMergePolicyFactory.java
@@ -20,7 +20,9 @@
 package org.apache.hyracks.storage.am.lsm.common.impls;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -36,14 +38,15 @@
 public class PrefixMergePolicyFactory implements ILSMMergePolicyFactory {
 
     private static final long serialVersionUID = 1L;
-
-    private static final String[] SET_VALUES =
-            new String[] { "max-mergable-component-size", "max-tolerance-component-count" };
-    private static final Set<String> PROPERTIES_NAMES = new HashSet<>(Arrays.asList(SET_VALUES));
+    public static final String NAME = "prefix";
+    public static final String MAX_MERGABLE_SIZE = "max-mergable-component-size";
+    public static final String MAX_TOLERANCE_COUNT = "max-tolerance-component-count";
+    public static final Set<String> PROPERTIES_NAMES =
+            Collections.unmodifiableSet(new HashSet<>(Arrays.asList(MAX_MERGABLE_SIZE, MAX_TOLERANCE_COUNT)));
 
     @Override
     public String getName() {
-        return "prefix";
+        return NAME;
     }
 
     @Override