[NO ISSUE][OTH] Extensible QueryServiceServlet

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

Details:

- Set StatementProperties before attempting to execute the statements
  to have any changes reflected in case of statements execution failures.
- Pass execution state when a request fails.

Change-Id: Ic84aa2d7641a0f51c2d2ec13f2900066b225ec5b
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/11923
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
Reviewed-by: Michael Blow <mblow@apache.org>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java
index d6ebdad..2189c17 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java
@@ -48,6 +48,7 @@
 import org.apache.hyracks.api.util.ExceptionUtils;
 import org.apache.hyracks.http.api.IChannelClosedHandler;
 import org.apache.hyracks.http.api.IServletRequest;
+import org.apache.hyracks.http.api.IServletResponse;
 import org.apache.hyracks.http.server.HttpServer;
 import org.apache.hyracks.http.server.InterruptOnCloseHandler;
 import org.apache.hyracks.ipc.exceptions.IPCException;
@@ -167,13 +168,13 @@
 
     @Override
     protected void handleExecuteStatementException(Throwable t, RequestExecutionState executionState,
-            QueryServiceRequestParameters param) {
+            QueryServiceRequestParameters param, IServletResponse response) {
         if (t instanceof TimeoutException // TODO(mblow): I don't think t can ever been an instance of TimeoutException
                 || ExceptionUtils.matchingCause(t, candidate -> candidate instanceof IPCException)) {
             GlobalConfig.ASTERIX_LOGGER.log(Level.WARN, t.toString(), t);
             executionState.setStatus(ResultStatus.FAILED, HttpResponseStatus.SERVICE_UNAVAILABLE);
         } else {
-            super.handleExecuteStatementException(t, executionState, param);
+            super.handleExecuteStatementException(t, executionState, param, response);
         }
     }
 
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 a043050..abe9716 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
@@ -305,9 +305,9 @@
             }
             errorCount = 0;
         } catch (Exception | org.apache.asterix.lang.sqlpp.parser.TokenMgrError e) {
-            handleExecuteStatementException(e, executionState, param);
+            handleExecuteStatementException(e, executionState, param, response);
             response.setStatus(executionState.getHttpStatus());
-            requestFailed(e, responsePrinter);
+            requestFailed(e, responsePrinter, executionState);
         } finally {
             executionState.finish();
         }
@@ -419,7 +419,7 @@
     }
 
     protected boolean handleIFormattedException(IError error, IFormattedException ex,
-            RequestExecutionState executionState, QueryServiceRequestParameters param) {
+            RequestExecutionState executionState, QueryServiceRequestParameters param, IServletResponse response) {
         if (error instanceof ErrorCode) {
             switch ((ErrorCode) error) {
                 case INVALID_REQ_PARAM_VAL:
@@ -451,7 +451,7 @@
     }
 
     protected void handleExecuteStatementException(Throwable t, RequestExecutionState executionState,
-            QueryServiceRequestParameters param) {
+            QueryServiceRequestParameters param, IServletResponse response) {
         if (t instanceof org.apache.asterix.lang.sqlpp.parser.TokenMgrError || t instanceof AlgebricksException) {
             if (LOGGER.isDebugEnabled()) {
                 LOGGER.debug("handleException: {}: {}", t.getMessage(), LogRedactionUtil.statement(param.toString()),
@@ -465,8 +465,8 @@
         } else if (t instanceof IFormattedException) {
             IFormattedException formattedEx = (IFormattedException) t;
             Optional<IError> maybeError = formattedEx.getError();
-            if (maybeError.isPresent()
-                    && handleIFormattedException(maybeError.get(), (IFormattedException) t, executionState, param)) {
+            if (maybeError.isPresent() && handleIFormattedException(maybeError.get(), (IFormattedException) t,
+                    executionState, param, response)) {
                 return;
             }
         }
@@ -496,7 +496,8 @@
         sessionConfig.set(SessionConfig.FORMAT_CSV_HEADER, param.isCSVWithHeader());
     }
 
-    protected void requestFailed(Throwable throwable, ResponsePrinter responsePrinter) {
+    protected void requestFailed(Throwable throwable, ResponsePrinter responsePrinter,
+            RequestExecutionState executionState) {
         final ExecutionError executionError = ExecutionError.of(throwable);
         responsePrinter.addResultPrinter(new ErrorsPrinter(Collections.singletonList(executionError)));
     }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/message/ExecuteStatementRequestMessage.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/message/ExecuteStatementRequestMessage.java
index 29ee76d..30b98ec 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/message/ExecuteStatementRequestMessage.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/message/ExecuteStatementRequestMessage.java
@@ -139,6 +139,8 @@
         IStorageComponentProvider storageComponentProvider = ccAppCtx.getStorageComponentProvider();
         IStatementExecutorFactory statementExecutorFactory = ccApp.getStatementExecutorFactory();
         ExecuteStatementResponseMessage responseMsg = new ExecuteStatementResponseMessage(requestMessageId);
+        final IStatementExecutor.StatementProperties statementProperties = new IStatementExecutor.StatementProperties();
+        responseMsg.setStatementProperties(statementProperties);
         try {
             List<Warning> warnings = new ArrayList<>();
             IParser parser = compilationProvider.getParserFactory().createParser(statementsText);
@@ -160,8 +162,6 @@
                     compilationProvider, storageComponentProvider, new ResponsePrinter(sessionOutput));
             final IStatementExecutor.Stats stats = new IStatementExecutor.Stats();
             stats.setProfileType(profileType);
-            final IStatementExecutor.StatementProperties statementProperties =
-                    new IStatementExecutor.StatementProperties();
             Map<String, IAObject> stmtParams = RequestParameters.deserializeParameterValues(statementParameters);
             final IRequestParameters requestParameters =
                     new RequestParameters(requestReference, statementsText, null, resultProperties, stats,
@@ -174,7 +174,6 @@
             responseMsg.setResult(outWriter.toString());
             responseMsg.setMetadata(outMetadata);
             responseMsg.setStats(stats);
-            responseMsg.setStatementProperties(statementProperties);
             responseMsg.setExecutionPlans(translator.getExecutionPlans());
             responseMsg.setWarnings(warnings);
         } catch (AlgebricksException | HyracksException | org.apache.asterix.lang.sqlpp.parser.TokenMgrError pe) {
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 4b6f01d..38225d7 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
@@ -3930,7 +3930,8 @@
         appCtx.getRequestTracker().track(clientRequest);
     }
 
-    protected void validateStatements(IRequestParameters requestParameters) throws CompilationException {
+    protected void validateStatements(IRequestParameters requestParameters)
+            throws CompilationException, HyracksDataException {
         validateStatements(statements, requestParameters.isMultiStatement(),
                 requestParameters.getStatementCategoryRestrictionMask());
     }