[email protected] has uploaded a new change for review. https://asterix-gerrit.ics.uci.edu/3076
Change subject: review comments -- mid fix; ParseValueParser approach to be modified. ...................................................................... review comments -- mid fix; ParseValueParser approach to be modified. Change-Id: Icd4e434c0f00a1855578046ff42e6a387d884936 --- D asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ParseValuesJsonPrintUtils.java M asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java M asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ResultUtil.java M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_parseonly.xml M asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java M asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java R asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseOnlyResult.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseValueParser.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java 9 files changed, 121 insertions(+), 186 deletions(-) git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb refs/changes/76/3076/1 diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ParseValuesJsonPrintUtils.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ParseValuesJsonPrintUtils.java deleted file mode 100644 index 4d41e86..0000000 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ParseValuesJsonPrintUtils.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.api.http.server; - -import org.apache.asterix.lang.sqlpp.parser.ParseValues; -import org.apache.asterix.translator.SessionConfig; -import org.apache.hyracks.util.JSONUtil; - -public class ParseValuesJsonPrintUtils { - - private static final String EXTERNAL_VARIABLE_LBL = "statement-parameters"; - - public static String asJson(ParseValues parseValues) { - final StringBuilder output = new StringBuilder(); - appendOutputPrefix(output); - appendNonNull(output, EXTERNAL_VARIABLE_LBL, parseValues.toStringDebug()); - appendOutputPostfix(output); - return output.toString(); - } - - private static void appendNonNull(StringBuilder builder, String lbl, String value) { - //TODO: The format is string. Should we use JSON? - - SessionConfig.PlanFormat format = SessionConfig.PlanFormat.STRING; - - if (value != null) { - printFieldPrefix(builder, lbl); - switch (format) { - case JSON: - //TODO: No support for JSON currently. - break; - case STRING: - JSONUtil.quoteAndEscape(builder, value); - break; - default: - throw new IllegalStateException("Unrecognized plan format: " + format); - } - printFieldPostfix(builder); - } - } - - //TODO: Refactor to remove code duplication from ExecutionPlansJsonPrintUtil - private static void appendOutputPrefix(StringBuilder builder) { - builder.append("{"); - } - - private static void printFieldPrefix(StringBuilder builder, String lbl) { - builder.append("\"" + lbl + "\": "); - } - - private static void printFieldPostfix(StringBuilder builder) { - builder.append(","); - } - - private static void appendOutputPostfix(StringBuilder builder) { - // remove extra comma if needed - if (builder.length() > 1) { - builder.deleteCharAt(builder.length() - 1); - } - builder.append("}"); - } - -} 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 41cc69d..707590a 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 @@ -47,6 +47,7 @@ import org.apache.asterix.lang.common.base.IParser; import org.apache.asterix.lang.common.base.IParserFactory; import org.apache.asterix.lang.common.base.Statement; +import org.apache.asterix.lang.sqlpp.parser.ParseOnlyResult; import org.apache.asterix.metadata.MetadataManager; import org.apache.asterix.om.base.IAObject; import org.apache.asterix.translator.*; @@ -64,7 +65,6 @@ import org.apache.logging.log4j.Logger; import org.apache.asterix.lang.sqlpp.parser.ParseValueParser; -import org.apache.asterix.lang.sqlpp.parser.ParseValues; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; @@ -532,97 +532,63 @@ long errorCount = 1; // so far we just return 1 error List<ExecutionWarning> warnings = Collections.emptyList(); // we don't have any warnings yet - if (param.getStatement() == null || param.getStatement().isEmpty()) { - throw new RuntimeDataException(ErrorCode.NO_STATEMENT_PROVIDED); - } //TODO: moved this out of try-catch block. - - String statementsText = param.getStatement() + ";"; - RequestExecutionState execution = new RequestExecutionState(); - if (param.isParseOnly()) { - try { - ParseValues parseValues = parseStatement(statementsText); //is cousin of executeStatement + try { + if (param.getStatement() == null || param.getStatement().isEmpty()) { + throw new RuntimeDataException(ErrorCode.NO_STATEMENT_PROVIDED); + } //TODO: moved this out of try-catch block. + + String statementsText = param.getStatement() + ";"; + + Map<String, String> optionalParams = null; + if (optionalParamProvider != null) { + optionalParams = optionalParamProvider.apply(request); + } + if (param.isParseOnly()) { + ParseOnlyResult parseOnlyResult = parseStatement(statementsText); //is cousin of executeStatement + response.setStatus(HttpResponseStatus.OK); // CORS if (request.getHeader("Origin") != null) { response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); } response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); - - response.setStatus(HttpResponseStatus.OK); - if (ResultDelivery.IMMEDIATE == delivery || ResultDelivery.DEFERRED == delivery) { - ResultUtil.printStatus(sessionOutput, execution.getResultStatus()); - } - if (!warnings.isEmpty()) { - printWarnings(sessionOutput.out(), warnings); - } - errorCount = 0; - printParseValues(sessionOutput, parseValues); - - } catch (Exception | TokenMgrError | org.apache.asterix.aqlplus.parser.TokenMgrError e) { - //TODO: figure out what to do with compilation error - //TODO: invoke the already backed exception handling - if (LOGGER.isDebugEnabled()) { - - LOGGER.debug("handleException: {}: {}", e.getMessage(), param, e); - } else { - LOGGER.info("handleException: {}: {}", e.getMessage(), param); - //sessionOutput.out() - // .print(e.getMessage() + ";" + e.getLocalizedMessage() + ";" + e.getSourceLocation()); - } - handleExecuteStatementException(e, execution, param); //hope this is generic enough to do its thing. - response.setStatus(execution.getHttpStatus()); - printError(sessionOutput.out(), e); - ResultUtil.printStatus(sessionOutput, execution.getResultStatus()); - if (!warnings.isEmpty()) { - printWarnings(sessionOutput.out(), warnings); - } - - } finally { - // make sure that we stop buffering and return the result to the http response - sessionOutput.release(); - - } - //printMetrics(sessionOutput.out(), System.nanoTime() - elapsedStart, execution.duration(), stats.getCount(), - // stats.getSize(), stats.getProcessedObjects(), errorCount, warnings.size()); - - } else { - - try { - Map<String, String> optionalParams = null; - if (optionalParamProvider != null) { - optionalParams = optionalParamProvider.apply(request); - } + printParseValues(sessionOutput, parseOnlyResult); + } else { Map<String, byte[]> statementParams = org.apache.asterix.app.translator.RequestParameters .serializeParameterValues(param.getStatementParams()); + // CORS if (request.getHeader("Origin") != null) { response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); } response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); response.setStatus(execution.getHttpStatus()); + executeStatement(statementsText, sessionOutput, resultProperties, stats, param, execution, optionalParams, statementParams); if (ResultDelivery.IMMEDIATE == delivery || ResultDelivery.DEFERRED == delivery) { ResultUtil.printStatus(sessionOutput, execution.getResultStatus()); } - if (!warnings.isEmpty()) { - printWarnings(sessionOutput.out(), warnings); - } - errorCount = 0; - - } catch (Exception | TokenMgrError | org.apache.asterix.aqlplus.parser.TokenMgrError e) { - handleExecuteStatementException(e, execution, param); - response.setStatus(execution.getHttpStatus()); - printError(sessionOutput.out(), e); - ResultUtil.printStatus(sessionOutput, execution.getResultStatus()); - } finally { - // make sure that we stop buffering and return the result to the http response - sessionOutput.release(); - execution.finish(); } + if (!warnings.isEmpty()) { + printWarnings(sessionOutput.out(), warnings); + } + + errorCount = 0; + + } catch (Exception | TokenMgrError | org.apache.asterix.aqlplus.parser.TokenMgrError e) { + handleExecuteStatementException(e, execution, param); + response.setStatus(execution.getHttpStatus()); + printError(sessionOutput.out(), e); + ResultUtil.printStatus(sessionOutput, execution.getResultStatus()); + } finally { + // make sure that we stop buffering and return the result to the http response + sessionOutput.release(); + execution.finish(); + } + if (!param.isParseOnly()) { printMetrics(sessionOutput.out(), System.nanoTime() - elapsedStart, execution.duration(), stats.getCount(), stats.getSize(), stats.getProcessedObjects(), errorCount, warnings.size()); - } sessionOutput.out().print("}\n"); sessionOutput.out().flush(); @@ -631,19 +597,11 @@ } } - protected ParseValues parseStatement(String statementsText) throws Exception { - //assert (param.isMultiStatement() == false); - try { - //IParser parser = compilationProvider.getParserFactory().createParser(statementsText); - IParserFactory factory = compilationProvider.getParserFactory(); - ParseValueParser parser = new ParseValueParser(factory, statementsText); - parser.parse(); - return parser.getParseValues(); - - } catch (Exception ce) { - throw ce; - } - + protected ParseOnlyResult parseStatement(String statementsText) throws Exception { + IParserFactory factory = compilationProvider.getParserFactory(); + ParseValueParser parser = new ParseValueParser(factory, statementsText); + parser.parse(); + return parser.getParseOnlyResult(); } protected void executeStatement(String statementsText, SessionOutput sessionOutput, @@ -716,13 +674,13 @@ ResultUtil.printWarnings(pw, warnings); } - protected void printParseValues(SessionOutput output, ParseValues parseValues) { + protected void printParseValues(SessionOutput output, ParseOnlyResult parseOnlyResult) { final PrintWriter pw = output.out(); pw.print("\t\""); pw.print(ResultFields.PARSEVALS.str()); pw.print("\":"); - pw.print(ParseValuesJsonPrintUtils.asJson(parseValues)); + pw.print(ResultUtil.ParseValuesJsonPrintUtils.asJson(parseOnlyResult)); //pw.print(",\n"); //TODO: comma or no comma pw.print("\n"); //TODO: comma or no comma diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ResultUtil.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ResultUtil.java index 8824f6a..a6d057b 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ResultUtil.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ResultUtil.java @@ -35,6 +35,7 @@ import org.apache.asterix.app.result.ResultReader; import org.apache.asterix.common.api.IApplicationContext; import org.apache.asterix.lang.aql.parser.TokenMgrError; +import org.apache.asterix.lang.sqlpp.parser.ParseOnlyResult; import org.apache.asterix.om.types.ARecordType; import org.apache.asterix.translator.IStatementExecutor.Stats; import org.apache.asterix.translator.SessionOutput; @@ -379,4 +380,47 @@ return (app, status) -> app.append("\t\"").append(AbstractQueryApiServlet.ResultFields.STATUS.str()) .append("\": \"").append(status).append("\",\n"); } + + public static class ParseValuesJsonPrintUtils { + + private static final String EXTERNAL_VARIABLE_LBL = "statement-parameters"; + + public static String asJson(ParseOnlyResult parseOnlyResult) { + final StringBuilder output = new StringBuilder(); + appendOutputPrefix(output); + appendNonNull(output, EXTERNAL_VARIABLE_LBL, parseOnlyResult.toStringDebug()); + appendOutputPostfix(output); + return output.toString(); + } + + private static void appendNonNull(StringBuilder builder, String lbl, String value) { + if (value != null) { + printFieldPrefix(builder, lbl); + JSONUtil.quoteAndEscape(builder, value); + printFieldPostfix(builder); + } + } + + //TODO: Refactor to remove code duplication from ExecutionPlansJsonPrintUtil + private static void appendOutputPrefix(StringBuilder builder) { + builder.append("{"); + } + + private static void printFieldPrefix(StringBuilder builder, String lbl) { + builder.append("\"" + lbl + "\": "); + } + + private static void printFieldPostfix(StringBuilder builder) { + builder.append(","); + } + + private static void appendOutputPostfix(StringBuilder builder) { + // remove extra comma if needed + if (builder.length() > 1) { + builder.deleteCharAt(builder.length() - 1); + } + builder.append("}"); + } + + } } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_parseonly.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_parseonly.xml index 35ba883..d443a9f 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_parseonly.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_parseonly.xml @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> <!-- ! Licensed to the Apache Software Foundation (ASF) under one ! or more contributor license agreements. See the NOTICE file @@ -16,8 +17,6 @@ ! specific language governing permissions and limitations ! under the License. !--> - -<?xml version="1.0" encoding="UTF-8"?> <test-suite xmlns="urn:xml.testframework.asterix.apache.org" ResultOffsetPath="results" QueryOffsetPath="queries" QueryFileExtension=".sqlpp"> <test-group name="parseonly"> diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java index 967fdae..85f19ad 100644 --- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java +++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java @@ -140,6 +140,11 @@ return gfc.getCalls(); } + @Override + Set<VariableExpr> getFreeVariables(Expression expr) { + throw new UnsupportedOperationException("getFreeVariables not implemented for AQL"); + } + private static class GatherFunctionCalls extends GatherFunctionCallsVisitor implements IAQLVisitor<Void, Void> { public GatherFunctionCalls() { diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java index 8f3b8a9..0c42e40 100644 --- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java +++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java @@ -24,6 +24,7 @@ import org.apache.asterix.common.exceptions.CompilationException; import org.apache.asterix.lang.common.expression.CallExpr; +import org.apache.asterix.lang.common.expression.VariableExpr; import org.apache.asterix.lang.common.rewrites.LangRewritingContext; import org.apache.asterix.lang.common.statement.FunctionDecl; import org.apache.asterix.lang.common.struct.VarIdentifier; @@ -52,5 +53,7 @@ * Find the function calls used by a given expression */ Set<CallExpr> getFunctionCalls(Expression expression) throws CompilationException; + Set<VariableExpr> getFreeVariables(Expression expr) throws CompilationException; + } diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseValues.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseOnlyResult.java similarity index 94% rename from asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseValues.java rename to asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseOnlyResult.java index 266e7d2..6b356d6 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseValues.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseOnlyResult.java @@ -22,10 +22,9 @@ import org.apache.asterix.lang.common.expression.VariableExpr; import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil; -import java.io.Serializable; import java.util.Set; -public class ParseValues implements Serializable { +public class ParseOnlyResult { private Set<VariableExpr> externalVariables; private String extVarsSerialized; diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseValueParser.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseValueParser.java index 14770b4..e765e83 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseValueParser.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/ParseValueParser.java @@ -25,15 +25,17 @@ import org.apache.asterix.lang.common.base.IParserFactory; import org.apache.asterix.lang.common.base.Statement; import org.apache.asterix.lang.common.expression.VariableExpr; -import org.apache.asterix.lang.sqlpp.visitor.NamedParameterVisitor; +import org.apache.asterix.lang.sqlpp.visitor.FreeVariableVisitor; +import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppQueryExpressionVisitor; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; public class ParseValueParser { private final IParserFactory parserFactory; - private final ParseValues parseValues; + private final ParseOnlyResult parseOnlyResult; private final Set<VariableExpr> extVars; private final String statementsText; private IParser parser; @@ -42,29 +44,25 @@ this.statementsText = statementsText; this.parserFactory = parserFactory; this.extVars = new HashSet<>(); - this.parseValues = new ParseValues(); + this.parseOnlyResult = new ParseOnlyResult(); } public List<Statement> parse() throws CompilationException { parser = parserFactory.createParser(statementsText); List<Statement> statements = parser.parse(); - NamedParameterVisitor erv = new NamedParameterVisitor(); + AbstractSqlppQueryExpressionVisitor<Void, Collection<VariableExpr>> frv = new FreeVariableVisitor(); + //NamedParameterVisitor erv = new NamedParameterVisitor(); for (Statement st : statements) { - st.accept(erv, extVars); + st.accept(frv, extVars); } - parseValues.setExternalVariables(extVars); + parseOnlyResult.setExternalVariables(extVars); return statements; } - public ParseValues getParseValues() { - return parseValues; - } - - public String toStringDebug() { - return parseValues.toStringDebug(); - + public ParseOnlyResult getParseOnlyResult() { + return parseOnlyResult; } } 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 5aa5a8c..030c3bf 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 @@ -18,10 +18,7 @@ */ package org.apache.asterix.lang.sqlpp.rewrites; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; +import java.util.*; import org.apache.asterix.common.exceptions.CompilationException; import org.apache.asterix.common.functions.FunctionSignature; @@ -30,6 +27,7 @@ import org.apache.asterix.lang.common.base.IReturningStatement; import org.apache.asterix.lang.common.clause.LetClause; import org.apache.asterix.lang.common.expression.CallExpr; +import org.apache.asterix.lang.common.expression.VariableExpr; import org.apache.asterix.lang.common.rewrites.LangRewritingContext; import org.apache.asterix.lang.common.statement.FunctionDecl; import org.apache.asterix.lang.common.struct.VarIdentifier; @@ -68,6 +66,8 @@ import org.apache.asterix.lang.sqlpp.rewrites.visitor.VariableCheckAndRewriteVisitor; import org.apache.asterix.lang.sqlpp.struct.SetOperationRight; import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil; +import org.apache.asterix.lang.sqlpp.visitor.FreeVariableVisitor; +import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppQueryExpressionVisitor; import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor; import org.apache.asterix.metadata.declared.MetadataProvider; @@ -251,6 +251,15 @@ return gfc.getCalls(); } + @Override + public Set<VariableExpr> getFreeVariables(Expression expr) throws CompilationException + { + Set<VariableExpr> extVars = new HashSet<>(); //TODO: memory alloc within function? + AbstractSqlppQueryExpressionVisitor<Void, Collection<VariableExpr>> frv = new FreeVariableVisitor(); + expr.accept(frv, extVars); + return extVars; + } + private static class GatherFunctionCalls extends GatherFunctionCallsVisitor implements ISqlppVisitor<Void, Void> { public GatherFunctionCalls() { -- To view, visit https://asterix-gerrit.ics.uci.edu/3076 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Icd4e434c0f00a1855578046ff42e6a387d884936 Gerrit-PatchSet: 1 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: [email protected]
