Till Westmann has submitted this change and it was merged. Change subject: Implement EXPLAIN for SQL++ ......................................................................
Implement EXPLAIN for SQL++ - move some code from static methods in ResultUtils to a stateful ResultPrinter to facilitate reuse (we create one ResultWriter per request) - tiny cleanup in LogicalOperatorPrettyPrintVisitor Change-Id: I7b7028fb243d494150cac525c73b2d77b0068646 Reviewed-on: https://asterix-gerrit.ics.uci.edu/1020 Tested-by: Jenkins <[email protected]> Integration-Tests: Jenkins <[email protected]> Reviewed-by: Yingyi Bu <[email protected]> --- M asterixdb/asterix-algebra/src/main/javacc/AQLPlus.jj M asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java M asterixdb/asterix-app/src/main/java/org/apache/asterix/aql/translator/QueryTranslator.java A asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultPrinter.java M asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/explain/explain_simple/explain_simple.1.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/results/explain/explain_simple/explain_simple.1.adm M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml M asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java M asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java M asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj M asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/Query.java M asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java M asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java M asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj M hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java 18 files changed, 292 insertions(+), 152 deletions(-) Approvals: Yingyi Bu: Looks good to me, approved Jenkins: Verified; Verified Objections: Jenkins: Violations found diff --git a/asterixdb/asterix-algebra/src/main/javacc/AQLPlus.jj b/asterixdb/asterix-algebra/src/main/javacc/AQLPlus.jj index 0e1e7a1..98cae63 100644 --- a/asterixdb/asterix-algebra/src/main/javacc/AQLPlus.jj +++ b/asterixdb/asterix-algebra/src/main/javacc/AQLPlus.jj @@ -487,7 +487,7 @@ Query Query()throws ParseException: { - Query query = new Query(); + Query query = new Query(false); Expression expr; } { 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 af17c05..d6864c1 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 @@ -18,6 +18,7 @@ */ package org.apache.asterix.api.common; +import java.io.IOException; import java.io.PrintWriter; import java.rmi.RemoteException; import java.util.ArrayList; @@ -48,6 +49,7 @@ import org.apache.asterix.metadata.declared.AqlMetadataProvider; import org.apache.asterix.om.util.AsterixAppContextInfo; import org.apache.asterix.optimizer.base.RuleCollections; +import org.apache.asterix.result.ResultUtils; import org.apache.asterix.runtime.job.listener.JobEventListenerFactory; import org.apache.asterix.transaction.management.service.transaction.JobIdFactory; import org.apache.asterix.translator.CompiledStatements.ICompiledDmlStatement; @@ -279,6 +281,16 @@ } } } + if (rwQ != null && rwQ.isExplain()) { + try { + LogicalOperatorPrettyPrintVisitor pvisitor = new LogicalOperatorPrettyPrintVisitor(); + PlanPrettyPrinter.printPlan(plan, pvisitor, 0); + ResultUtils.displayResults(pvisitor.get().toString(), conf, new ResultUtils.Stats(), null); + return null; + } catch (IOException e) { + throw new AlgebricksException(e); + } + } if (!conf.isGenerateJobSpec()) { return null; diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/aql/translator/QueryTranslator.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/aql/translator/QueryTranslator.java index 05d9b3d..d6065fb 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/aql/translator/QueryTranslator.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/aql/translator/QueryTranslator.java @@ -2529,14 +2529,16 @@ boolean bActiveTxn = true; metadataProvider.setMetadataTxnContext(mdTxnCtx); MetadataLockManager.INSTANCE.queryBegin(activeDefaultDataverse, query.getDataverses(), query.getDatasets()); - JobSpecification compiled = null; try { - compiled = rewriteCompileQuery(metadataProvider, query, null); + JobSpecification compiled = rewriteCompileQuery(metadataProvider, query, null); MetadataManager.INSTANCE.commitTransaction(mdTxnCtx); bActiveTxn = false; - if (sessionConfig.isExecuteQuery() && compiled != null) { + if (query.isExplain()) { + sessionConfig.out().flush(); + return; + } else if (sessionConfig.isExecuteQuery() && compiled != null) { GlobalConfig.ASTERIX_LOGGER.info(compiled.toJSON().toString(1)); JobId jobId = JobUtils.runJob(hcc, compiled, false); diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultPrinter.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultPrinter.java new file mode 100644 index 0000000..8e16ef7 --- /dev/null +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultPrinter.java @@ -0,0 +1,188 @@ +/* + * 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.result; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.IOException; +import java.io.StringWriter; +import java.nio.ByteBuffer; + +import org.apache.asterix.api.common.SessionConfig; +import org.apache.asterix.common.utils.JSONUtil; +import org.apache.asterix.om.types.ARecordType; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.prettyprint.AlgebricksAppendable; +import org.apache.hyracks.api.comm.IFrame; +import org.apache.hyracks.api.comm.IFrameTupleAccessor; +import org.apache.hyracks.api.comm.VSizeFrame; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.control.nc.resources.memory.FrameManager; + +public class ResultPrinter { + + // TODO(tillw): Should this be static? + private static FrameManager resultDisplayFrameMgr = new FrameManager(ResultReader.FRAME_SIZE); + + private final SessionConfig conf; + private final ResultUtils.Stats stats; + private final ARecordType recordType; + + private boolean indentJSON; + private boolean quoteRecord; + + // Whether we are wrapping the output sequence in an array + private boolean wrapArray = false; + // Whether this is the first instance being output + private boolean notFirst = false; + + public ResultPrinter(SessionConfig conf, ResultUtils.Stats stats, ARecordType recordType) { + this.conf = conf; + this.stats = stats; + this.recordType = recordType; + this.indentJSON = conf.is(SessionConfig.FORMAT_INDENT_JSON); + this.quoteRecord = conf.is(SessionConfig.FORMAT_QUOTE_RECORD); + } + + private static void appendCSVHeader(Appendable app, ARecordType recordType) throws HyracksDataException { + try { + String[] fieldNames = recordType.getFieldNames(); + boolean notfirst = false; + for (String name : fieldNames) { + if (notfirst) { + app.append(','); + } + notfirst = true; + app.append('"').append(name.replace("\"", "\"\"")).append('"'); + } + app.append("\r\n"); + } catch (IOException e) { + throw new HyracksDataException(e); + } + } + + private void printPrefix() throws HyracksDataException { + // If we're outputting CSV with a header, the HTML header was already + // output by displayCSVHeader(), so skip it here + if (conf.is(SessionConfig.FORMAT_HTML)) { + conf.out().println("<h4>Results:</h4>"); + conf.out().println("<pre>"); + } + + try { + conf.resultPrefix(new AlgebricksAppendable(conf.out())); + } catch (AlgebricksException e) { + throw new HyracksDataException(e); + } + + if (conf.is(SessionConfig.FORMAT_WRAPPER_ARRAY)) { + conf.out().print("[ "); + wrapArray = true; + } + + if (conf.fmt() == SessionConfig.OutputFormat.CSV && conf.is(SessionConfig.FORMAT_CSV_HEADER)) { + if (recordType == null) { + throw new HyracksDataException("Cannot print CSV with header without specifying output-record-type"); + } + if (quoteRecord) { + StringWriter sw = new StringWriter(); + appendCSVHeader(sw, recordType); + conf.out().print(JSONUtil.quoteAndEscape(sw.toString())); + conf.out().print("\n"); + notFirst = true; + } else { + appendCSVHeader(conf.out(), recordType); + } + } + } + + private void printPostfix() throws HyracksDataException { + conf.out().flush(); + if (wrapArray) { + conf.out().println(" ]"); + } + try { + conf.resultPostfix(new AlgebricksAppendable(conf.out())); + } catch (AlgebricksException e) { + throw new HyracksDataException(e); + } + if (conf.is(SessionConfig.FORMAT_HTML)) { + conf.out().println("</pre>"); + } + } + + private void displayRecord(String result) { + String record = result; + if (indentJSON) { + // TODO(tillw): this is inefficient - do this during record generation + record = JSONUtil.indent(record, 2); + } + if (conf.fmt() == SessionConfig.OutputFormat.CSV) { + // TODO(tillw): this is inefficient as well + record = record + "\r\n"; + } + if (quoteRecord) { + // TODO(tillw): this is inefficient as well + record = JSONUtil.quoteAndEscape(record); + } + conf.out().print(record); + ++stats.count; + // TODO(tillw) fix this approximation + stats.size += record.length(); + } + + public void print(String record) throws HyracksDataException { + printPrefix(); + // TODO(tillw) evil hack + quoteRecord = true; + displayRecord(record); + printPostfix(); + } + + public void print(ResultReader resultReader) throws HyracksDataException { + printPrefix(); + + final IFrameTupleAccessor fta = resultReader.getFrameTupleAccessor(); + final IFrame frame = new VSizeFrame(resultDisplayFrameMgr); + + while (resultReader.read(frame) > 0) { + final ByteBuffer frameBuffer = frame.getBuffer(); + final byte[] frameBytes = frameBuffer.array(); + fta.reset(frameBuffer); + final int last = fta.getTupleCount(); + for (int tIndex = 0; tIndex < last; tIndex++) { + final int start = fta.getTupleStartOffset(tIndex); + int length = fta.getTupleEndOffset(tIndex) - start; + if (conf.fmt() == SessionConfig.OutputFormat.CSV + && ((length > 0) && (frameBytes[start + length - 1] == '\n'))) { + length--; + } + String result = new String(frameBytes, start, length, UTF_8); + if (wrapArray && notFirst) { + conf.out().print(", "); + } + notFirst = true; + displayRecord(result); + } + frameBuffer.clear(); + } + + printPostfix(); + } +} diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java index 8c3ccfc..3503549 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java @@ -24,7 +24,6 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; -import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; @@ -32,25 +31,16 @@ import java.util.regex.Pattern; import org.apache.asterix.api.common.SessionConfig; -import org.apache.asterix.api.common.SessionConfig.OutputFormat; import org.apache.asterix.api.http.servlet.APIServlet; -import org.apache.asterix.common.utils.JSONUtil; import org.apache.asterix.om.types.ARecordType; import org.apache.http.ParseException; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; -import org.apache.hyracks.algebricks.core.algebra.prettyprint.AlgebricksAppendable; -import org.apache.hyracks.api.comm.IFrame; -import org.apache.hyracks.api.comm.IFrameTupleAccessor; -import org.apache.hyracks.api.comm.VSizeFrame; import org.apache.hyracks.api.exceptions.HyracksDataException; -import org.apache.hyracks.control.nc.resources.memory.FrameManager; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; public class ResultUtils { - private static final Charset UTF_8 = Charset.forName("UTF-8"); - static Map<Character, String> HTML_ENTITIES = new HashMap<Character, String>(); static { @@ -74,124 +64,14 @@ return s; } - private static void printCSVHeader(ARecordType recordType, PrintWriter out) { - String[] fieldNames = recordType.getFieldNames(); - boolean notfirst = false; - for (String name : fieldNames) { - if (notfirst) { - out.print(','); - } - notfirst = true; - out.print('"'); - out.print(name.replace("\"", "\"\"")); - out.print('"'); - } - out.print("\r\n"); - } - - public static FrameManager resultDisplayFrameMgr = new FrameManager(ResultReader.FRAME_SIZE); - public static void displayResults(ResultReader resultReader, SessionConfig conf, Stats stats, ARecordType recordType) throws HyracksDataException { - // 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; + new ResultPrinter(conf, stats, recordType).print(resultReader); + } - // If we're outputting CSV with a header, the HTML header was already - // output by displayCSVHeader(), so skip it here - if (conf.is(SessionConfig.FORMAT_HTML)) { - conf.out().println("<h4>Results:</h4>"); - conf.out().println("<pre>"); - } - - try { - conf.resultPrefix(new AlgebricksAppendable(conf.out())); - } catch (AlgebricksException e) { - throw new HyracksDataException(e); - } - - if (conf.is(SessionConfig.FORMAT_WRAPPER_ARRAY)) { - conf.out().print("[ "); - wrap_array = true; - } - - final boolean indentJSON = conf.is(SessionConfig.FORMAT_INDENT_JSON); - final boolean quoteRecord = conf.is(SessionConfig.FORMAT_QUOTE_RECORD); - - if (conf.fmt() == OutputFormat.CSV && conf.is(SessionConfig.FORMAT_CSV_HEADER)) { - if (recordType == null) { - throw new HyracksDataException("Cannot print CSV with header without specifying output-record-type"); - } - if (quoteRecord) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - printCSVHeader(recordType, pw); - pw.close(); - conf.out().print(JSONUtil.quoteAndEscape(sw.toString())); - conf.out().print("\n"); - notfirst = true; - } else { - printCSVHeader(recordType, conf.out()); - } - } - - final IFrameTupleAccessor fta = resultReader.getFrameTupleAccessor(); - final IFrame frame = new VSizeFrame(resultDisplayFrameMgr); - - while (resultReader.read(frame) > 0) { - final ByteBuffer frameBuffer = frame.getBuffer(); - final byte[] frameBytes = frameBuffer.array(); - fta.reset(frameBuffer); - final int last = fta.getTupleCount(); - for (int tIndex = 0; tIndex < last; tIndex++) { - final int start = fta.getTupleStartOffset(tIndex); - int length = fta.getTupleEndOffset(tIndex) - start; - if (conf.fmt() == OutputFormat.CSV) { - if ((length > 0) && (frameBytes[start + length - 1] == '\n')) { - length--; - } - } - String result = new String(frameBytes, start, length, UTF_8); - if (wrap_array && notfirst) { - conf.out().print(", "); - } - notfirst = true; - if (indentJSON) { - // TODO(tillw): this is inefficient - do this during result generation - result = JSONUtil.indent(result, 2); - } - if (conf.fmt() == OutputFormat.CSV) { - // TODO(tillw): this is inefficient as well - result = result + "\r\n"; - } - if (quoteRecord) { - // TODO(tillw): this is inefficient as well - result = JSONUtil.quoteAndEscape(result); - } - conf.out().print(result); - ++stats.count; - // TODO(tillw) fix this approximation - stats.size += result.length(); - } - frameBuffer.clear(); - } - - conf.out().flush(); - - if (wrap_array) { - conf.out().println(" ]"); - } - - try { - conf.resultPostfix(new AlgebricksAppendable(conf.out())); - } catch (AlgebricksException e) { - throw new HyracksDataException(e); - } - - if (conf.is(SessionConfig.FORMAT_HTML)) { - conf.out().println("</pre>"); - } + public static void displayResults(String record, SessionConfig conf, Stats stats, ARecordType recordType) + throws HyracksDataException { + new ResultPrinter(conf, stats, recordType).print(record); } public static JSONObject getErrorResponse(int errorCode, String errorMessage, String errorSummary, diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/explain/explain_simple/explain_simple.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/explain/explain_simple/explain_simple.1.query.sqlpp new file mode 100644 index 0000000..6860087 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/explain/explain_simple/explain_simple.1.query.sqlpp @@ -0,0 +1,24 @@ +/* + * 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. + */ +/* +* Description : EXPLAIN a plan for a very simple query +* Expected Res : Success +* Date : Jul 25, 2016 +*/ +explain select value 1+1; diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/explain/explain_simple/explain_simple.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/explain/explain_simple/explain_simple.1.adm new file mode 100644 index 0000000..d3b66a5 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/explain/explain_simple/explain_simple.1.adm @@ -0,0 +1,9 @@ +distribute result [%0->$$2] +-- DISTRIBUTE_RESULT |UNPARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |UNPARTITIONED| + assign [$$2] <- [AInt64: {2}] + -- ASSIGN |UNPARTITIONED| + empty-tuple-source + -- EMPTY_TUPLE_SOURCE |UNPARTITIONED| + diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml index 99e4935..fa29a42 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml @@ -63,6 +63,13 @@ </compilation-unit> </test-case> </test-group> + <test-group name="explain"> + <test-case FilePath="explain"> + <compilation-unit name="explain_simple"> + <output-dir compare="Text">explain_simple</output-dir> + </compilation-unit> + </test-case> + </test-group> <!-- <test-group name="union"> <test-case FilePath="union"> diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java index 9e6f857..836de6a 100644 --- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java +++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/statement/SubscribeFeedStatement.java @@ -70,7 +70,7 @@ } public void initialize(MetadataTransactionContext mdTxnCtx) throws MetadataException { - this.query = new Query(); + this.query = new Query(false); EntityId sourceFeedId = connectionRequest.getFeedJointKey().getFeedId(); Feed subscriberFeed = MetadataManager.INSTANCE.getFeed(mdTxnCtx, connectionRequest.getReceivingFeedId().getDataverse(), diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java index cedeb77..9268422 100644 --- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java +++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java @@ -64,7 +64,7 @@ VariableExpr returnExpr = new VariableExpr(var.getVar()); returnExpr.setIsNewVar(false); FLWOGRExpression flowgr = new FLWOGRExpression(clauseList, returnExpr); - Query query = new Query(); + Query query = new Query(false); query.setBody(flowgr); deleteStmt.setQuery(query); return null; diff --git a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj index 172e534..b3f6200 100644 --- a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj +++ b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj @@ -1528,7 +1528,7 @@ Query Query() throws ParseException: { - Query query = new Query(); + Query query = new Query(false); // we set the pointers to the dataverses and datasets lists to fill them with entities to be locked setDataverses(query.getDataverses()); setDatasets(query.getDatasets()); diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/Query.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/Query.java index 80853c8..9be4830 100644 --- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/Query.java +++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/Query.java @@ -28,17 +28,20 @@ import org.apache.commons.lang3.ObjectUtils; public class Query implements Statement { + private final boolean explain; private boolean topLevel = true; private Expression body; private int varCounter; private List<String> dataverses = new ArrayList<>(); private List<String> datasets = new ArrayList<>(); - public Query() { - // Default constructor. + public Query(boolean explain) { + this.explain = explain; } - public Query(boolean topLevel, Expression body, int varCounter, List<String> dataverses, List<String> datasets) { + public Query(boolean explain, boolean topLevel, Expression body, int varCounter, List<String> dataverses, + List<String> datasets) { + this.explain = explain; this.topLevel = topLevel; this.body = body; this.varCounter = varCounter; @@ -70,6 +73,10 @@ return topLevel; } + public boolean isExplain() { + return explain; + } + @Override public byte getKind() { return Statement.Kind.QUERY; @@ -98,7 +105,7 @@ @Override public int hashCode() { - return ObjectUtils.hashCodeMulti(body, datasets, dataverses, topLevel); + return ObjectUtils.hashCodeMulti(body, datasets, dataverses, topLevel, explain); } @Override @@ -110,7 +117,8 @@ return false; } Query target = (Query) object; - return ObjectUtils.equals(body, target.body) && ObjectUtils.equals(datasets, target.datasets) - && ObjectUtils.equals(dataverses, target.dataverses) && topLevel == target.topLevel; + return explain == target.explain && ObjectUtils.equals(body, target.body) + && ObjectUtils.equals(datasets, target.datasets) && ObjectUtils.equals(dataverses, target.dataverses) + && topLevel == target.topLevel; } } diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java index 159af9f..f79f811 100644 --- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java +++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java @@ -307,7 +307,7 @@ } protected Expression rewriteFunctionBody(Expression expr) throws AsterixException { - Query wrappedQuery = new Query(); + Query wrappedQuery = new Query(false); wrappedQuery.setBody(expr); wrappedQuery.setTopLevel(false); IQueryRewriter queryRewriter = rewriterFactory.createQueryRewriter(); diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java index 667878c..9ffcf8d 100644 --- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java +++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java @@ -235,7 +235,7 @@ @Override public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(Query q, VariableSubstitutionEnvironment env) throws AsterixException { - Query newQ = new Query(); + Query newQ = new Query(q.isExplain()); Pair<ILangExpression, VariableSubstitutionEnvironment> p1 = q.getBody().accept(this, env); newQ.setBody((Expression) p1.first); return new Pair<>(newQ, p1.second); diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java index 01f3524..d752396 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java @@ -229,7 +229,7 @@ @Override public Query visit(Query q, Void arg) throws AsterixException { - return new Query(q.isTopLevel(), (Expression) q.getBody().accept(this, arg), q.getVarCounter(), + return new Query(q.isExplain(), q.isTopLevel(), (Expression) q.getBody().accept(this, arg), q.getVarCounter(), q.getDataverses(), q.getDatasets()); } diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java index bfb1e44..a71cc47 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java @@ -84,7 +84,7 @@ SelectBlock selectBlock = new SelectBlock(selectClause, fromClause, null, whereClause, null, null, null); SelectSetOperation selectSetOperation = new SelectSetOperation(new SetOperationInput(selectBlock, null), null); SelectExpression selectExpression = new SelectExpression(null, selectSetOperation, null, null, false); - Query query = new Query(false, selectExpression, 0, new ArrayList<>(), new ArrayList<>()); + Query query = new Query(false, false, selectExpression, 0, new ArrayList<>(), new ArrayList<>()); query.setBody(selectExpression); // return the delete statement. diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj index afc970a..8f9a201 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj +++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj @@ -316,7 +316,8 @@ | stmt = UpdateStatement() | stmt = FeedStatement() | stmt = CompactStatement() - | stmt = Query() <SEMICOLON> + | stmt = ExplainStatement() + | stmt = Query(false) <SEMICOLON> | stmt = RefreshExternalDatasetStatement() | stmt = RunStatement() ) @@ -925,7 +926,7 @@ Query query; } { - <INSERT> <INTO> nameComponents = QualifiedName() query = Query() + <INSERT> <INTO> nameComponents = QualifiedName() query = Query(false) { query.setTopLevel(true); return new InsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter()); @@ -1562,10 +1563,20 @@ } } - -Query Query() throws ParseException: +Query ExplainStatement() throws ParseException: { - Query query = new Query(); + Query query; +} +{ + "explain" query = Query(true) + { + return query; + } +} + +Query Query(boolean explain) throws ParseException: +{ + Query query = new Query(explain); // we set the pointers to the dataverses and datasets lists to fill them with entities to be locked setDataverses(query.getDataverses()); setDatasets(query.getDatasets()); diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java index 7c749ed..fe8e044 100644 --- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java +++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java @@ -142,7 +142,7 @@ @Override public Void visitDistinctOperator(DistinctOperator op, Integer indent) throws AlgebricksException { - addIndent(indent).append("distinct " + "("); + addIndent(indent).append("distinct ("); pprintExprList(op.getExpressions(), indent); buffer.append(")"); return null; @@ -177,7 +177,6 @@ } String fst = getOrderString(p.first); buffer.append("(" + fst + ", " + p.second.getValue().accept(exprVisitor, indent) + ") "); - } return null; } @@ -346,7 +345,7 @@ @Override public Void visitExchangeOperator(ExchangeOperator op, Integer indent) throws AlgebricksException { - addIndent(indent).append("exchange "); + addIndent(indent).append("exchange"); return null; } @@ -358,13 +357,13 @@ @Override public Void visitReplicateOperator(ReplicateOperator op, Integer indent) throws AlgebricksException { - addIndent(indent).append("replicate "); + addIndent(indent).append("replicate"); return null; } @Override public Void visitMaterializeOperator(MaterializeOperator op, Integer indent) throws AlgebricksException { - addIndent(indent).append("materialize "); + addIndent(indent).append("materialize"); return null; } -- To view, visit https://asterix-gerrit.ics.uci.edu/1020 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-MessageType: merged Gerrit-Change-Id: I7b7028fb243d494150cac525c73b2d77b0068646 Gerrit-PatchSet: 9 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: Till Westmann <[email protected]> Gerrit-Reviewer: Jenkins <[email protected]> Gerrit-Reviewer: Till Westmann <[email protected]> Gerrit-Reviewer: Yingyi Bu <[email protected]>
