ASTERIXDB-1148: Selectable array-wrapping of results
Introduce "wrapper-array" parameter to HTTP API which selects (for ADM and
JSON) whether to wrap the result sequence in a generated outer array. For
JSON this defaults to "true" as before. For ADM this defaults to false,
resulting in a large number of expected-results changes.
Also introduce ability to have AQL tests which provide HTTP parameters.
Change-Id: I3122f136ff9ca8a2c2268238c57bb5eddab7b27e
Reviewed-on: https://asterix-gerrit.ics.uci.edu/473
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Chris Hillery <ceej@lambda.nu>
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/common/SessionConfig.java b/asterix-app/src/main/java/org/apache/asterix/api/common/SessionConfig.java
index 4e64802..f0a0cc2 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/common/SessionConfig.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/common/SessionConfig.java
@@ -87,6 +87,11 @@
*/
public static final String FORMAT_CSV_HEADER = "format-csv-header";
+ /**
+ * Format flag: wrap results in outer array brackets (JSON or ADM).
+ */
+ public static final String FORMAT_WRAPPER_ARRAY = "format-wrapper-array";
+
// Standard execution flags.
private final boolean executeQuery;
private final boolean generateJobSpec;
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/APIServlet.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/APIServlet.java
index c22cb8e..2c0f897 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/APIServlet.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/APIServlet.java
@@ -77,6 +77,7 @@
}
String query = request.getParameter("query");
+ String wrapperArray = request.getParameter("wrapper-array");
String printExprParam = request.getParameter("print-expr-tree");
String printRewrittenExprParam = request.getParameter("print-rewritten-expr-tree");
String printLogicalPlanParam = request.getParameter("print-logical-plan");
@@ -105,6 +106,7 @@
SessionConfig sessionConfig = new SessionConfig(out, format, true, isSet(executeQuery), true);
sessionConfig.set(SessionConfig.FORMAT_HTML, true);
sessionConfig.set(SessionConfig.FORMAT_CSV_HEADER, csv_and_header);
+ sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, isSet(wrapperArray));
sessionConfig.setOOBData(isSet(printExprParam), isSet(printRewrittenExprParam),
isSet(printLogicalPlanParam), isSet(printOptimizedLogicalPlanParam), isSet(printJob));
MetadataManager.INSTANCE.init();
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/RESTAPIServlet.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/RESTAPIServlet.java
index be17229..fdaee18 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/RESTAPIServlet.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/RESTAPIServlet.java
@@ -71,6 +71,9 @@
// First check the "output" servlet parameter.
String output = request.getParameter("output");
String accept = request.getHeader("Accept");
+ if (accept == null) {
+ accept = "";
+ }
if (output != null) {
if (output.equals("CSV")) {
format = OutputFormat.CSV;
@@ -79,24 +82,43 @@
}
} else {
// Second check the Accept: HTTP header.
- if (accept != null) {
- if (accept.contains("application/x-adm")) {
- format = OutputFormat.ADM;
- } else if (accept.contains("text/csv")) {
- format = OutputFormat.CSV;
- }
+ if (accept.contains("application/x-adm")) {
+ format = OutputFormat.ADM;
+ } else if (accept.contains("text/csv")) {
+ format = OutputFormat.CSV;
}
}
// If it's JSON, check for the "lossless" flag
- if (format == OutputFormat.CLEAN_JSON
- && ("true".equals(request.getParameter("lossless")) || (accept != null && accept
- .contains("lossless=true")))) {
+ if (format == OutputFormat.CLEAN_JSON &&
+ ("true".equals(request.getParameter("lossless")) || accept.contains("lossless=true")) ) {
format = OutputFormat.LOSSLESS_JSON;
}
SessionConfig sessionConfig = new SessionConfig(response.getWriter(), format);
+ // If it's JSON or ADM, check for the "wrapper-array" flag. Default is
+ // "true" for JSON and "false" for ADM. (Not applicable for CSV.)
+ boolean wrapper_array;
+ switch (format) {
+ case CLEAN_JSON:
+ case LOSSLESS_JSON:
+ wrapper_array = true;
+ break;
+ default:
+ wrapper_array = false;
+ break;
+ }
+ String wrapper_param = request.getParameter("wrapper-array");
+ if (wrapper_param != null) {
+ wrapper_array = Boolean.valueOf(wrapper_param);
+ } else if (accept.contains("wrap-array=true")) {
+ wrapper_array = true;
+ } else if (accept.contains("wrap-array=false")) {
+ wrapper_array = false;
+ }
+ sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, wrapper_array);
+
// Now that format is set, output the content-type
switch (format) {
case ADM:
@@ -109,15 +131,15 @@
break;
case CSV: {
// Check for header parameter or in Accept:.
- if ("present".equals(request.getParameter("header"))
- || (accept != null && accept.contains("header=present"))) {
+ if ("present".equals(request.getParameter("header")) ||
+ accept.contains("header=present")) {
response.setContentType("text/csv; header=present");
sessionConfig.set(SessionConfig.FORMAT_CSV_HEADER, true);
} else {
response.setContentType("text/csv; header=absent");
}
}
- };
+ }
return sessionConfig;
}
diff --git a/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java b/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java
index 44c878d..391f61b 100644
--- a/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java
+++ b/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java
@@ -100,8 +100,8 @@
int bytesRead = resultReader.read(frame);
ByteBufferInputStream bbis = new ByteBufferInputStream();
- // Whether we need to separate top-level ADM instances with commas
- boolean need_commas = true;
+ // Whether we are wrapping the output sequence in an array
+ boolean wrap_array = false;
// Whether this is the first instance being output
boolean notfirst = false;
@@ -114,16 +114,16 @@
}
switch (conf.fmt()) {
- case CSV:
- need_commas = false;
- break;
case LOSSLESS_JSON:
case CLEAN_JSON:
case ADM:
- // Conveniently, LOSSLESS_JSON and ADM have the same syntax for an
- // "ordered list", and our representation of the result of a
- // statement is an ordered list of instances.
- conf.out().print("[ ");
+ if (conf.is(SessionConfig.FORMAT_WRAPPER_ARRAY)) {
+ // Conveniently, LOSSLESS_JSON and ADM have the same syntax for an
+ // "ordered list", and our representation of the result of a
+ // statement is an ordered list of instances.
+ conf.out().print("[ ");
+ wrap_array = true;
+ }
break;
}
@@ -145,7 +145,7 @@
}
}
result = new String(recordBytes, 0, numread, UTF_8);
- if (need_commas && notfirst) {
+ if (wrap_array && notfirst) {
conf.out().print(", ");
}
notfirst = true;
@@ -167,15 +167,8 @@
conf.out().flush();
- switch (conf.fmt()) {
- case LOSSLESS_JSON:
- case CLEAN_JSON:
- case ADM:
- conf.out().println(" ]");
- break;
- case CSV:
- // Nothing to do
- break;
+ if (wrap_array) {
+ conf.out().println(" ]");
}
if (conf.is(SessionConfig.FORMAT_HTML)) {
diff --git a/asterix-app/src/main/resources/webui/querytemplate.html b/asterix-app/src/main/resources/webui/querytemplate.html
index 6ddd664..6ad4818 100644
--- a/asterix-app/src/main/resources/webui/querytemplate.html
+++ b/asterix-app/src/main/resources/webui/querytemplate.html
@@ -220,7 +220,7 @@
</div>
<div>
- <label class="checkbox optlabel"> Output Format:<br/>
+ <label id="output-format" class="optlabel"> Output Format:<br/>
<select name="output-format" class="btn">
<option selected value="ADM">ADM</option>
<option value="CSV">CSV (no header)</option>
@@ -229,12 +229,13 @@
<option value="LOSSLESS_JSON">JSON (lossless)</option>
</select>
</label>
+ <label class="optlabel"><input type="checkbox" name="wrapper-array" value="true" /> Wrap results in outer array</label>
<label class="checkbox optlabel"><input type="checkbox" name="print-expr-tree" value="true" /> Print parsed expressions</label>
<label class="checkbox optlabel"><input type="checkbox" name="print-rewritten-expr-tree" value="true" /> Print rewritten expressions</label>
<label class="checkbox optlabel"><input type="checkbox" name="print-logical-plan" value="true" /> Print logical plan</label>
<label class="checkbox optlabel"><input type="checkbox" name="print-optimized-logical-plan" value="true" /> Print optimized logical plan</label>
<label class="checkbox optlabel"><input type="checkbox" name="print-job" value="true" /> Print Hyracks job</label>
- <label class="checkbox optlabel"><input type="checkbox" name="execute-query" value="true" checked/> Execute query</label>
+ <label class="optlabel"><input type="checkbox" name="execute-query" value="true" checked/> Execute query</label>
</div>
</form>
</div>