[NO ISSUE][API] Support sql-compat parameter in QueryServiceServlet

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

Details:
- QueryServiceServlet supports 'sql-compat' parameter which indicates
  that a query should be evaluated in SQL-compatible mode

Change-Id: I3e0cfe3839e4bbdf1827cedf5f0abfaa536f78ff
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/13645
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IRequestParameters.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IRequestParameters.java
index ab1061f..c6022eb 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IRequestParameters.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IRequestParameters.java
@@ -78,6 +78,8 @@
 
     boolean isPrintSignature();
 
+    boolean isSQLCompatMode();
+
     /**
      * @return canonical name of the default dataverse for this statement
      */
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 53137e6..f2bb66d 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
@@ -150,7 +150,7 @@
             SqlppExpressionToPlanTranslator.REWRITE_IN_AS_OR_OPTION, "hash_merge", "output-record-type",
             DisjunctivePredicateToJoinRule.REWRITE_OR_AS_JOIN_OPTION,
             SetAsterixPhysicalOperatorsRule.REWRITE_ATTEMPT_BATCH_ASSIGN,
-            EquivalenceClassUtils.REWRITE_INTERNAL_QUERYUID_PK);
+            EquivalenceClassUtils.REWRITE_INTERNAL_QUERYUID_PK, SqlppQueryRewriter.SQL_COMPAT_OPTION);
 
     private final IRewriterFactory rewriterFactory;
     private final IAstPrintVisitorFactory astPrintVisitorFactory;
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 e6ba15f..5bcde3d 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
@@ -140,11 +140,13 @@
             Map<String, String> optionalParameters, Map<String, byte[]> statementParameters, INCServiceContext ncCtx,
             MessageFuture responseFuture, ILangExtension.Language queryLanguage, String handleUrl,
             int stmtCategoryRestrictionMask, boolean forceDropDataset) {
-        return new ExecuteStatementRequestMessage(ncCtx.getNodeId(), responseFuture.getFutureId(), queryLanguage,
-                statementsText, sessionOutput.config(), resultProperties.getNcToCcResultProperties(),
-                param.getClientContextID(), param.getDataverse(), handleUrl, optionalParameters, statementParameters,
-                param.isMultiStatement(), param.getProfileType(), stmtCategoryRestrictionMask, requestReference,
-                forceDropDataset);
+        ExecuteStatementRequestMessage requestMessage = new ExecuteStatementRequestMessage(ncCtx.getNodeId(),
+                responseFuture.getFutureId(), queryLanguage, statementsText, sessionOutput.config(),
+                resultProperties.getNcToCcResultProperties(), param.getClientContextID(), param.getDataverse(),
+                handleUrl, optionalParameters, statementParameters, param.isMultiStatement(), param.getProfileType(),
+                stmtCategoryRestrictionMask, requestReference, forceDropDataset);
+        requestMessage.setSQLCompatMode(param.isSQLCompatMode());
+        return requestMessage;
     }
 
     private void cancelQuery(INCMessageBroker messageBroker, String nodeId, String uuid, String clientContextID,
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceRequestParameters.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceRequestParameters.java
index 084bca7..df068c0 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceRequestParameters.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceRequestParameters.java
@@ -79,7 +79,8 @@
         PROFILE("profile"),
         SIGNATURE("signature"),
         MULTI_STATEMENT("multi-statement"),
-        MAX_WARNINGS("max-warnings");
+        MAX_WARNINGS("max-warnings"),
+        SQL_COMPAT("sql-compat");
 
         private final String str;
 
@@ -142,6 +143,7 @@
     private boolean isCSVWithHeader = false;
     private boolean signature = true;
     private boolean multiStatement = true;
+    private boolean sqlCompatMode = false;
     private long timeout = TimeUnit.MILLISECONDS.toMillis(Long.MAX_VALUE);
     private long maxResultReads = 1L;
     private long maxWarnings = 0L;
@@ -358,6 +360,14 @@
         this.multiStatement = multiStatement;
     }
 
+    public boolean isSQLCompatMode() {
+        return sqlCompatMode;
+    }
+
+    public void setSQLCompatMode(boolean sqlCompatMode) {
+        this.sqlCompatMode = sqlCompatMode;
+    }
+
     public void setMaxWarnings(long maxWarnings) {
         this.maxWarnings = maxWarnings;
     }
@@ -391,6 +401,7 @@
         object.put("parseOnly", parseOnly);
         object.put("readOnly", readOnly);
         object.put("maxWarnings", maxWarnings);
+        object.put("sqlCompat", sqlCompatMode);
         if (statementParams != null) {
             for (Map.Entry<String, JsonNode> statementParam : statementParams.entrySet()) {
                 object.set('$' + statementParam.getKey(), statementParam.getValue());
@@ -474,6 +485,7 @@
         setJob(parseBoolean(req, Parameter.JOB.str(), valGetter, isJob()));
         setSignature(parseBoolean(req, Parameter.SIGNATURE.str(), valGetter, isSignature()));
         setClientType(parseIfExists(req, Parameter.CLIENT_TYPE.str(), valGetter, getClientType(), clientTypes::get));
+        setSQLCompatMode(parseBoolean(req, Parameter.SQL_COMPAT.str(), valGetter, isSQLCompatMode()));
     }
 
     protected void setExtraParams(JsonNode jsonRequest) throws HyracksDataException {
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 b46c299..9f83aa8 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
@@ -519,6 +519,7 @@
                 resultProperties, stats, statementProperties, null, param.getClientContextID(), param.getDataverse(),
                 optionalParameters, stmtParams, param.isMultiStatement(), stmtCategoryRestriction);
         requestParameters.setPrintSignature(param.isSignature());
+        requestParameters.setSQLCompatMode(param.isSQLCompatMode());
         return requestParameters;
     }
 
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 fa05870..0a5e033 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
@@ -66,7 +66,7 @@
 import org.apache.logging.log4j.Logger;
 
 public class ExecuteStatementRequestMessage implements ICcAddressedMessage {
-    private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 4L;
     private static final Logger LOGGER = LogManager.getLogger();
     //TODO: Make configurable: https://issues.apache.org/jira/browse/ASTERIXDB-2062
     public static final long DEFAULT_NC_TIMEOUT_MILLIS = TimeUnit.MILLISECONDS.toMillis(Long.MAX_VALUE);
@@ -89,6 +89,7 @@
     private final IRequestReference requestReference;
     private final boolean forceDropDataset;
     private final boolean skipAdmissionPolicy;
+    private boolean sqlCompatMode;
 
     public ExecuteStatementRequestMessage(String requestNodeId, long requestMessageId, ILangExtension.Language lang,
             String statementsText, SessionConfig sessionConfig, ResultProperties resultProperties,
@@ -126,6 +127,14 @@
         this.defaultDataverseName = defaultDataverseName;
     }
 
+    public boolean isSQLCompatMode() {
+        return sqlCompatMode;
+    }
+
+    public void setSQLCompatMode(boolean sqlCompatMode) {
+        this.sqlCompatMode = sqlCompatMode;
+    }
+
     @Override
     public void handle(ICcApplicationContext ccAppCtx) throws HyracksDataException, InterruptedException {
         ICCServiceContext ccSrvContext = ccAppCtx.getServiceContext();
@@ -166,10 +175,8 @@
             final IStatementExecutor.Stats stats = new IStatementExecutor.Stats();
             stats.setProfileType(profileType);
             Map<String, IAObject> stmtParams = RequestParameters.deserializeParameterValues(statementParameters);
-            final IRequestParameters requestParameters = new RequestParameters(requestReference, statementsText, null,
-                    resultProperties, stats, statementProperties, outMetadata, clientContextID, defaultDataverseName,
-                    optionalParameters, stmtParams, multiStatement, statementCategoryRestrictionMask, forceDropDataset,
-                    skipAdmissionPolicy);
+            final IRequestParameters requestParameters =
+                    createRequestParameters(statementProperties, stmtParams, outMetadata, stats);
             translator.compileAndExecute(ccApp.getHcc(), requestParameters);
             translator.getWarnings(warnings, maxWarnings - warnings.size());
             stats.updateTotalWarningsCount(parserTotalWarningsCount);
@@ -194,6 +201,17 @@
         }
     }
 
+    protected IRequestParameters createRequestParameters(IStatementExecutor.StatementProperties statementProperties,
+            Map<String, IAObject> stmtParams, IStatementExecutor.ResultMetadata outMetadata,
+            IStatementExecutor.Stats stats) {
+        RequestParameters requestParameters = new RequestParameters(requestReference, statementsText, null,
+                resultProperties, stats, statementProperties, outMetadata, clientContextID, defaultDataverseName,
+                optionalParameters, stmtParams, multiStatement, statementCategoryRestrictionMask, forceDropDataset,
+                skipAdmissionPolicy);
+        requestParameters.setSQLCompatMode(sqlCompatMode);
+        return requestParameters;
+    }
+
     protected CCMessageBroker getMessageBroker(ICcApplicationContext ccAppCtx) {
         ICCServiceContext ccSrvContext = ccAppCtx.getServiceContext();
         return (CCMessageBroker) ccSrvContext.getMessageBroker();
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 0529c15..70ac386 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
@@ -158,6 +158,7 @@
 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.lang.sqlpp.rewrites.SqlppQueryRewriter;
 import org.apache.asterix.metadata.IDatasetDetails;
 import org.apache.asterix.metadata.MetadataManager;
 import org.apache.asterix.metadata.MetadataTransactionContext;
@@ -350,7 +351,7 @@
                 validateOperation(appCtx, activeDataverse, stmt);
                 MetadataProvider metadataProvider = MetadataProvider.create(appCtx, activeDataverse);
                 configureMetadataProvider(metadataProvider, config, resultSerializerFactoryProvider, writerFactory,
-                        outputFile);
+                        outputFile, requestParameters, stmt);
                 IStatementRewriter stmtRewriter = rewriterFactory.createStatementRewriter();
                 rewriteStatement(stmt, stmtRewriter, metadataProvider); // Rewrite the statement's AST.
                 Statement.Kind kind = stmt.getKind();
@@ -519,7 +520,10 @@
 
     protected void configureMetadataProvider(MetadataProvider metadataProvider, Map<String, String> config,
             IResultSerializerFactoryProvider resultSerializerFactoryProvider, IAWriterFactory writerFactory,
-            FileSplit outputFile) {
+            FileSplit outputFile, IRequestParameters requestParameters, Statement statement) {
+        if (statement.getKind() == Statement.Kind.QUERY && requestParameters.isSQLCompatMode()) {
+            metadataProvider.getConfig().put(SqlppQueryRewriter.SQL_COMPAT_OPTION, Boolean.TRUE.toString());
+        }
         metadataProvider.getConfig().putAll(config);
         metadataProvider.setWriterFactory(writerFactory);
         metadataProvider.setResultSerializerFactoryProvider(resultSerializerFactoryProvider);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/RequestParameters.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/RequestParameters.java
index 7b634bd..8bc6b76 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/RequestParameters.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/RequestParameters.java
@@ -64,6 +64,7 @@
     private final boolean forceDropDataset;
     private final boolean skipAdmissionPolicy;
     private boolean printSignature;
+    private boolean sqlCompatMode;
 
     public RequestParameters(IRequestReference requestReference, String statement, IResultSet resultSet,
             ResultProperties resultProperties, Stats stats, StatementProperties statementProperties,
@@ -199,6 +200,15 @@
         this.printSignature = printSignature;
     }
 
+    @Override
+    public boolean isSQLCompatMode() {
+        return sqlCompatMode;
+    }
+
+    public void setSQLCompatMode(boolean sqlCompatMode) {
+        this.sqlCompatMode = sqlCompatMode;
+    }
+
     public static Map<String, byte[]> serializeParameterValues(Map<String, JsonNode> inParams,
             SessionConfig.OutputFormat format) throws HyracksDataException {
         if (inParams == null || inParams.isEmpty()) {
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 7b2e5e3..b6fd9da 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
@@ -100,6 +100,10 @@
 
     public static final String INLINE_WITH_OPTION = "inline_with";
     private static final boolean INLINE_WITH_OPTION_DEFAULT = true;
+
+    public static final String SQL_COMPAT_OPTION = "sql_compat";
+    private static final boolean SQL_COMPAT_OPTION_DEFAULT = false;
+
     private final IParserFactory parserFactory;
     private SqlppFunctionBodyRewriter functionAndViewBodyRewriter;
     private IReturningStatement topStatement;