DRILL-7603: Allow default schema to be set for HTTP queries

This allows REST API requests and Web UI requests to specify a
default
schema.  Otherwise this is not possible for HTTP clients because the
"USE" command requires a session, which HTTP clients do not have.

closes #1996
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryResources.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryResources.java
index bf07fae..ec2a400 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryResources.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryResources.java
@@ -96,10 +96,12 @@
   public Viewable submitQuery(@FormParam("query") String query,
                               @FormParam("queryType") String queryType,
                               @FormParam("autoLimit") String autoLimit,
-                              @FormParam("userName") String userName) throws Exception {
+                              @FormParam("userName") String userName,
+                              @FormParam("defaultSchema") String defaultSchema) throws Exception {
     try {
+      // Apply options from the form fields, if provided
       final String trimmedQueryString = CharMatcher.is(';').trimTrailingFrom(query.trim());
-      final QueryResult result = submitQueryJSON(new QueryWrapper(trimmedQueryString, queryType, autoLimit, userName));
+      final QueryResult result = submitQueryJSON(new QueryWrapper(trimmedQueryString, queryType, autoLimit, userName, defaultSchema));
       List<Integer> rowsPerPageValues = work.getContext().getConfig().getIntList(ExecConstants.HTTP_WEB_CLIENT_RESULTSET_ROWS_PER_PAGE_VALUES);
       Collections.sort(rowsPerPageValues);
       final String rowsPerPageValuesAsStr = Joiner.on(",").join(rowsPerPageValues);
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
index 3b99491..0a7bcd7 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
@@ -19,6 +19,7 @@
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.calcite.schema.SchemaPlus;
 import org.apache.drill.common.config.DrillConfig;
 import org.apache.drill.common.exceptions.UserException;
 import org.apache.drill.common.exceptions.UserRemoteException;
@@ -32,6 +33,7 @@
 import org.apache.drill.exec.proto.helper.QueryIdHelper;
 import org.apache.drill.exec.rpc.user.InboundImpersonationManager;
 import org.apache.drill.exec.server.options.SessionOptionManager;
+import org.apache.drill.exec.store.SchemaTreeProvider;
 import org.apache.drill.exec.util.ImpersonationUtil;
 import org.apache.drill.exec.work.WorkManager;
 import org.apache.parquet.Strings;
@@ -51,8 +53,8 @@
   private final String query;
   private final String queryType;
   private final int autoLimitRowCount;
-
   private final String userName;
+  private final String defaultSchema;
 
   private static MemoryMXBean memMXBean = ManagementFactory.getMemoryMXBean();
 
@@ -61,11 +63,13 @@
     @JsonProperty("query") String query,
     @JsonProperty("queryType") String queryType,
     @JsonProperty("autoLimit") String autoLimit,
-    @JsonProperty("userName") String userName) {
+    @JsonProperty("userName") String userName,
+    @JsonProperty("defaultSchema") String defaultSchema) {
     this.query = query;
     this.queryType = queryType.toUpperCase();
     this.autoLimitRowCount = autoLimit != null && autoLimit.matches("[0-9]+") ? Integer.valueOf(autoLimit) : 0;
     this.userName = userName;
+    this.defaultSchema = defaultSchema;
   }
 
   public String getQuery() {
@@ -90,6 +94,13 @@
     applyUserName(workManager, webUserConnection);
 
     int defaultMaxRows = webUserConnection.getSession().getOptions().getOption(ExecConstants.QUERY_MAX_ROWS).num_val.intValue();
+    if (!Strings.isNullOrEmpty(defaultSchema)) {
+      SessionOptionManager options = webUserConnection.getSession().getOptions();
+      SchemaTreeProvider schemaTreeProvider = new SchemaTreeProvider(workManager.getContext());
+      SchemaPlus rootSchema = schemaTreeProvider.createRootSchema(options);
+      webUserConnection.getSession().setDefaultSchemaPath(defaultSchema, rootSchema);
+    }
+
     int maxRows;
     if (autoLimitRowCount > 0 && defaultMaxRows > 0) {
       maxRows = Math.min(autoLimitRowCount, defaultMaxRows);
diff --git a/exec/java-exec/src/main/resources/rest/query/query.ftl b/exec/java-exec/src/main/resources/rest/query/query.ftl
index 520a93b..e7bbed2 100644
--- a/exec/java-exec/src/main/resources/rest/query/query.ftl
+++ b/exec/java-exec/src/main/resources/rest/query/query.ftl
@@ -82,6 +82,8 @@
       Submit
     </button>
     <input type="checkbox" name="forceLimit" value="limit" <#if model.isAutoLimitEnabled()>checked</#if>> Limit results to <input type="text" id="autoLimit" name="autoLimit" min="0" value="${model.getDefaultRowsAutoLimited()?c}" size="6" pattern="[0-9]*"> rows <span class="glyphicon glyphicon-info-sign" title="Limits the number of records retrieved in the query. Ignored if query has a limit already" style="cursor:pointer"></span>
+    <label> Default Schema <input type="text" size="10" name="defaultSchema" id="defaultSchema"> </label>
+    <span class="glyphicon glyphicon-info-sign" title="Set the default schema used to find table names, and for SHOW FILES and SHOW TABLES" style="cursor:pointer"></span>
     <input type="hidden" name="csrfToken" value="${model.getCsrfToken()}">
   </form>
 
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/RestServerTest.java b/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/RestServerTest.java
index 7136a7d..2915d28 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/RestServerTest.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/RestServerTest.java
@@ -30,11 +30,11 @@
 
 public class RestServerTest extends ClusterTest {
   protected QueryWrapper.QueryResult runQuery(String sql) throws Exception {
-    return runQuery(new QueryWrapper(sql, "SQL", null, null));
+    return runQuery(new QueryWrapper(sql, "SQL", null, null, null));
   }
 
   protected QueryWrapper.QueryResult runQueryWithUsername(String sql, String userName) throws Exception {
-    return runQuery(new QueryWrapper(sql, "SQL", null, userName));
+    return runQuery(new QueryWrapper(sql, "SQL", null, userName, null));
   }
 
   protected QueryWrapper.QueryResult runQuery(QueryWrapper q) throws Exception {
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/TestQueryWrapper.java b/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/TestQueryWrapper.java
index ed8ac2d..aaa7931 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/TestQueryWrapper.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/TestQueryWrapper.java
@@ -50,11 +50,19 @@
   @Test
   public void testImpersonationDisabled() throws Exception {
     try {
-      QueryWrapper q = new QueryWrapper("SHOW SCHEMAS", "SQL", null, "alfred");
+      QueryWrapper q = new QueryWrapper("SHOW SCHEMAS", "SQL", null, "alfred", null);
       runQuery(q);
       fail("Should have thrown exception");
     } catch (UserException e) {
       assertThat(e.getMessage(), containsString("User impersonation is not enabled"));
     }
   }
+
+  @Test
+  public void testSpecifyDefaultSchema() throws Exception {
+    QueryWrapper.QueryResult result = runQuery(new QueryWrapper("SHOW FILES", "SQL", null, null, "dfs.tmp"));
+    // SHOW FILES will fail if default schema is not provided
+    assertEquals("COMPLETED", result.queryState);
+  }
+
 }