[ASTERIXDB-2401][SQLPP] Support parameterized queries
- user model changes: yes
- storage format changes: no
- interface changes: yes
Details:
- Support statement parameters: named ($name) and positional ($1 or ?)
- Enhance query service API to accept these parameters in the request
- Remove [?] index accessor from SQL++ grammar because it conflicts
with positional parameters ([0] can be used instead)
- Add testcases for parameterized queries
Change-Id: Ia612f731cd2370fccd54c4796bd9787fbea16766
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2707
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/base/ILangExpressionToPlanTranslatorFactory.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/base/ILangExpressionToPlanTranslatorFactory.java
index 5db516e..c29dee8 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/base/ILangExpressionToPlanTranslatorFactory.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/base/ILangExpressionToPlanTranslatorFactory.java
@@ -18,7 +18,11 @@
*/
package org.apache.asterix.algebra.base;
+import java.util.Map;
+
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.om.base.IAObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
public interface ILangExpressionToPlanTranslatorFactory {
@@ -28,10 +32,11 @@
* providing the definition of created (i.e., stored) user-defined functions.
* @param currentVarCounter,
* the current minimum available variable id.
+ * @param externalVars
* @return a logical query plan.
* @throws AlgebricksException
*/
ILangExpressionToPlanTranslator createExpressionToPlanTranslator(MetadataProvider metadataProvider,
- int currentVarCountert) throws AlgebricksException;
+ int currentVarCounter, Map<VarIdentifier, IAObject> externalVars) throws AlgebricksException;
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/AqlCompilationProvider.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/AqlCompilationProvider.java
index af0ba73..548917a 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/AqlCompilationProvider.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/AqlCompilationProvider.java
@@ -19,6 +19,7 @@
package org.apache.asterix.compiler.provider;
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslatorFactory;
+import org.apache.asterix.algebra.base.ILangExtension;
import org.apache.asterix.lang.aql.parser.AQLParserFactory;
import org.apache.asterix.lang.aql.rewrites.AQLRewriterFactory;
import org.apache.asterix.lang.aql.visitor.AQLAstPrintVisitorFactory;
@@ -30,6 +31,11 @@
public class AqlCompilationProvider implements ILangCompilationProvider {
@Override
+ public ILangExtension.Language getLanguage() {
+ return ILangExtension.Language.AQL;
+ }
+
+ @Override
public IParserFactory getParserFactory() {
return new AQLParserFactory();
}
@@ -53,5 +59,4 @@
public IRuleSetFactory getRuleSetFactory() {
return new DefaultRuleSetFactory();
}
-
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/ILangCompilationProvider.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/ILangCompilationProvider.java
index f658be9..f625343 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/ILangCompilationProvider.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/ILangCompilationProvider.java
@@ -19,35 +19,39 @@
package org.apache.asterix.compiler.provider;
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslatorFactory;
+import org.apache.asterix.algebra.base.ILangExtension;
import org.apache.asterix.lang.common.base.IAstPrintVisitorFactory;
import org.apache.asterix.lang.common.base.IParserFactory;
import org.apache.asterix.lang.common.base.IRewriterFactory;
public interface ILangCompilationProvider {
+ /**
+ * @return language kind
+ */
+ ILangExtension.Language getLanguage();
/**
* @return the parser factory of a language implementation.
*/
- public IParserFactory getParserFactory();
+ IParserFactory getParserFactory();
/**
* @return the rewriter factory of a language implementation.
*/
- public IRewriterFactory getRewriterFactory();
+ IRewriterFactory getRewriterFactory();
/**
* @return the AST printer factory of a language implementation.
*/
- public IAstPrintVisitorFactory getAstPrintVisitorFactory();
+ IAstPrintVisitorFactory getAstPrintVisitorFactory();
/**
* @return the language expression to logical query plan translator factory of a language implementation.
*/
- public ILangExpressionToPlanTranslatorFactory getExpressionToPlanTranslatorFactory();
+ ILangExpressionToPlanTranslatorFactory getExpressionToPlanTranslatorFactory();
/**
* @return the rule set factory of a language implementation
*/
- public IRuleSetFactory getRuleSetFactory();
-
+ IRuleSetFactory getRuleSetFactory();
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
index 70f8f92..6451b6f 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
@@ -19,6 +19,7 @@
package org.apache.asterix.compiler.provider;
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslatorFactory;
+import org.apache.asterix.algebra.base.ILangExtension;
import org.apache.asterix.lang.common.base.IAstPrintVisitorFactory;
import org.apache.asterix.lang.common.base.IParserFactory;
import org.apache.asterix.lang.common.base.IRewriterFactory;
@@ -30,6 +31,11 @@
public class SqlppCompilationProvider implements ILangCompilationProvider {
@Override
+ public ILangExtension.Language getLanguage() {
+ return ILangExtension.Language.SQLPP;
+ }
+
+ @Override
public IParserFactory getParserFactory() {
return new SqlppParserFactory();
}
@@ -53,5 +59,4 @@
public IRuleSetFactory getRuleSetFactory() {
return new DefaultRuleSetFactory();
}
-
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AqlExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AqlExpressionToPlanTranslator.java
index e777c4e..6a173db 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AqlExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AqlExpressionToPlanTranslator.java
@@ -20,6 +20,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslator;
import org.apache.asterix.common.exceptions.CompilationException;
@@ -34,7 +35,9 @@
import org.apache.asterix.lang.common.base.ILangExpression;
import org.apache.asterix.lang.common.expression.VariableExpr;
import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.om.types.BuiltinType;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AqlExpressionToPlanTranslatorFactory.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AqlExpressionToPlanTranslatorFactory.java
index a3e9d74..911c443 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AqlExpressionToPlanTranslatorFactory.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/AqlExpressionToPlanTranslatorFactory.java
@@ -18,16 +18,20 @@
*/
package org.apache.asterix.translator;
+import java.util.Map;
+
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslator;
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslatorFactory;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.om.base.IAObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
public class AqlExpressionToPlanTranslatorFactory implements ILangExpressionToPlanTranslatorFactory {
@Override
public ILangExpressionToPlanTranslator createExpressionToPlanTranslator(MetadataProvider metadataProvider,
- int currentVarCounter) throws AlgebricksException {
+ int currentVarCounter, Map<VarIdentifier, IAObject> externalVars) throws AlgebricksException {
return new AqlExpressionToPlanTranslator(metadataProvider, currentVarCounter);
}
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 a1fbac6..d58d761 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
@@ -20,6 +20,7 @@
import java.util.Map;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.translator.IStatementExecutor.Stats;
import org.apache.hyracks.api.dataset.IHyracksDataset;
@@ -56,4 +57,9 @@
* @return Optional request parameters. Otherwise null.
*/
Map<String, String> getOptionalParameters();
+
+ /**
+ * @return Statement parameters
+ */
+ Map<String, IAObject> getStatementParameters();
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IStatementExecutor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IStatementExecutor.java
index 0ff877b..fa967f5 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IStatementExecutor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/IStatementExecutor.java
@@ -22,11 +22,14 @@
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.apache.asterix.common.exceptions.ACIDException;
import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.IStatementRewriter;
import org.apache.asterix.lang.common.statement.Query;
import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.translator.CompiledStatements.ICompiledDmlStatement;
import org.apache.commons.lang3.tuple.Triple;
@@ -123,6 +126,9 @@
* The query to be compiled
* @param dmlStatement
* The data modification statement when the query results in a modification to a dataset
+ * @param statementParameters
+ * Statement parameters
+ * @param statementRewriter
* @return the compiled {@code JobSpecification}
* @throws AsterixException
* @throws RemoteException
@@ -130,7 +136,8 @@
* @throws ACIDException
*/
JobSpecification rewriteCompileQuery(IClusterInfoCollector clusterInfoCollector, MetadataProvider metadataProvider,
- Query query, ICompiledDmlStatement dmlStatement) throws RemoteException, AlgebricksException, ACIDException;
+ Query query, ICompiledDmlStatement dmlStatement, Map<String, IAObject> statementParameters,
+ IStatementRewriter statementRewriter) throws RemoteException, AlgebricksException, ACIDException;
/**
* returns the active dataverse for an entity or a statement
@@ -148,5 +155,4 @@
* @return the executions plans
*/
ExecutionPlans getExecutionPlans();
-
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index 0c46383..18a6597 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -679,10 +679,9 @@
Expression bindingExpr = lc.getBindingExpr();
SourceLocation sourceLoc = bindingExpr.getSourceLocation();
if (bindingExpr.getKind() == Kind.VARIABLE_EXPRESSION) {
+ VariableExpr bindingVarExpr = (VariableExpr) bindingExpr;
+ ILogicalExpression prevVarRef = translateVariableRef(bindingVarExpr);
v = context.newVarFromExpression(lc.getVarExpr());
- LogicalVariable prevVar = context.getVar(((VariableExpr) bindingExpr).getVar().getId());
- VariableReferenceExpression prevVarRef = new VariableReferenceExpression(prevVar);
- prevVarRef.setSourceLocation(sourceLoc);
returnedOp = new AssignOperator(v, new MutableObject<>(prevVarRef));
returnedOp.getInputs().add(tupSource);
returnedOp.setSourceLocation(sourceLoc);
@@ -753,10 +752,8 @@
switch (expr.getKind()) {
case VARIABLE_EXPRESSION:
VariableExpr varExpr = (VariableExpr) expr;
- LogicalVariable var = context.getVar(varExpr.getVar().getId());
- VariableReferenceExpression varRef = new VariableReferenceExpression(var);
- varRef.setSourceLocation(varExpr.getSourceLocation());
- args.add(new MutableObject<>(varRef));
+ ILogicalExpression varRefExpr = translateVariableRef(varExpr);
+ args.add(new MutableObject<>(varRefExpr));
break;
case LITERAL_EXPRESSION:
LiteralExpr val = (LiteralExpr) expr;
@@ -801,6 +798,17 @@
return new Pair<>(op, v);
}
+ protected ILogicalExpression translateVariableRef(VariableExpr varExpr) throws CompilationException {
+ LogicalVariable var = context.getVar(varExpr.getVar().getId());
+ if (var == null) {
+ throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, varExpr.getSourceLocation(),
+ varExpr.toString());
+ }
+ VariableReferenceExpression varRef = new VariableReferenceExpression(var);
+ varRef.setSourceLocation(varExpr.getSourceLocation());
+ return varRef;
+ }
+
private AbstractFunctionCallExpression lookupUserDefinedFunction(FunctionSignature signature,
List<Mutable<ILogicalExpression>> args, SourceLocation sourceLoc) throws CompilationException {
try {
@@ -1326,16 +1334,14 @@
}
@Override
- public Pair<ILogicalOperator, LogicalVariable> visit(VariableExpr v, Mutable<ILogicalOperator> tupSource) {
- SourceLocation sourceLoc = v.getSourceLocation();
+ public Pair<ILogicalOperator, LogicalVariable> visit(VariableExpr v, Mutable<ILogicalOperator> tupSource)
+ throws CompilationException {
// Should we ever get to this method?
+ ILogicalExpression oldVRef = translateVariableRef(v);
LogicalVariable var = context.newVar();
- LogicalVariable oldV = context.getVar(v.getVar().getId());
- VariableReferenceExpression oldVRef = new VariableReferenceExpression(oldV);
- oldVRef.setSourceLocation(sourceLoc);
AssignOperator a = new AssignOperator(var, new MutableObject<>(oldVRef));
a.getInputs().add(tupSource);
- a.setSourceLocation(sourceLoc);
+ a.setSourceLocation(v.getSourceLocation());
return new Pair<>(a, var);
}
@@ -1452,13 +1458,9 @@
SourceLocation sourceLoc = expr.getSourceLocation();
switch (expr.getKind()) {
case VARIABLE_EXPRESSION:
- LogicalVariable var = context.getVar(((VariableExpr) expr).getVar().getId());
- if (var == null) {
- throw new IllegalStateException(String.valueOf(expr));
- }
- VariableReferenceExpression ve = new VariableReferenceExpression(var);
- ve.setSourceLocation(sourceLoc);
- return new Pair<>(ve, topOpRef);
+ VariableExpr varExpr = (VariableExpr) expr;
+ ILogicalExpression varRefExpr = translateVariableRef(varExpr);
+ return new Pair<>(varRefExpr, topOpRef);
case LITERAL_EXPRESSION:
LiteralExpr val = (LiteralExpr) expr;
return new Pair<>(new ConstantExpression(
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
index 5c7b165..3954135 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
@@ -23,6 +23,7 @@
import java.util.Collections;
import java.util.Deque;
import java.util.List;
+import java.util.Map;
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslator;
import org.apache.asterix.common.exceptions.CompilationException;
@@ -42,6 +43,7 @@
import org.apache.asterix.lang.common.expression.VariableExpr;
import org.apache.asterix.lang.common.literal.StringLiteral;
import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.lang.common.util.FunctionUtil;
import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
import org.apache.asterix.lang.sqlpp.clause.FromClause;
@@ -67,10 +69,14 @@
import org.apache.asterix.metadata.declared.MetadataProvider;
import org.apache.asterix.om.base.ABoolean;
import org.apache.asterix.om.base.AInt32;
+import org.apache.asterix.om.base.AMissing;
import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.om.constants.AsterixConstantValue;
import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.typecomputer.base.TypeCastUtils;
import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -113,10 +119,12 @@
ISqlppVisitor<Pair<ILogicalOperator, LogicalVariable>, Mutable<ILogicalOperator>> {
private static final String ERR_MSG = "Translator should never enter this method!";
private Deque<Mutable<ILogicalOperator>> uncorrelatedLeftBranchStack = new ArrayDeque<>();
+ private final Map<VarIdentifier, IAObject> externalVars;
- public SqlppExpressionToPlanTranslator(MetadataProvider metadataProvider, int currentVarCounter)
- throws AlgebricksException {
+ public SqlppExpressionToPlanTranslator(MetadataProvider metadataProvider, int currentVarCounter,
+ Map<VarIdentifier, IAObject> externalVars) throws AlgebricksException {
super(metadataProvider, currentVarCounter);
+ this.externalVars = externalVars != null ? externalVars : Collections.emptyMap();
}
@Override
@@ -621,6 +629,38 @@
return new Pair<>(finalAssignOp, resultVar);
}
+ @Override
+ protected ILogicalExpression translateVariableRef(VariableExpr varExpr) throws CompilationException {
+ VarIdentifier varId = varExpr.getVar();
+ if (SqlppVariableUtil.isExternalVariableIdentifier(varId)) {
+ IAObject value = externalVars.get(varId);
+ SourceLocation sourceLoc = varExpr.getSourceLocation();
+ if (value == null) {
+ throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc, varId.toString());
+ }
+
+ ILogicalExpression resultExpr;
+ ConstantExpression constExpr = new ConstantExpression(new AsterixConstantValue(value));
+ constExpr.setSourceLocation(sourceLoc);
+ resultExpr = constExpr;
+
+ IAType valueType = value.getType();
+ if (valueType.getTypeTag().isDerivedType()) {
+ ScalarFunctionCallExpression castExpr =
+ new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CAST_TYPE));
+ castExpr.setSourceLocation(sourceLoc);
+ // The first argument is the field
+ castExpr.getArguments().add(new MutableObject<>(resultExpr));
+ TypeCastUtils.setRequiredAndInputTypes(castExpr, BuiltinType.ANY, valueType);
+ resultExpr = castExpr;
+ }
+
+ return resultExpr;
+ }
+
+ return super.translateVariableRef(varExpr);
+ }
+
private Pair<ILogicalOperator, LogicalVariable> produceSelectPlan(boolean isSubquery,
Mutable<ILogicalOperator> returnOpRef, LogicalVariable resVar) {
if (isSubquery) {
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslatorFactory.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslatorFactory.java
index 49c088f..65d90ae 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslatorFactory.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslatorFactory.java
@@ -18,17 +18,21 @@
*/
package org.apache.asterix.translator;
+import java.util.Map;
+
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslator;
import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslatorFactory;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.om.base.IAObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
public class SqlppExpressionToPlanTranslatorFactory implements ILangExpressionToPlanTranslatorFactory {
@Override
public ILangExpressionToPlanTranslator createExpressionToPlanTranslator(MetadataProvider metadataProvider,
- int currentVarCounter) throws AlgebricksException {
- return new SqlppExpressionToPlanTranslator(metadataProvider, currentVarCounter);
+ int currentVarCounter, Map<VarIdentifier, IAObject> externalVars) throws AlgebricksException {
+ return new SqlppExpressionToPlanTranslator(metadataProvider, currentVarCounter, externalVars);
}
}
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 a1d3f57..1a88170 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
@@ -23,6 +23,7 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -62,8 +63,10 @@
import org.apache.asterix.lang.common.statement.FunctionDecl;
import org.apache.asterix.lang.common.statement.Query;
import org.apache.asterix.lang.common.statement.StartFeedStatement;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.lang.common.util.FunctionUtil;
import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.optimizer.base.FuzzyUtils;
import org.apache.asterix.optimizer.rules.am.AbstractIntroduceAccessMethodRule;
import org.apache.asterix.runtime.job.listener.JobEventListenerFactory;
@@ -170,8 +173,8 @@
}
public Pair<IReturningStatement, Integer> reWriteQuery(List<FunctionDecl> declaredFunctions,
- MetadataProvider metadataProvider, IReturningStatement q, SessionOutput output, boolean inlineUdfs)
- throws CompilationException {
+ MetadataProvider metadataProvider, IReturningStatement q, SessionOutput output, boolean inlineUdfs,
+ Collection<VarIdentifier> externalVars) throws CompilationException {
if (q == null) {
return null;
}
@@ -180,13 +183,15 @@
generateExpressionTree(q);
}
IQueryRewriter rw = rewriterFactory.createQueryRewriter();
- rw.rewrite(declaredFunctions, q, metadataProvider, new LangRewritingContext(q.getVarCounter()), inlineUdfs);
+ rw.rewrite(declaredFunctions, q, metadataProvider, new LangRewritingContext(q.getVarCounter()), inlineUdfs,
+ externalVars);
return new Pair<>(q, q.getVarCounter());
}
public JobSpecification compileQuery(IClusterInfoCollector clusterInfoCollector, MetadataProvider metadataProvider,
Query query, int varCounter, String outputDatasetName, SessionOutput output,
- ICompiledDmlStatement statement) throws AlgebricksException, ACIDException {
+ ICompiledDmlStatement statement, Map<VarIdentifier, IAObject> externalVars)
+ throws AlgebricksException, ACIDException {
// establish facts
final boolean isQuery = query != null;
@@ -203,7 +208,7 @@
final TxnId txnId = metadataProvider.getTxnIdFactory().create();
metadataProvider.setTxnId(txnId);
ILangExpressionToPlanTranslator t =
- translatorFactory.createExpressionToPlanTranslator(metadataProvider, varCounter);
+ translatorFactory.createExpressionToPlanTranslator(metadataProvider, varCounter, externalVars);
ILogicalPlan plan = isLoad ? t.translateLoad(statement) : t.translate(query, outputDatasetName, statement);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java
index 63896f2..86cac25 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java
@@ -164,7 +164,7 @@
long startTime = System.currentTimeMillis();
final IRequestParameters requestParameters =
new RequestParameters(hds, new ResultProperties(IStatementExecutor.ResultDelivery.IMMEDIATE),
- new IStatementExecutor.Stats(), null, null, null);
+ new IStatementExecutor.Stats(), null, null, null, null);
translator.compileAndExecute(hcc, null, requestParameters);
long endTime = System.currentTimeMillis();
duration = (endTime - startTime) / 1000.00;
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 1713ca5..9655f57 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
@@ -71,7 +71,8 @@
@Override
protected void executeStatement(String statementsText, SessionOutput sessionOutput,
ResultProperties resultProperties, IStatementExecutor.Stats stats, RequestParameters param,
- RequestExecutionState execution, Map<String, String> optionalParameters) throws Exception {
+ RequestExecutionState execution, Map<String, String> optionalParameters,
+ Map<String, byte[]> statementParameters) throws Exception {
// Running on NC -> send 'execute' message to CC
INCServiceContext ncCtx = (INCServiceContext) serviceCtx;
INCMessageBroker ncMb = (INCMessageBroker) ncCtx.getMessageBroker();
@@ -87,9 +88,10 @@
if (param.timeout != null && !param.timeout.trim().isEmpty()) {
timeout = TimeUnit.NANOSECONDS.toMillis(Duration.parseDurationStringToNanos(param.timeout));
}
- ExecuteStatementRequestMessage requestMsg = new ExecuteStatementRequestMessage(ncCtx.getNodeId(),
- responseFuture.getFutureId(), queryLanguage, statementsText, sessionOutput.config(),
- resultProperties.getNcToCcResultProperties(), param.clientContextID, handleUrl, optionalParameters);
+ ExecuteStatementRequestMessage requestMsg =
+ new ExecuteStatementRequestMessage(ncCtx.getNodeId(), responseFuture.getFutureId(), queryLanguage,
+ statementsText, sessionOutput.config(), resultProperties.getNcToCcResultProperties(),
+ param.clientContextID, handleUrl, optionalParameters, statementParameters);
execution.start();
ncMb.sendMessageToPrimaryCC(requestMsg);
try {
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 3d0858c..a52973c 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
@@ -27,9 +27,12 @@
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiFunction;
import java.util.function.Function;
import org.apache.asterix.algebra.base.ILangExtension;
@@ -45,6 +48,7 @@
import org.apache.asterix.lang.common.base.IParser;
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.metadata.MetadataManager;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.translator.ExecutionPlans;
import org.apache.asterix.translator.ExecutionPlansJsonPrintUtil;
import org.apache.asterix.translator.IRequestParameters;
@@ -75,7 +79,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
-
import io.netty.handler.codec.http.HttpResponseStatus;
public class QueryServiceServlet extends AbstractQueryApiServlet {
@@ -137,6 +140,7 @@
}
public enum Parameter {
+ ARGS("args"),
STATEMENT("statement"),
FORMAT("format"),
CLIENT_ID("client_context_id"),
@@ -208,6 +212,7 @@
String mode;
String maxResultReads;
String planFormat;
+ Map<String, JsonNode> statementParams;
boolean expressionTree;
boolean rewrittenExpressionTree;
boolean logicalPlan;
@@ -236,6 +241,11 @@
on.put("optimizedLogicalPlan", optimizedLogicalPlan);
on.put("job", job);
on.put("signature", signature);
+ if (statementParams != null) {
+ for (Map.Entry<String, JsonNode> statementParam : statementParams.entrySet()) {
+ on.set('$' + statementParam.getKey(), statementParam.getValue());
+ }
+ }
return om.writer(new MinimalPrettyPrinter()).writeValueAsString(on);
} catch (JsonProcessingException e) { // NOSONAR
LOGGER.debug("unexpected exception marshalling {} instance to json", getClass(), e);
@@ -412,6 +422,41 @@
return value != null ? value.asBoolean() : defaultValue;
}
+ @FunctionalInterface
+ interface CheckedFunction<I, O> {
+ O apply(I requestParamValue) throws IOException;
+ }
+
+ private <R, P> Map<String, JsonNode> getOptStatementParameters(R request, Iterator<String> paramNameIter,
+ BiFunction<R, String, P> paramValueAccessor, CheckedFunction<P, JsonNode> paramValueParser)
+ throws IOException {
+ Map<String, JsonNode> result = null;
+ while (paramNameIter.hasNext()) {
+ String paramName = paramNameIter.next();
+ String stmtParamName = extractStatementParameterName(paramName);
+ if (stmtParamName != null) {
+ if (result == null) {
+ result = new HashMap<>();
+ }
+ P paramValue = paramValueAccessor.apply(request, paramName);
+ JsonNode stmtParamValue = paramValueParser.apply(paramValue);
+ result.put(stmtParamName, stmtParamValue);
+ } else if (Parameter.ARGS.str().equals(paramName)) {
+ if (result == null) {
+ result = new HashMap<>();
+ }
+ P paramValue = paramValueAccessor.apply(request, paramName);
+ JsonNode stmtParamValue = paramValueParser.apply(paramValue);
+ if (stmtParamValue.isArray()) {
+ for (int i = 0, ln = stmtParamValue.size(); i < ln; i++) {
+ result.put(String.valueOf(i + 1), stmtParamValue.get(i));
+ }
+ }
+ }
+ }
+ return result;
+ }
+
private RequestParameters getRequestParameters(IServletRequest request) throws IOException {
final String contentType = HttpUtil.getContentTypeOnly(request);
RequestParameters param = new RequestParameters();
@@ -435,6 +480,8 @@
param.optimizedLogicalPlan = getOptBoolean(jsonRequest, Parameter.OPTIMIZED_LOGICAL_PLAN.str(), false);
param.job = getOptBoolean(jsonRequest, Parameter.JOB.str(), false);
param.signature = getOptBoolean(jsonRequest, Parameter.SIGNATURE.str(), true);
+ param.statementParams =
+ getOptStatementParameters(jsonRequest, jsonRequest.fieldNames(), JsonNode::get, v -> v);
} catch (JsonParseException | JsonMappingException e) {
// if the JSON parsing fails, the statement is empty and we get an empty statement error
GlobalConfig.ASTERIX_LOGGER.log(Level.ERROR, e.getMessage(), e);
@@ -451,6 +498,12 @@
param.timeout = request.getParameter(Parameter.TIMEOUT.str());
param.maxResultReads = request.getParameter(Parameter.MAX_RESULT_READS.str());
param.planFormat = request.getParameter(Parameter.PLAN_FORMAT.str());
+ try {
+ param.statementParams = getOptStatementParameters(request, request.getParameterNames().iterator(),
+ IServletRequest::getParameter, OBJECT_MAPPER::readTree);
+ } catch (JsonParseException | JsonMappingException e) {
+ GlobalConfig.ASTERIX_LOGGER.log(Level.ERROR, e.getMessage(), e);
+ }
}
return param;
}
@@ -530,12 +583,15 @@
if (optionalParamProvider != null) {
optionalParams = optionalParamProvider.apply(request);
}
+ Map<String, byte[]> statementParams =
+ org.apache.asterix.app.translator.RequestParameters.serializeParameterValues(param.statementParams);
// CORS
response.setHeader("Access-Control-Allow-Origin",
"http://" + hostName + ":" + appCtx.getExternalProperties().getQueryWebInterfacePort());
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);
+ executeStatement(statementsText, sessionOutput, resultProperties, stats, param, execution, optionalParams,
+ statementParams);
if (ResultDelivery.IMMEDIATE == delivery || ResultDelivery.DEFERRED == delivery) {
ResultUtil.printStatus(sessionOutput, execution.getResultStatus());
}
@@ -560,8 +616,8 @@
}
protected void executeStatement(String statementsText, SessionOutput sessionOutput,
- ResultProperties resultProperties, IStatementExecutor.Stats stats, RequestParameters param,
- RequestExecutionState execution, Map<String, String> optionalParameters) throws Exception {
+ ResultProperties resultProperties, Stats stats, RequestParameters param, RequestExecutionState execution,
+ Map<String, String> optionalParameters, Map<String, byte[]> statementParameters) throws Exception {
IClusterManagementWork.ClusterState clusterState =
((ICcApplicationContext) appCtx).getClusterStateManager().getState();
if (clusterState != IClusterManagementWork.ClusterState.ACTIVE) {
@@ -574,8 +630,11 @@
IStatementExecutor translator = statementExecutorFactory.create((ICcApplicationContext) appCtx, statements,
sessionOutput, compilationProvider, componentProvider);
execution.start();
- final IRequestParameters requestParameters = new org.apache.asterix.app.translator.RequestParameters(
- getHyracksDataset(), resultProperties, stats, null, param.clientContextID, optionalParameters);
+ Map<String, IAObject> stmtParams =
+ org.apache.asterix.app.translator.RequestParameters.deserializeParameterValues(statementParameters);
+ IRequestParameters requestParameters =
+ new org.apache.asterix.app.translator.RequestParameters(getHyracksDataset(), resultProperties, stats,
+ null, param.clientContextID, optionalParameters, stmtParams);
translator.compileAndExecute(getHyracksClientConnection(), queryCtx, requestParameters);
execution.end();
printExecutionPlans(sessionOutput, translator.getExecutionPlans());
@@ -638,4 +697,26 @@
return format.startsWith(HttpUtil.ContentType.APPLICATION_JSON)
|| format.equalsIgnoreCase(HttpUtil.ContentType.JSON);
}
+
+ public static String extractStatementParameterName(String name) {
+ int ln = name.length();
+ if (ln > 1 && name.charAt(0) == '$' && Character.isLetter(name.charAt(1))) {
+ if (ln == 2 || isStatementParameterNameRest(name, 2)) {
+ return name.substring(1);
+ }
+ }
+ return null;
+ }
+
+ private static boolean isStatementParameterNameRest(CharSequence input, int startIndex) {
+ int i = startIndex;
+ for (int ln = input.length(); i < ln; i++) {
+ char c = input.charAt(i);
+ boolean ok = c == '_' || Character.isLetterOrDigit(c);
+ if (!ok) {
+ return false;
+ }
+ }
+ return i > startIndex;
+ }
}
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
index 428a4e0..40095d7 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
@@ -210,7 +210,7 @@
IStatementExecutor translator = statementExecutorFactory.create(appCtx, aqlStatements, sessionOutput,
compilationProvider, componentProvider);
final IRequestParameters requestParameters = new RequestParameters(hds,
- new ResultProperties(resultDelivery), new IStatementExecutor.Stats(), null, null, null);
+ new ResultProperties(resultDelivery), new IStatementExecutor.Stats(), null, null, null, null);
translator.compileAndExecute(hcc, null, requestParameters);
} catch (AsterixException | TokenMgrError | org.apache.asterix.aqlplus.parser.TokenMgrError pe) {
response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java
index 0e51953..2d3a2f6 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java
@@ -21,6 +21,7 @@
import java.io.PrintWriter;
import java.io.Reader;
import java.util.List;
+import java.util.Map;
import org.apache.asterix.api.common.APIFramework;
import org.apache.asterix.app.translator.RequestParameters;
@@ -32,6 +33,7 @@
import org.apache.asterix.lang.common.base.IParserFactory;
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.metadata.MetadataManager;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.translator.IRequestParameters;
import org.apache.asterix.translator.IStatementExecutor;
import org.apache.asterix.translator.IStatementExecutorFactory;
@@ -57,6 +59,7 @@
private final IStatementExecutorFactory statementExecutorFactory;
private final IStorageComponentProvider storageComponentProvider;
private ICcApplicationContext appCtx;
+ private Map<String, IAObject> statementParams;
public AsterixJavaClient(ICcApplicationContext appCtx, IHyracksClientConnection hcc, Reader queryText,
PrintWriter writer, ILangCompilationProvider compilationProvider,
@@ -81,6 +84,10 @@
compilationProvider, statementExecutorFactory, storageComponentProvider);
}
+ public void setStatementParameters(Map<String, IAObject> statementParams) {
+ this.statementParams = statementParams;
+ }
+
public void compile() throws Exception {
compile(true, false, true, false, false, false, false);
}
@@ -121,7 +128,7 @@
storageComponentProvider);
final IRequestParameters requestParameters =
new RequestParameters(null, new ResultProperties(IStatementExecutor.ResultDelivery.IMMEDIATE),
- new IStatementExecutor.Stats(), null, null, null);
+ new IStatementExecutor.Stats(), null, null, null, statementParams);
translator.compileAndExecute(hcc, null, requestParameters);
writer.flush();
}
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 977bbe3..ce259a2 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
@@ -29,7 +29,6 @@
import org.apache.asterix.api.http.server.ResultUtil;
import org.apache.asterix.app.cc.CCExtensionManager;
import org.apache.asterix.app.translator.RequestParameters;
-import org.apache.asterix.common.api.Duration;
import org.apache.asterix.common.api.IClusterManagementWork;
import org.apache.asterix.common.cluster.IClusterStateManager;
import org.apache.asterix.common.config.GlobalConfig;
@@ -45,6 +44,7 @@
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.messaging.CCMessageBroker;
import org.apache.asterix.metadata.MetadataManager;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.translator.IRequestParameters;
import org.apache.asterix.translator.IStatementExecutor;
import org.apache.asterix.translator.IStatementExecutorContext;
@@ -77,10 +77,12 @@
private final String clientContextID;
private final String handleUrl;
private final Map<String, String> optionalParameters;
+ private final Map<String, byte[]> statementParameters;
public ExecuteStatementRequestMessage(String requestNodeId, long requestMessageId, ILangExtension.Language lang,
String statementsText, SessionConfig sessionConfig, ResultProperties resultProperties,
- String clientContextID, String handleUrl, Map<String, String> optionalParameters) {
+ String clientContextID, String handleUrl, Map<String, String> optionalParameters,
+ Map<String, byte[]> statementParameters) {
this.requestNodeId = requestNodeId;
this.requestMessageId = requestMessageId;
this.lang = lang;
@@ -90,6 +92,7 @@
this.clientContextID = clientContextID;
this.handleUrl = handleUrl;
this.optionalParameters = optionalParameters;
+ this.statementParameters = statementParameters;
}
@Override
@@ -125,8 +128,9 @@
IStatementExecutor translator = statementExecutorFactory.create(ccAppCtx, statements, sessionOutput,
compilationProvider, storageComponentProvider);
final IStatementExecutor.Stats stats = new IStatementExecutor.Stats();
+ Map<String, IAObject> stmtParams = RequestParameters.deserializeParameterValues(statementParameters);
final IRequestParameters requestParameters = new RequestParameters(null, resultProperties, stats,
- outMetadata, clientContextID, optionalParameters);
+ outMetadata, clientContextID, optionalParameters, stmtParams);
translator.compileAndExecute(ccApp.getHcc(), statementExecutorContext, requestParameters);
outPrinter.close();
responseMsg.setResult(outWriter.toString());
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 bc6fff1..6bb6f35 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
@@ -115,7 +115,6 @@
import org.apache.asterix.lang.common.struct.Identifier;
import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.lang.common.util.FunctionUtil;
-import org.apache.asterix.lang.sqlpp.rewrites.SqlppRewriterFactory;
import org.apache.asterix.metadata.IDatasetDetails;
import org.apache.asterix.metadata.MetadataManager;
import org.apache.asterix.metadata.MetadataTransactionContext;
@@ -145,6 +144,7 @@
import org.apache.asterix.metadata.utils.MetadataConstants;
import org.apache.asterix.metadata.utils.MetadataLockUtil;
import org.apache.asterix.metadata.utils.MetadataUtil;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.IAType;
@@ -221,6 +221,7 @@
protected final SessionConfig sessionConfig;
protected Dataverse activeDataverse;
protected final List<FunctionDecl> declaredFunctions;
+ protected final ILangCompilationProvider compilationProvider;
protected final APIFramework apiFramework;
protected final IRewriterFactory rewriterFactory;
protected final ExecutorService executorService;
@@ -228,15 +229,16 @@
protected final IMetadataLockManager lockManager;
public QueryTranslator(ICcApplicationContext appCtx, List<Statement> statements, SessionOutput output,
- ILangCompilationProvider compliationProvider, ExecutorService executorService) {
+ ILangCompilationProvider compilationProvider, ExecutorService executorService) {
this.appCtx = appCtx;
this.lockManager = appCtx.getMetadataLockManager();
this.statements = statements;
this.sessionOutput = output;
this.sessionConfig = output.config();
+ this.compilationProvider = compilationProvider;
declaredFunctions = getDeclaredFunctions(statements);
- apiFramework = new APIFramework(compliationProvider);
- rewriterFactory = compliationProvider.getRewriterFactory();
+ apiFramework = new APIFramework(compilationProvider);
+ rewriterFactory = compilationProvider.getRewriterFactory();
activeDataverse = MetadataBuiltinEntities.DEFAULT_DATAVERSE;
this.executorService = executorService;
if (appCtx.getServiceContext().getAppConfig().getBoolean(CCConfig.Option.ENFORCE_FRAME_WRITER_PROTOCOL)) {
@@ -280,13 +282,15 @@
final Stats stats = requestParameters.getStats();
final ResultMetadata outMetadata = requestParameters.getOutMetadata();
final String clientContextId = requestParameters.getClientContextId();
+ final Map<String, IAObject> stmtParams = requestParameters.getStatementParameters();
try {
for (Statement stmt : statements) {
if (sessionConfig.is(SessionConfig.FORMAT_HTML)) {
sessionOutput.out().println(ApiServlet.HTML_STATEMENT_SEPARATOR);
}
validateOperation(appCtx, activeDataverse, stmt);
- rewriteStatement(stmt); // Rewrite the statement's AST.
+ IStatementRewriter stmtRewriter = rewriterFactory.createStatementRewriter();
+ rewriteStatement(stmt, stmtRewriter); // Rewrite the statement's AST.
MetadataProvider metadataProvider = new MetadataProvider(appCtx, activeDataverse);
metadataProvider.getConfig().putAll(config);
metadataProvider.setWriterFactory(writerFactory);
@@ -347,10 +351,10 @@
metadataProvider.setMaxResultReads(maxResultReads);
}
handleInsertUpsertStatement(metadataProvider, stmt, hcc, hdc, resultDelivery, outMetadata,
- stats, false, clientContextId);
+ stats, false, clientContextId, stmtParams, stmtRewriter);
break;
case DELETE:
- handleDeleteStatement(metadataProvider, stmt, hcc, false);
+ handleDeleteStatement(metadataProvider, stmt, hcc, false, stmtParams, stmtRewriter);
break;
case CREATE_FEED:
handleCreateFeedStatement(metadataProvider, stmt);
@@ -382,7 +386,7 @@
resultDelivery == ResultDelivery.ASYNC || resultDelivery == ResultDelivery.DEFERRED);
metadataProvider.setMaxResultReads(maxResultReads);
handleQuery(metadataProvider, (Query) stmt, hcc, hdc, resultDelivery, outMetadata, stats,
- clientContextId, ctx);
+ clientContextId, ctx, stmtParams, stmtRewriter);
break;
case COMPACT:
handleCompactStatement(metadataProvider, stmt, hcc);
@@ -1721,20 +1725,18 @@
wrappedQuery.setSourceLocation(sourceLoc);
wrappedQuery.setBody(cfs.getFunctionBodyExpression());
wrappedQuery.setTopLevel(false);
- List<VarIdentifier> varIds = new ArrayList<>();
+ List<VarIdentifier> paramVars = new ArrayList<>();
for (String v : cfs.getParamList()) {
- varIds.add(new VarIdentifier(v));
+ paramVars.add(new VarIdentifier(v));
}
- wrappedQuery.setExternalVars(varIds);
- apiFramework.reWriteQuery(declaredFunctions, metadataProvider, wrappedQuery, sessionOutput, false);
+ apiFramework.reWriteQuery(declaredFunctions, metadataProvider, wrappedQuery, sessionOutput, false,
+ paramVars);
List<List<List<String>>> dependencies = FunctionUtil.getFunctionDependencies(
rewriterFactory.createQueryRewriter(), cfs.getFunctionBodyExpression(), metadataProvider);
- final String language =
- rewriterFactory instanceof SqlppRewriterFactory ? Function.LANGUAGE_SQLPP : Function.LANGUAGE_AQL;
Function function = new Function(signature, cfs.getParamList(), Function.RETURNTYPE_VOID,
- cfs.getFunctionBody(), language, FunctionKind.SCALAR.toString(), dependencies);
+ cfs.getFunctionBody(), getFunctionLanguage(), FunctionKind.SCALAR.toString(), dependencies);
MetadataManager.INSTANCE.addFunction(mdTxnCtx, function);
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
@@ -1747,6 +1749,17 @@
}
}
+ private String getFunctionLanguage() {
+ switch (compilationProvider.getLanguage()) {
+ case SQLPP:
+ return Function.LANGUAGE_SQLPP;
+ case AQL:
+ return Function.LANGUAGE_AQL;
+ default:
+ throw new IllegalStateException(String.valueOf(compilationProvider.getLanguage()));
+ }
+ }
+
protected boolean isFunctionUsed(MetadataTransactionContext ctx, FunctionSignature signature,
String currentDataverse) throws AlgebricksException {
List<Dataverse> allDataverses = MetadataManager.INSTANCE.getDataverses(ctx);
@@ -1810,7 +1823,8 @@
new CompiledLoadFromFileStatement(dataverseName, loadStmt.getDatasetName().getValue(),
loadStmt.getAdapter(), loadStmt.getProperties(), loadStmt.dataIsAlreadySorted());
cls.setSourceLocation(stmt.getSourceLocation());
- JobSpecification spec = apiFramework.compileQuery(hcc, metadataProvider, null, 0, null, sessionOutput, cls);
+ JobSpecification spec =
+ apiFramework.compileQuery(hcc, metadataProvider, null, 0, null, sessionOutput, cls, null);
afterCompile();
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
bActiveTxn = false;
@@ -1829,7 +1843,8 @@
public JobSpecification handleInsertUpsertStatement(MetadataProvider metadataProvider, Statement stmt,
IHyracksClientConnection hcc, IHyracksDataset hdc, ResultDelivery resultDelivery,
- ResultMetadata outMetadata, Stats stats, boolean compileOnly, String clientContextId) throws Exception {
+ ResultMetadata outMetadata, Stats stats, boolean compileOnly, String clientContextId,
+ Map<String, IAObject> stmtParams, IStatementRewriter stmtRewriter) throws Exception {
InsertStatement stmtInsertUpsert = (InsertStatement) stmt;
String dataverseName = getActiveDataverse(stmtInsertUpsert.getDataverseName());
final IMetadataLocker locker = new IMetadataLocker() {
@@ -1850,7 +1865,8 @@
metadataProvider.setMetadataTxnContext(mdTxnCtx);
try {
metadataProvider.setWriteTransaction(true);
- final JobSpecification jobSpec = rewriteCompileInsertUpsert(hcc, metadataProvider, stmtInsertUpsert);
+ final JobSpecification jobSpec =
+ rewriteCompileInsertUpsert(hcc, metadataProvider, stmtInsertUpsert, stmtParams, stmtRewriter);
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
bActiveTxn = false;
return jobSpec;
@@ -1889,7 +1905,8 @@
}
public JobSpecification handleDeleteStatement(MetadataProvider metadataProvider, Statement stmt,
- IHyracksClientConnection hcc, boolean compileOnly) throws Exception {
+ IHyracksClientConnection hcc, boolean compileOnly, Map<String, IAObject> stmtParams,
+ IStatementRewriter stmtRewriter) throws Exception {
DeleteStatement stmtDelete = (DeleteStatement) stmt;
String dataverseName = getActiveDataverse(stmtDelete.getDataverseName());
MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
@@ -1903,7 +1920,8 @@
stmtDelete.getDatasetName().getValue(), stmtDelete.getCondition(), stmtDelete.getVarCounter(),
stmtDelete.getQuery());
clfrqs.setSourceLocation(stmt.getSourceLocation());
- JobSpecification jobSpec = rewriteCompileQuery(hcc, metadataProvider, clfrqs.getQuery(), clfrqs);
+ JobSpecification jobSpec =
+ rewriteCompileQuery(hcc, metadataProvider, clfrqs.getQuery(), clfrqs, stmtParams, stmtRewriter);
afterCompile();
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
@@ -1925,27 +1943,31 @@
@Override
public JobSpecification rewriteCompileQuery(IClusterInfoCollector clusterInfoCollector,
- MetadataProvider metadataProvider, Query query, ICompiledDmlStatement stmt)
- throws RemoteException, AlgebricksException, ACIDException {
+ MetadataProvider metadataProvider, Query query, ICompiledDmlStatement stmt,
+ Map<String, IAObject> stmtParams, IStatementRewriter stmtRewriter)
+ throws AlgebricksException, ACIDException {
+
+ Map<VarIdentifier, IAObject> externalVars = createExternalVariables(stmtParams, stmtRewriter);
// Query Rewriting (happens under the same ongoing metadata transaction)
- Pair<IReturningStatement, Integer> rewrittenResult =
- apiFramework.reWriteQuery(declaredFunctions, metadataProvider, query, sessionOutput, true);
+ Pair<IReturningStatement, Integer> rewrittenResult = apiFramework.reWriteQuery(declaredFunctions,
+ metadataProvider, query, sessionOutput, true, externalVars.keySet());
// Query Compilation (happens under the same ongoing metadata transaction)
return apiFramework.compileQuery(clusterInfoCollector, metadataProvider, (Query) rewrittenResult.first,
- rewrittenResult.second, stmt == null ? null : stmt.getDatasetName(), sessionOutput, stmt);
+ rewrittenResult.second, stmt == null ? null : stmt.getDatasetName(), sessionOutput, stmt, externalVars);
}
private JobSpecification rewriteCompileInsertUpsert(IClusterInfoCollector clusterInfoCollector,
- MetadataProvider metadataProvider, InsertStatement insertUpsert)
- throws RemoteException, AlgebricksException, ACIDException {
+ MetadataProvider metadataProvider, InsertStatement insertUpsert, Map<String, IAObject> stmtParams,
+ IStatementRewriter stmtRewriter) throws AlgebricksException, ACIDException {
SourceLocation sourceLoc = insertUpsert.getSourceLocation();
- // Insert/upsert statement rewriting (happens under the same ongoing metadata
- // transaction)
- Pair<IReturningStatement, Integer> rewrittenResult =
- apiFramework.reWriteQuery(declaredFunctions, metadataProvider, insertUpsert, sessionOutput, true);
+ Map<VarIdentifier, IAObject> externalVars = createExternalVariables(stmtParams, stmtRewriter);
+
+ // Insert/upsert statement rewriting (happens under the same ongoing metadata transaction)
+ Pair<IReturningStatement, Integer> rewrittenResult = apiFramework.reWriteQuery(declaredFunctions,
+ metadataProvider, insertUpsert, sessionOutput, true, externalVars.keySet());
InsertStatement rewrittenInsertUpsert = (InsertStatement) rewrittenResult.first;
String dataverseName = getActiveDataverse(rewrittenInsertUpsert.getDataverseName());
@@ -1971,7 +1993,7 @@
// Insert/upsert statement compilation (happens under the same ongoing metadata
// transaction)
return apiFramework.compileQuery(clusterInfoCollector, metadataProvider, rewrittenInsertUpsert.getQuery(),
- rewrittenResult.second, datasetName, sessionOutput, clfrqs);
+ rewrittenResult.second, datasetName, sessionOutput, clfrqs, externalVars);
}
protected void handleCreateFeedStatement(MetadataProvider metadataProvider, Statement stmt) throws Exception {
@@ -2419,7 +2441,8 @@
protected void handleQuery(MetadataProvider metadataProvider, Query query, IHyracksClientConnection hcc,
IHyracksDataset hdc, ResultDelivery resultDelivery, ResultMetadata outMetadata, Stats stats,
- String clientContextId, IStatementExecutorContext ctx) throws Exception {
+ String clientContextId, IStatementExecutorContext ctx, Map<String, IAObject> stmtParams,
+ IStatementRewriter stmtRewriter) throws Exception {
final IMetadataLocker locker = new IMetadataLocker() {
@Override
public void lock() {
@@ -2437,7 +2460,8 @@
boolean bActiveTxn = true;
metadataProvider.setMetadataTxnContext(mdTxnCtx);
try {
- final JobSpecification jobSpec = rewriteCompileQuery(hcc, metadataProvider, query, null);
+ final JobSpecification jobSpec =
+ rewriteCompileQuery(hcc, metadataProvider, query, null, stmtParams, stmtRewriter);
afterCompile();
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
bActiveTxn = false;
@@ -2885,8 +2909,7 @@
}
}
- protected void rewriteStatement(Statement stmt) throws CompilationException {
- IStatementRewriter rewriter = rewriterFactory.createStatementRewriter();
+ protected void rewriteStatement(Statement stmt, IStatementRewriter rewriter) throws CompilationException {
rewriter.rewrite(stmt);
}
@@ -2902,4 +2925,20 @@
ExecutionPlansHtmlPrintUtil.print(sessionOutput.out(), getExecutionPlans());
}
}
+
+ private Map<VarIdentifier, IAObject> createExternalVariables(Map<String, IAObject> stmtParams,
+ IStatementRewriter stmtRewriter) {
+ if (stmtParams == null || stmtParams.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<VarIdentifier, IAObject> m = new HashMap<>();
+ for (Map.Entry<String, IAObject> me : stmtParams.entrySet()) {
+ String paramName = me.getKey();
+ String extVarName = stmtRewriter.toExternalVariableName(paramName);
+ if (extVarName != null) {
+ m.put(new VarIdentifier(extVarName), me.getValue());
+ }
+ }
+ return m;
+ }
}
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 9592492..0655285 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
@@ -18,13 +18,26 @@
*/
package org.apache.asterix.app.translator;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.util.HashMap;
import java.util.Map;
+import org.apache.asterix.external.library.java.base.ByteArrayAccessibleInputStream;
+import org.apache.asterix.external.parser.JSONDataParser;
+import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
+import org.apache.asterix.om.base.IAObject;
+import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.translator.IRequestParameters;
import org.apache.asterix.translator.IStatementExecutor;
import org.apache.asterix.translator.IStatementExecutor.Stats;
import org.apache.asterix.translator.ResultProperties;
+import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
import org.apache.hyracks.api.dataset.IHyracksDataset;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.util.ByteArrayAccessibleOutputStream;
+
+import com.fasterxml.jackson.databind.JsonNode;
public class RequestParameters implements IRequestParameters {
@@ -34,16 +47,18 @@
private final Map<String, String> optionalParameters;
private final IStatementExecutor.ResultMetadata outMetadata;
private final String clientContextId;
+ private final Map<String, IAObject> statementParameters;
public RequestParameters(IHyracksDataset hdc, ResultProperties resultProperties, Stats stats,
IStatementExecutor.ResultMetadata outMetadata, String clientContextId,
- Map<String, String> optionalParameters) {
+ Map<String, String> optionalParameters, Map<String, IAObject> statementParameters) {
this.hdc = hdc;
this.resultProperties = resultProperties;
this.stats = stats;
this.outMetadata = outMetadata;
this.clientContextId = clientContextId;
this.optionalParameters = optionalParameters;
+ this.statementParameters = statementParameters;
}
@Override
@@ -75,4 +90,50 @@
public String getClientContextId() {
return clientContextId;
}
+
+ @Override
+ public Map<String, IAObject> getStatementParameters() {
+ return statementParameters;
+ }
+
+ public static Map<String, byte[]> serializeParameterValues(Map<String, JsonNode> inParams)
+ throws HyracksDataException {
+ if (inParams == null || inParams.isEmpty()) {
+ return null;
+ }
+ JSONDataParser parser = new JSONDataParser(null, null);
+ ByteArrayAccessibleOutputStream buffer = new ByteArrayAccessibleOutputStream();
+ DataOutputStream bufferDataOutput = new DataOutputStream(buffer);
+ Map<String, byte[]> m = new HashMap<>();
+ for (Map.Entry<String, JsonNode> me : inParams.entrySet()) {
+ String name = me.getKey();
+ JsonNode jsonValue = me.getValue();
+ parser.setInputNode(jsonValue);
+ buffer.reset();
+ parser.parseAnyValue(bufferDataOutput);
+ byte[] byteValue = buffer.toByteArray();
+ m.put(name, byteValue);
+ }
+ return m;
+ }
+
+ public static Map<String, IAObject> deserializeParameterValues(Map<String, byte[]> inParams)
+ throws HyracksDataException {
+ if (inParams == null || inParams.isEmpty()) {
+ return null;
+ }
+ Map<String, IAObject> m = new HashMap<>();
+ ByteArrayAccessibleInputStream buffer = new ByteArrayAccessibleInputStream(new byte[0], 0, 0);
+ DataInputStream bufferDataInput = new DataInputStream(buffer);
+ ISerializerDeserializer serDe =
+ SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ANY);
+ for (Map.Entry<String, byte[]> me : inParams.entrySet()) {
+ String name = me.getKey();
+ byte[] value = me.getValue();
+ buffer.setContent(value, 0, value.length);
+ IAObject iaValue = (IAObject) serDe.deserialize(bufferDataInput);
+ m.put(name, iaValue);
+ }
+ return m;
+ }
}
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
index 424444a..dc057cb 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
@@ -264,7 +264,7 @@
clfrqs = new CompiledStatements.CompiledUpsertStatement(feedConn.getDataverseName(),
feedConn.getDatasetName(), feedConnQuery, stmtUpsert.getVarCounter(), null, null);
}
- return statementExecutor.rewriteCompileQuery(hcc, metadataProvider, feedConnQuery, clfrqs);
+ return statementExecutor.rewriteCompileQuery(hcc, metadataProvider, feedConnQuery, clfrqs, null, null);
}
private static JobSpecification combineIntakeCollectJobs(MetadataProvider metadataProvider, Feed feed,
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java
index 942b192..e85fedf 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java
@@ -35,6 +35,7 @@
import org.apache.asterix.common.utils.Servlets;
import org.apache.asterix.test.runtime.SqlppExecutionWithCancellationTest;
import org.apache.asterix.testframework.context.TestCaseContext;
+import org.apache.asterix.testframework.xml.ParameterTypeEnum;
import org.apache.asterix.testframework.xml.TestCase;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.http.HttpResponse;
@@ -51,8 +52,8 @@
List<TestCase.CompilationUnit.Parameter> params, boolean jsonEncoded,
Predicate<Integer> responseCodeValidator, boolean cancellable) throws Exception {
String clientContextId = UUID.randomUUID().toString();
- final List<TestCase.CompilationUnit.Parameter> newParams =
- cancellable ? upsertParam(params, "client_context_id", clientContextId) : params;
+ final List<TestCase.CompilationUnit.Parameter> newParams = cancellable
+ ? upsertParam(params, "client_context_id", ParameterTypeEnum.STRING, clientContextId) : params;
Callable<InputStream> query = () -> {
try {
return CancellationTestExecutor.super.executeQueryService(str, fmt, uri, newParams, jsonEncoded,
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index 4697a2a..2281238 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -30,6 +30,7 @@
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.math.BigDecimal;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;
@@ -69,6 +70,7 @@
import org.apache.asterix.testframework.context.TestCaseContext.OutputFormat;
import org.apache.asterix.testframework.context.TestFileContext;
import org.apache.asterix.testframework.xml.ComparisonEnum;
+import org.apache.asterix.testframework.xml.ParameterTypeEnum;
import org.apache.asterix.testframework.xml.TestCase.CompilationUnit;
import org.apache.asterix.testframework.xml.TestCase.CompilationUnit.Parameter;
import org.apache.asterix.testframework.xml.TestGroup;
@@ -90,10 +92,13 @@
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
+import org.apache.hyracks.http.server.utils.HttpUtil;
import org.apache.hyracks.util.StorageUtil;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+
+import com.fasterxml.jackson.databind.util.RawValue;
import org.junit.Assert;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -124,11 +129,13 @@
private static final Pattern POLL_DELAY_PATTERN = Pattern.compile("polldelaysecs=(\\d+)(\\D|$)", Pattern.MULTILINE);
private static final Pattern HANDLE_VARIABLE_PATTERN = Pattern.compile("handlevariable=(\\w+)");
private static final Pattern VARIABLE_REF_PATTERN = Pattern.compile("\\$(\\w+)");
- private static final Pattern HTTP_PARAM_PATTERN = Pattern.compile("param (\\w+)=(.*)", Pattern.MULTILINE);
+ private static final Pattern HTTP_PARAM_PATTERN =
+ Pattern.compile("param (?<name>[\\w$]+)(?::(?<type>\\w+))?=(?<value>.*)", Pattern.MULTILINE);
private static final Pattern HTTP_BODY_PATTERN = Pattern.compile("body=(.*)", Pattern.MULTILINE);
private static final Pattern HTTP_STATUSCODE_PATTERN = Pattern.compile("statuscode (.*)", Pattern.MULTILINE);
private static final Pattern MAX_RESULT_READS_PATTERN =
Pattern.compile("maxresultreads=(\\d+)(\\D|$)", Pattern.MULTILINE);
+ private static final Pattern HTTP_REQUEST_TYPE = Pattern.compile("requesttype=(.*)", Pattern.MULTILINE);
public static final int TRUNCATE_THRESHOLD = 16384;
public static final Set<String> NON_CANCELLABLE =
Collections.unmodifiableSet(new HashSet<>(Arrays.asList("store", "validate")));
@@ -579,15 +586,15 @@
public InputStream executeQueryService(String str, OutputFormat fmt, URI uri, List<Parameter> params,
boolean jsonEncoded, Predicate<Integer> responseCodeValidator, boolean cancellable) throws Exception {
- List<Parameter> newParams = upsertParam(params, "format", fmt.mimeType());
+ List<Parameter> newParams = upsertParam(params, "format", ParameterTypeEnum.STRING, fmt.mimeType());
final Optional<String> maxReadsOptional = extractMaxResultReads(str);
if (maxReadsOptional.isPresent()) {
newParams = upsertParam(newParams, QueryServiceServlet.Parameter.MAX_RESULT_READS.str(),
- maxReadsOptional.get());
+ ParameterTypeEnum.STRING, maxReadsOptional.get());
}
final List<Parameter> additionalParams = extractParameters(str);
for (Parameter param : additionalParams) {
- newParams = upsertParam(newParams, param.getName(), param.getValue());
+ newParams = upsertParam(newParams, param.getName(), param.getType(), param.getValue());
}
HttpUriRequest method = jsonEncoded ? constructPostMethodJson(str, uri, "statement", newParams)
: constructPostMethodUrl(str, uri, "statement", newParams);
@@ -600,16 +607,18 @@
return response.getEntity().getContent();
}
- protected List<Parameter> upsertParam(List<Parameter> params, String name, String value) {
+ protected List<Parameter> upsertParam(List<Parameter> params, String name, ParameterTypeEnum type, String value) {
boolean replaced = false;
List<Parameter> result = new ArrayList<>();
for (Parameter param : params) {
Parameter newParam = new Parameter();
newParam.setName(param.getName());
if (name.equals(param.getName())) {
+ newParam.setType(type);
newParam.setValue(value);
replaced = true;
} else {
+ newParam.setType(param.getType());
newParam.setValue(param.getValue());
}
result.add(newParam);
@@ -617,6 +626,7 @@
if (!replaced) {
Parameter newParam = new Parameter();
newParam.setName(name);
+ newParam.setType(type);
newParam.setValue(value);
result.add(newParam);
}
@@ -677,7 +687,7 @@
List<Parameter> otherParams) {
RequestBuilder builder = RequestBuilder.post(uri);
if (stmtParam != null) {
- for (Parameter param : upsertParam(otherParams, stmtParam, statement)) {
+ for (Parameter param : upsertParam(otherParams, stmtParam, ParameterTypeEnum.STRING, statement)) {
builder.addParameter(param.getName(), param.getValue());
}
builder.addParameter(stmtParam, statement);
@@ -697,8 +707,23 @@
RequestBuilder builder = RequestBuilder.post(uri);
ObjectMapper om = new ObjectMapper();
ObjectNode content = om.createObjectNode();
- for (Parameter param : upsertParam(otherParams, stmtParam, statement)) {
- content.put(param.getName(), param.getValue());
+ for (Parameter param : upsertParam(otherParams, stmtParam, ParameterTypeEnum.STRING, statement)) {
+ String paramName = param.getName();
+ ParameterTypeEnum paramType = param.getType();
+ if (paramType == null) {
+ paramType = ParameterTypeEnum.STRING;
+ }
+ String paramValue = param.getValue();
+ switch (paramType) {
+ case STRING:
+ content.put(paramName, paramValue);
+ break;
+ case JSON:
+ content.putRawValue(paramName, new RawValue(paramValue));
+ break;
+ default:
+ throw new IllegalStateException(paramType.toString());
+ }
}
try {
builder.setEntity(new StringEntity(om.writeValueAsString(content), ContentType.APPLICATION_JSON));
@@ -1178,14 +1203,17 @@
}
URI uri = testFile.getName().endsWith("aql") ? getEndpoint(Servlets.QUERY_AQL)
: getEndpoint(Servlets.QUERY_SERVICE);
+ boolean isJsonEncoded = isJsonEncoded(extractHttpRequestType(statement));
InputStream resultStream;
if (DELIVERY_IMMEDIATE.equals(delivery)) {
- resultStream = executeQueryService(statement, fmt, uri, params, true, null, isCancellable(reqType));
+ resultStream =
+ executeQueryService(statement, fmt, uri, params, isJsonEncoded, null, isCancellable(reqType));
resultStream = METRICS_QUERY_TYPE.equals(reqType) ? ResultExtractor.extractMetrics(resultStream)
: ResultExtractor.extract(resultStream);
} else {
String handleVar = getHandleVariable(statement);
- resultStream = executeQueryService(statement, fmt, uri, upsertParam(params, "mode", delivery), true);
+ resultStream = executeQueryService(statement, fmt, uri,
+ upsertParam(params, "mode", ParameterTypeEnum.STRING, delivery), isJsonEncoded);
String handle = ResultExtractor.extractHandle(resultStream);
Assert.assertNotNull("no handle for " + reqType + " test " + testFile.toString(), handleVar);
variableCtx.put(handleVar, toQueryServiceHandle(handle));
@@ -1445,18 +1473,49 @@
return Optional.empty();
}
- protected static List<Parameter> extractParameters(String statement) {
+ public static List<Parameter> extractParameters(String statement) {
List<Parameter> params = new ArrayList<>();
final Matcher m = HTTP_PARAM_PATTERN.matcher(statement);
while (m.find()) {
final Parameter param = new Parameter();
- param.setName(m.group(1));
- param.setValue(m.group(2));
+ String name = m.group("name");
+ param.setName(name);
+ String value = m.group("value");
+ param.setValue(value);
+ String type = m.group("type");
+ if (type != null) {
+ try {
+ param.setType(ParameterTypeEnum.fromValue(type.toLowerCase()));
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException(
+ String.format("Invalid type '%s' specified for parameter '%s'", type, name));
+ }
+ }
params.add(param);
}
return params;
}
+ private static String extractHttpRequestType(String statement) {
+ Matcher m = HTTP_REQUEST_TYPE.matcher(statement);
+ return m.find() ? m.group(1) : null;
+ }
+
+ private static boolean isJsonEncoded(String httpRequestType) throws Exception {
+ if (httpRequestType == null || httpRequestType.isEmpty()) {
+ return true;
+ }
+ switch (httpRequestType.trim()) {
+ case HttpUtil.ContentType.JSON:
+ case HttpUtil.ContentType.APPLICATION_JSON:
+ return true;
+ case HttpUtil.ContentType.APPLICATION_X_WWW_FORM_URLENCODED:
+ return false;
+ default:
+ throw new Exception("Invalid value for http request type: " + httpRequestType);
+ }
+ }
+
protected static Predicate<Integer> extractStatusCodePredicate(String statement) {
List<Integer> codes = new ArrayList<>();
final Matcher m = HTTP_STATUSCODE_PATTERN.matcher(statement);
@@ -1511,6 +1570,7 @@
List<Parameter> params = new ArrayList<>();
Parameter node = new Parameter();
node.setName("node");
+ node.setType(ParameterTypeEnum.STRING);
node.setValue(nodeId);
params.add(node);
InputStream executeJSON = executeJSON(fmt, "POST", URI.create("http://localhost:16001" + endpoint), params);
@@ -1798,6 +1858,7 @@
Stream.of("partition", "host", "port").forEach(arg -> {
Parameter p = new Parameter();
p.setName(arg);
+ p.setType(ParameterTypeEnum.STRING);
parameters.add(p);
});
parameters.get(0).setValue(partition);
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestHelper.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestHelper.java
index 66a34ff..a7a7fce 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestHelper.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestHelper.java
@@ -23,15 +23,29 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import org.apache.asterix.api.http.server.QueryServiceServlet;
+import org.apache.asterix.app.translator.RequestParameters;
+import org.apache.asterix.om.base.IAObject;
+import org.apache.asterix.testframework.xml.ParameterTypeEnum;
+import org.apache.asterix.testframework.xml.TestCase;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.io.FileUtils;
import org.apache.hyracks.util.file.FileUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.node.TextNode;
+
public final class TestHelper {
private static final String TEST_DIR_BASE_PATH = System.getProperty("user.dir") + File.separator + "target";
@@ -81,4 +95,53 @@
}
}
}
+
+ public static Map<String, IAObject> readStatementParameters(String statement) throws IOException {
+ List<TestCase.CompilationUnit.Parameter> parameterList = TestExecutor.extractParameters(statement);
+ if (parameterList.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<String, JsonNode> stmtParams = new HashMap<>();
+ ObjectMapper om = createObjectMapper();
+ for (TestCase.CompilationUnit.Parameter param : parameterList) {
+ String paramName = param.getName();
+ JsonNode paramJsonValue;
+ ParameterTypeEnum paramType = param.getType();
+ if (paramType == null) {
+ paramType = ParameterTypeEnum.STRING;
+ }
+ String paramValue = param.getValue();
+ switch (paramType) {
+ case STRING:
+ paramJsonValue = TextNode.valueOf(paramValue);
+ break;
+ case JSON:
+ paramJsonValue = om.readTree(paramValue);
+ break;
+ default:
+ throw new IllegalArgumentException(String.valueOf(paramType));
+
+ }
+ String name = QueryServiceServlet.extractStatementParameterName(paramName);
+ if (name != null) {
+ stmtParams.put(name, paramJsonValue);
+ } else if (QueryServiceServlet.Parameter.ARGS.str().equals(paramName)) {
+ if (paramJsonValue.isArray()) {
+ for (int i = 0, ln = paramJsonValue.size(); i < ln; i++) {
+ stmtParams.put(String.valueOf(i + 1), paramJsonValue.get(i));
+ }
+ }
+ }
+ }
+
+ return RequestParameters.deserializeParameterValues(RequestParameters.serializeParameterValues(stmtParams));
+ }
+
+ private static ObjectMapper createObjectMapper() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
+ objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
+ objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
+ return objectMapper;
+ }
}
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonLogicalPlanTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonLogicalPlanTest.java
index e7b6271..0751178 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonLogicalPlanTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonLogicalPlanTest.java
@@ -24,9 +24,11 @@
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
-import java.io.Reader;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Map;
import org.apache.asterix.api.common.AsterixHyracksIntegrationUtil;
import org.apache.asterix.api.java.AsterixJavaClient;
@@ -41,11 +43,13 @@
import org.apache.asterix.external.util.ExternalDataConstants;
import org.apache.asterix.external.util.IdentitiyResolverFactory;
import org.apache.asterix.file.StorageComponentProvider;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.test.base.AsterixTestHelper;
import org.apache.asterix.test.common.TestHelper;
import org.apache.asterix.test.runtime.HDFSCluster;
import org.apache.asterix.translator.IStatementExecutorFactory;
import org.apache.asterix.translator.SessionConfig.PlanFormat;
+import org.apache.commons.io.FileUtils;
import org.apache.hyracks.api.client.IHyracksClientConnection;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -173,31 +177,28 @@
Assume.assumeTrue(!skipped);
LOGGER.info("RUN TEST: \"" + queryFile.getPath() + "\"");
- Reader query = new BufferedReader(new InputStreamReader(new FileInputStream(queryFile), "UTF-8"));
+ String query = FileUtils.readFileToString(queryFile, StandardCharsets.UTF_8);
+ Map<String, IAObject> queryParams = TestHelper.readStatementParameters(query);
// Forces the creation of actualFile.
actualFile.getParentFile().mkdirs();
- PrintWriter plan = new PrintWriter(actualFile);
ILangCompilationProvider provider =
queryFile.getName().endsWith("aql") ? aqlCompilationProvider : sqlppCompilationProvider;
if (extensionLangCompilationProvider != null) {
provider = extensionLangCompilationProvider;
}
IHyracksClientConnection hcc = integrationUtil.getHyracksClientConnection();
- AsterixJavaClient asterix =
- new AsterixJavaClient((ICcApplicationContext) integrationUtil.cc.getApplicationContext(), hcc,
- query, plan, provider, statementExecutorFactory, storageComponentProvider);
- try {
- asterix.compile(true, false, !optimized, optimized, false, false, false, PlanFormat.JSON);
+ try (PrintWriter plan = new PrintWriter(actualFile)) {
+ AsterixJavaClient asterix = new AsterixJavaClient(
+ (ICcApplicationContext) integrationUtil.cc.getApplicationContext(), hcc,
+ new StringReader(query), plan, provider, statementExecutorFactory, storageComponentProvider);
+ asterix.setStatementParameters(queryParams);
+ asterix.compile(true, false, !optimized, optimized, false, false, false, PlanFormat.JSON);
} catch (AsterixException e) {
- plan.close();
- query.close();
throw new Exception("Compile ERROR for " + queryFile + ": " + e.getMessage(), e);
}
- plan.close();
- query.close();
BufferedReader readerActual =
new BufferedReader(new InputStreamReader(new FileInputStream(actualFile), "UTF-8"));
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/optimizer/OptimizerTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/optimizer/OptimizerTest.java
index 3fd59a4..debb3f9 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/optimizer/OptimizerTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/optimizer/OptimizerTest.java
@@ -23,14 +23,16 @@
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
-import java.io.Reader;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Map;
import org.apache.asterix.api.common.AsterixHyracksIntegrationUtil;
import org.apache.asterix.api.java.AsterixJavaClient;
import org.apache.asterix.app.translator.DefaultStatementExecutorFactory;
-import org.apache.asterix.common.config.GlobalConfig;
import org.apache.asterix.common.context.IStorageComponentProvider;
import org.apache.asterix.common.dataflow.ICcApplicationContext;
import org.apache.asterix.compiler.provider.AqlCompilationProvider;
@@ -39,10 +41,12 @@
import org.apache.asterix.external.util.ExternalDataConstants;
import org.apache.asterix.external.util.IdentitiyResolverFactory;
import org.apache.asterix.file.StorageComponentProvider;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.test.base.AsterixTestHelper;
import org.apache.asterix.test.common.TestHelper;
import org.apache.asterix.test.runtime.HDFSCluster;
import org.apache.asterix.translator.IStatementExecutorFactory;
+import org.apache.commons.io.FileUtils;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.api.client.IHyracksClientConnection;
import org.apache.logging.log4j.LogManager;
@@ -113,7 +117,9 @@
private static void suiteBuildPerFile(File file, Collection<Object[]> testArgs, String path) {
if (file.isDirectory() && !file.getName().startsWith(".")) {
- for (File innerfile : file.listFiles()) {
+ File[] files = file.listFiles();
+ Arrays.sort(files);
+ for (File innerfile : files) {
String subdir = innerfile.isDirectory() ? path + innerfile.getName() + SEPARATOR : path;
suiteBuildPerFile(innerfile, testArgs, subdir);
}
@@ -170,32 +176,29 @@
Assume.assumeTrue(!skipped);
LOGGER.info("RUN TEST: \"" + queryFile.getPath() + "\"");
- Reader query = new BufferedReader(new InputStreamReader(new FileInputStream(queryFile), "UTF-8"));
+ String query = FileUtils.readFileToString(queryFile, StandardCharsets.UTF_8);
+ Map<String, IAObject> queryParams = TestHelper.readStatementParameters(query);
LOGGER.info("ACTUAL RESULT FILE: " + actualFile.getAbsolutePath());
// Forces the creation of actualFile.
actualFile.getParentFile().mkdirs();
- PrintWriter plan = new PrintWriter(actualFile);
ILangCompilationProvider provider =
queryFile.getName().endsWith("aql") ? aqlCompilationProvider : sqlppCompilationProvider;
if (extensionLangCompilationProvider != null) {
provider = extensionLangCompilationProvider;
}
IHyracksClientConnection hcc = integrationUtil.getHyracksClientConnection();
- AsterixJavaClient asterix =
- new AsterixJavaClient((ICcApplicationContext) integrationUtil.cc.getApplicationContext(), hcc,
- query, plan, provider, statementExecutorFactory, storageComponentProvider);
- try {
+ try (PrintWriter plan = new PrintWriter(actualFile)) {
+ AsterixJavaClient asterix = new AsterixJavaClient(
+ (ICcApplicationContext) integrationUtil.cc.getApplicationContext(), hcc,
+ new StringReader(query), plan, provider, statementExecutorFactory, storageComponentProvider);
+ asterix.setStatementParameters(queryParams);
asterix.compile(true, false, false, true, true, false, false);
} catch (AlgebricksException e) {
- plan.close();
- query.close();
throw new Exception("Compile ERROR for " + queryFile + ": " + e.getMessage(), e);
}
- plan.close();
- query.close();
BufferedReader readerExpected =
new BufferedReader(new InputStreamReader(new FileInputStream(expectedFile), "UTF-8"));
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
index 0d0c1d9..830307b 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
@@ -188,8 +188,8 @@
PA.invokeMethod(rewriter,
"setup(java.util.List, org.apache.asterix.lang.common.base.IReturningStatement, "
+ "org.apache.asterix.metadata.declared.MetadataProvider, "
- + "org.apache.asterix.lang.common.rewrites.LangRewritingContext)",
- declaredFunctions, topExpr, metadataProvider, context);
+ + "org.apache.asterix.lang.common.rewrites.LangRewritingContext, " + "java.util.Collection)",
+ declaredFunctions, topExpr, metadataProvider, context, null);
PA.invokeMethod(rewriter, "inlineColumnAlias()");
PA.invokeMethod(rewriter, "generateColumnNames()");
PA.invokeMethod(rewriter, "substituteGroupbyKeyExpression()");
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-01.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-01.sqlpp
new file mode 100644
index 0000000..0a53f64
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-01.sqlpp
@@ -0,0 +1,45 @@
+/*
+ * 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 : Test plan for a query with named parameters
+ * Expected Res : Success
+ * Date : 20 Jun 2017
+ */
+
+// param $p_str:json="hello"
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+write output to asterix_nc1:"rttest/statement-params_statement-params-01.adm";
+
+create type TestOpenType as open {
+ c_id: int64
+};
+
+create dataset TestOpen(TestOpenType)
+primary key c_id;
+
+create index idx_s on TestOpen(c_s:string);
+
+select c_id
+from TestOpen as t
+where t.c_s = $p_str
+;
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-02.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-02.sqlpp
new file mode 100644
index 0000000..71e9f3c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-02.sqlpp
@@ -0,0 +1,45 @@
+/*
+ * 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 : Test plan for a query with named parameters
+ * Expected Res : Success
+ * Date : 20 Jun 2017
+ */
+
+// param args:json=["hello"]
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+write output to asterix_nc1:"rttest/statement-params_statement-params-03.adm";
+
+create type TestOpenType as open {
+ c_id: int64
+};
+
+create dataset TestOpen(TestOpenType)
+primary key c_id;
+
+create index idx_s on TestOpen(c_s:string);
+
+select c_id
+from TestOpen as t
+where t.c_s = $1
+;
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-03.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-03.sqlpp
new file mode 100644
index 0000000..9019f68
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/statement-params/statement-params-03.sqlpp
@@ -0,0 +1,45 @@
+/*
+ * 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 : Test plan for a query with named parameters
+ * Expected Res : Success
+ * Date : 20 Jun 2017
+ */
+
+// param args:json=["hello"]
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+write output to asterix_nc1:"rttest/statement-params_statement-params-03.adm";
+
+create type TestOpenType as open {
+ c_id: int64
+};
+
+create dataset TestOpen(TestOpenType)
+primary key c_id;
+
+create index idx_s on TestOpen(c_s:string);
+
+select c_id
+from TestOpen as t
+where t.c_s = ?
+;
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-01.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-01.plan
new file mode 100644
index 0000000..cd5c81e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-01.plan
@@ -0,0 +1,17 @@
+-- DISTRIBUTE_RESULT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$21(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-02.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-02.plan
new file mode 100644
index 0000000..cd5c81e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-02.plan
@@ -0,0 +1,17 @@
+-- DISTRIBUTE_RESULT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$21(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-03.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-03.plan
new file mode 100644
index 0000000..cd5c81e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/statement-params/statement-params-03.plan
@@ -0,0 +1,17 @@
+-- DISTRIBUTE_RESULT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$21(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/ANYInFieldAccessor.sqlpp b/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/ANYInFieldAccessor.sqlpp
index bca9e57..ceddca3 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/ANYInFieldAccessor.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/parserts/queries_sqlpp/ANYInFieldAccessor.sqlpp
@@ -20,5 +20,5 @@
select element {'name':user.name,'movie':mv.movie}
from User as user,
Movie as mv
-where some i in user.interests satisfies (i.movie = mv.movie[?])
+where some i in user.interests satisfies (i.movie = mv.movie[0])
;
diff --git a/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/ANYInFieldAccessor.ast b/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/ANYInFieldAccessor.ast
index 42e81f9..3e3575d 100644
--- a/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/ANYInFieldAccessor.ast
+++ b/asterixdb/asterix-app/src/test/resources/parserts/results_parser_sqlpp/ANYInFieldAccessor.ast
@@ -50,7 +50,7 @@
Variable [ Name=$mv ]
Field=movie
]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
]
]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/customer_q_06/customer_q_06.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/customer_q_06/customer_q_06.3.query.sqlpp
index d5afe16..0be9caa 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/customer_q_06/customer_q_06.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/customer_q_06/customer_q_06.3.query.sqlpp
@@ -24,5 +24,5 @@
from Customers as c
with rec as c.lastorder,
m as [c.cid,rec.oid],
- n as [m[?],m[1],m[4]]
+ n as [m[0],m[1],m[4]]
;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/customer_q_07/customer_q_07.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/customer_q_07/customer_q_07.3.query.sqlpp
index 3344c77..71a0714 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/customer_q_07/customer_q_07.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/customer_q_07/customer_q_07.3.query.sqlpp
@@ -24,5 +24,5 @@
from Customers as c
with rec as c.lastorder,
m as [c.cid,rec.oid],
- n as {{m[?],m[1],m[4]}}
+ n as {{m[0],m[1],m[4]}}
;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/join_q_03/join_q_03.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/join_q_03/join_q_03.3.query.sqlpp
index 7b34440..fac0fa5 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/join_q_03/join_q_03.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/join_q_03/join_q_03.3.query.sqlpp
@@ -20,7 +20,7 @@
use test;
-select element {'cust_name':c.name,'order_total':o.total,'orderedlist':ol,'unorderedlist':ul,'ol_item1':ol[0],'ol_item2':ol[1],'ol_item5':ol[4],'ul_item1':ul[?]}
+select element {'cust_name':c.name,'order_total':o.total,'orderedlist':ol,'unorderedlist':ul,'ol_item1':ol[0],'ol_item2':ol[1],'ol_item5':ol[4],'ul_item1':ul[0]}
from Customers as c,
Orders as o
with rec as c.lastorder,
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/order_q_05/order_q_05.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/order_q_05/order_q_05.3.query.sqlpp
index 7271316..83a01cb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/order_q_05/order_q_05.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/order_q_05/order_q_05.3.query.sqlpp
@@ -20,7 +20,7 @@
use test;
-select element {'orderid':o.oid,'ordertot':o.total,'emptyorderedlist':c1,'emptyunorderedlist':c2,'olist_item1':c1[0],'olist_item5':c1[4],'ulist_item1':c2[?]}
+select element {'orderid':o.oid,'ordertot':o.total,'emptyorderedlist':c1,'emptyunorderedlist':c2,'olist_item1':c1[0],'olist_item5':c1[4],'ulist_item1':c2[0]}
from Orders as o
with c1 as [],
c2 as {{}}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/order_q_06/order_q_06.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/order_q_06/order_q_06.3.query.sqlpp
index a8859c5..cc8bc88 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/order_q_06/order_q_06.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/custord/order_q_06/order_q_06.3.query.sqlpp
@@ -20,7 +20,7 @@
use test;
-select element {'item1':c3[?]}
+select element {'item1':c3[0]}
from Orders as o
with c3 as {{o.heList,o.openlist}}
;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/employee/q_02/q_02.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/employee/q_02/q_02.3.query.sqlpp
index 7c8f2ea..ea7e438 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/employee/q_02/q_02.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/employee/q_02/q_02.3.query.sqlpp
@@ -22,5 +22,5 @@
select element m
from Emp as e
-with m as [{'EmpName':e.name,'parent_interest_1':e.interests[?],'child1Name':e.children[?],'child2Name':e.children[1]}]
+with m as [{'EmpName':e.name,'parent_interest_1':e.interests[0],'child1Name':e.children[0],'child2Name':e.children[1]}]
;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/any-collection-member_01/any-collection-member_01.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/any-collection-member_01/any-collection-member_01.3.query.sqlpp
index 208a440..ebccaf3 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/any-collection-member_01/any-collection-member_01.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/any-collection-member_01/any-collection-member_01.3.query.sqlpp
@@ -20,4 +20,4 @@
use test;
-{{1,1,1}}[?];
+{{1,1,1}}[0];
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/mixed_01/mixed_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/mixed_01/mixed_01.1.query.sqlpp
new file mode 100644
index 0000000..1763959
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/mixed_01/mixed_01.1.query.sqlpp
@@ -0,0 +1,35 @@
+/*
+ * 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 : Test named and positional statement parameters with json encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param args:json=[2.5, " world"]
+// param $p_int:json=2
+// param $p_str:json="hello"
+
+{
+ "t1": $p_int + ? + $1,
+ "t2": $p_str || ? || $2
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/mixed_01/mixed_01.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/mixed_01/mixed_01.2.query.sqlpp
new file mode 100644
index 0000000..c01c253
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/mixed_01/mixed_01.2.query.sqlpp
@@ -0,0 +1,33 @@
+/*
+ * 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 : Test named and positional statement parameters with url encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/x-www-form-urlencoded
+
+// param args:json=[" b", " c"]
+// param $p_str:json="a"
+
+{
+ "t1": $p_str || ? || $1 || ? || $2
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_01/named_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_01/named_01.1.query.sqlpp
new file mode 100644
index 0000000..68d6aad
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_01/named_01.1.query.sqlpp
@@ -0,0 +1,61 @@
+/*
+ * 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 : Test named statement parameters with json encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param $p_null:json=null
+// param $p_bool:json=true
+// param $p_int:json=42
+// param $p_dec:json=42.5
+// param $p_dbl:json=42.5e2
+// param $p_str:json="hello"
+// param $p_arr:json=["99",100,{"a":null},null,true]
+// param $p_obj:json={"a":[1,2,3]}
+
+{
+ "t1": {
+ "p_null": $p_null,
+ "p_bool": $p_bool,
+ "p_int": $p_int,
+ "p_dec": $p_dec,
+ "p_dbl": $p_dbl,
+ "p_str": $p_str,
+ "p_arr": $p_arr,
+ "p_obj": $p_obj
+ },
+
+ "t2": {
+ "p_null_type": $p_null is null,
+ "p_bool_type": is_boolean($p_bool),
+ "p_int_type": is_number($p_int),
+ "p_dec_type": is_number($p_dec),
+ "p_dbl_type": is_number($p_dbl),
+ "p_str_type": is_string($p_str),
+ "p_arr_type": is_array($p_arr),
+ "p_obj_type": is_object($p_obj)
+ },
+
+ "t3": [ $p_null, $p_bool, $p_int, $p_dec, $p_dbl, $p_str, $p_arr, $p_obj ]
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_01/named_01.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_01/named_01.2.query.sqlpp
new file mode 100644
index 0000000..6ecefd1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_01/named_01.2.query.sqlpp
@@ -0,0 +1,61 @@
+/*
+ * 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 : Test named statement parameters with url encoded request.
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/x-www-form-urlencoded
+
+// param $p_null:json=null
+// param $p_bool:json=true
+// param $p_int:json=42
+// param $p_dec:json=42.5
+// param $p_dbl:json=42.5e2
+// param $p_str:json="hello"
+// param $p_arr:json=["99",100,{"a":null},null,true]
+// param $p_obj:json={"a":[1,2,3]}
+
+{
+ "t1": {
+ "p_null": $p_null,
+ "p_bool": $p_bool,
+ "p_int": $p_int,
+ "p_dec": $p_dec,
+ "p_dbl": $p_dbl,
+ "p_str": $p_str,
+ "p_arr": $p_arr,
+ "p_obj": $p_obj
+ },
+
+ "t2": {
+ "p_null_type": is_string($p_null),
+ "p_bool_type": is_string($p_bool),
+ "p_int_type": is_string($p_int),
+ "p_dec_type": is_string($p_dec),
+ "p_dbl_type": is_string($p_dbl),
+ "p_str_type": is_string($p_str),
+ "p_arr_type": is_string($p_arr),
+ "p_obj_type": is_string($p_obj)
+ },
+
+ "t3": [ $p_null, $p_bool, $p_int, $p_dec, $p_dbl, $p_str, $p_arr, $p_obj ]
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_02/named_02.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_02/named_02.1.query.sqlpp
new file mode 100644
index 0000000..f2ec9e0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_02/named_02.1.query.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * 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 : Test named statement parameters with json encoded request
+ * Expected Res : Failure (no value for a named parameter)
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param $p1:json="hello"
+
+$p1 || $p2
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_03/named_03.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_03/named_03.1.query.sqlpp
new file mode 100644
index 0000000..522b776
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/named_03/named_03.1.query.sqlpp
@@ -0,0 +1,31 @@
+/*
+ * 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 : Test autogenerated column aliases named statement parameters
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param $p_int:json=42
+// param $p_str:json="hello"
+
+select $p_int, $p_str
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_01/positional_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_01/positional_01.1.query.sqlpp
new file mode 100644
index 0000000..ef71010
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_01/positional_01.1.query.sqlpp
@@ -0,0 +1,54 @@
+/*
+ * 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 : Test positional ($) statement parameters with json encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param args:json=[null, true, 42, 42.5, 42.5e2, "hello", ["99",100,{"a":null},null,true], {"a":[1,2,3]}]
+
+{
+ "t1": {
+ "p_null": $1,
+ "p_bool": $2,
+ "p_int": $3,
+ "p_dec": $4,
+ "p_dbl": $5,
+ "p_str": $6,
+ "p_arr": $7,
+ "p_obj": $8
+ },
+
+ "t2": {
+ "p_null_type": $1 is null,
+ "p_bool_type": is_boolean($2),
+ "p_int_type": is_number($3),
+ "p_dec_type": is_number($4),
+ "p_dbl_type": is_number($5),
+ "p_str_type": is_string($6),
+ "p_arr_type": is_array($7),
+ "p_obj_type": is_object($8)
+ },
+
+ "t3": [ $1, $2, $3, $4, $5, $6, $7, $8 ]
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_01/positional_01.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_01/positional_01.2.query.sqlpp
new file mode 100644
index 0000000..a31a646
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_01/positional_01.2.query.sqlpp
@@ -0,0 +1,54 @@
+/*
+ * 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 : Test positional ($) statement parameters with url encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/x-www-form-urlencoded
+
+// param args:json=[null, true, 42, 42.5, 42.5e2, "hello", ["99",100,{"a":null},null,true], {"a":[1,2,3]}]
+
+{
+ "t1": {
+ "p_null": $1,
+ "p_bool": $2,
+ "p_int": $3,
+ "p_dec": $4,
+ "p_dbl": $5,
+ "p_str": $6,
+ "p_arr": $7,
+ "p_obj": $8
+ },
+
+ "t2": {
+ "p_null_type": $1 is null,
+ "p_bool_type": is_boolean($2),
+ "p_int_type": is_number($3),
+ "p_dec_type": is_number($4),
+ "p_dbl_type": is_number($5),
+ "p_str_type": is_string($6),
+ "p_arr_type": is_array($7),
+ "p_obj_type": is_object($8)
+ },
+
+ "t3": [ $1, $2, $3, $4, $5, $6, $7, $8 ]
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.1.query.sqlpp
new file mode 100644
index 0000000..2fa7cde
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.1.query.sqlpp
@@ -0,0 +1,41 @@
+/*
+ * 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 : Test positional (?) statement parameters with json encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param args:json=[null, true, 42, 42.5, 42.5e2, "hello", ["99",100,{"a":null},null,true], {"a":[1,2,3]}]
+
+{
+ "t1": {
+ "p_null": ?,
+ "p_bool": ?,
+ "p_int": ?,
+ "p_dec": ?,
+ "p_dbl": ?,
+ "p_str": ?,
+ "p_arr": ?,
+ "p_obj": ?
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.2.query.sqlpp
new file mode 100644
index 0000000..1d952d3
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.2.query.sqlpp
@@ -0,0 +1,41 @@
+/*
+ * 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 : Test positional (?) statement parameters with json encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param args:json=[null, true, 42, 42.5, 42.5e2, "hello", ["99",100,{"a":null},null,true], {"a":[1,2,3]}]
+
+{
+ "t2": {
+ "p_null_type": ? is null,
+ "p_bool_type": is_boolean(?),
+ "p_int_type": is_number(?),
+ "p_dec_type": is_number(?),
+ "p_dbl_type": is_number(?),
+ "p_str_type": is_string(?),
+ "p_arr_type": is_array(?),
+ "p_obj_type": is_object(?)
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.3.query.sqlpp
new file mode 100644
index 0000000..13c077b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_02/positional_02.3.query.sqlpp
@@ -0,0 +1,32 @@
+/*
+ * 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 : Test positional (?) statement parameters with json encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param args:json=[null, true, 42, 42.5, 42.5e2, "hello", ["99",100,{"a":null},null,true], {"a":[1,2,3]}]
+
+{
+ "t3": [ ?, ?, ?, ?, ?, ?, ?, ? ]
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.1.query.sqlpp
new file mode 100644
index 0000000..1eb6e0f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.1.query.sqlpp
@@ -0,0 +1,41 @@
+/*
+ * 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 : Test positional (?) statement parameters with url encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/x-www-form-urlencoded
+
+// param args:json=[null, true, 42, 42.5, 42.5e2, "hello", ["99",100,{"a":null},null,true], {"a":[1,2,3]}]
+
+{
+ "t1": {
+ "p_null": ?,
+ "p_bool": ?,
+ "p_int": ?,
+ "p_dec": ?,
+ "p_dbl": ?,
+ "p_str": ?,
+ "p_arr": ?,
+ "p_obj": ?
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.2.query.sqlpp
new file mode 100644
index 0000000..bbacada
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.2.query.sqlpp
@@ -0,0 +1,41 @@
+/*
+ * 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 : Test positional (?) statement parameters with url encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/x-www-form-urlencoded
+
+// param args:json=[null, true, 42, 42.5, 42.5e2, "hello", ["99",100,{"a":null},null,true], {"a":[1,2,3]}]
+
+{
+ "t2": {
+ "p_null_type": ? is null,
+ "p_bool_type": is_boolean(?),
+ "p_int_type": is_number(?),
+ "p_dec_type": is_number(?),
+ "p_dbl_type": is_number(?),
+ "p_str_type": is_string(?),
+ "p_arr_type": is_array(?),
+ "p_obj_type": is_object(?)
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.3.query.sqlpp
new file mode 100644
index 0000000..312278f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_03/positional_02.3.query.sqlpp
@@ -0,0 +1,32 @@
+/*
+ * 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 : Test positional (?) statement parameters with url encoded request
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/x-www-form-urlencoded
+
+// param args:json=[null, true, 42, 42.5, 42.5e2, "hello", ["99",100,{"a":null},null,true], {"a":[1,2,3]}]
+
+{
+ "t3": [ ?, ?, ?, ?, ?, ?, ?, ? ]
+}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_04/positional_04.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_04/positional_04.1.query.sqlpp
new file mode 100644
index 0000000..279f336
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_04/positional_04.1.query.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * 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 : Test named statement parameters with json encoded request
+ * Expected Res : Failure (no value for a positional parameter)
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param args:json=["hello"]
+
+$1 || $2
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_04/positional_04.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_04/positional_04.2.query.sqlpp
new file mode 100644
index 0000000..5f7dedc
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_04/positional_04.2.query.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * 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 : Test named statement parameters with json encoded request
+ * Expected Res : Failure (no value for a positional parameter)
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param args:json=["a", "b"]
+
+? || ? || ?
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_05/positional_05.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_05/positional_05.1.query.sqlpp
new file mode 100644
index 0000000..89901e7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/statement-params/positional_05/positional_05.1.query.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * 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 : Test autogenerated column aliases positional statement parameters
+ * Expected Res : Success
+ * Date : Jun 2018
+ */
+
+// requesttype=application/json
+
+// param args:json=[3,4]
+
+select $2, $1
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/mixed_01/mixed_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/mixed_01/mixed_01.1.adm
new file mode 100644
index 0000000..7190640
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/mixed_01/mixed_01.1.adm
@@ -0,0 +1 @@
+{ "t1": 7.0, "t2": "hello world world" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/mixed_01/mixed_01.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/mixed_01/mixed_01.2.adm
new file mode 100644
index 0000000..3ed423f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/mixed_01/mixed_01.2.adm
@@ -0,0 +1 @@
+{ "t1": "a b b c c" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_01/named_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_01/named_01.1.adm
new file mode 100644
index 0000000..2d95320
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_01/named_01.1.adm
@@ -0,0 +1 @@
+{ "t1": { "p_null": null, "p_bool": true, "p_int": 42, "p_dec": 42.5, "p_dbl": 4250.0, "p_str": "hello", "p_arr": [ "99", 100, { "a": null }, null, true ], "p_obj": { "a": [ 1, 2, 3 ] } }, "t2": { "p_null_type": true, "p_bool_type": true, "p_int_type": true, "p_dec_type": true, "p_dbl_type": true, "p_str_type": true, "p_arr_type": true, "p_obj_type": true }, "t3": [ null, true, 42, 42.5, 4250.0, "hello", [ "99", 100, { "a": null }, null, true ], { "a": [ 1, 2, 3 ] } ] }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_01/named_01.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_01/named_01.2.adm
new file mode 100644
index 0000000..e16cae9
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_01/named_01.2.adm
@@ -0,0 +1 @@
+{ "t1": { "p_null": null, "p_bool": true, "p_int": 42, "p_dec": 42.5, "p_dbl": 4250.0, "p_str": "hello", "p_arr": [ "99", 100, { "a": null }, null, true ], "p_obj": { "a": [ 1, 2, 3 ] } }, "t2": { "p_null_type": null, "p_bool_type": false, "p_int_type": false, "p_dec_type": false, "p_dbl_type": false, "p_str_type": true, "p_arr_type": false, "p_obj_type": false }, "t3": [ null, true, 42, 42.5, 4250.0, "hello", [ "99", 100, { "a": null }, null, true ], { "a": [ 1, 2, 3 ] } ] }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_03/named_03.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_03/named_03.1.adm
new file mode 100644
index 0000000..e7eb119
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/named_03/named_03.1.adm
@@ -0,0 +1 @@
+{ "$1": 42, "$2": "hello" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_01/positional_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_01/positional_01.1.adm
new file mode 100644
index 0000000..aab6f21
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_01/positional_01.1.adm
@@ -0,0 +1 @@
+{ "t1": { "p_null": null, "p_bool": true, "p_int": 42, "p_dec": 42.5, "p_dbl": 4250.0, "p_str": "hello", "p_arr": [ "99", 100, { "a": null }, null, true ], "p_obj": { "a": [ 1, 2, 3 ] } }, "t2": { "p_null_type": true, "p_bool_type": true, "p_int_type": true, "p_dec_type": true, "p_dbl_type": true, "p_str_type": true, "p_arr_type": true, "p_obj_type": true }, "t3": [ null, true, 42, 42.5, 4250.0, "hello", [ "99", 100, { "a": null }, null, true ], { "a": [ 1, 2, 3 ] } ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_01/positional_01.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_01/positional_01.2.adm
new file mode 100644
index 0000000..2d95320
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_01/positional_01.2.adm
@@ -0,0 +1 @@
+{ "t1": { "p_null": null, "p_bool": true, "p_int": 42, "p_dec": 42.5, "p_dbl": 4250.0, "p_str": "hello", "p_arr": [ "99", 100, { "a": null }, null, true ], "p_obj": { "a": [ 1, 2, 3 ] } }, "t2": { "p_null_type": true, "p_bool_type": true, "p_int_type": true, "p_dec_type": true, "p_dbl_type": true, "p_str_type": true, "p_arr_type": true, "p_obj_type": true }, "t3": [ null, true, 42, 42.5, 4250.0, "hello", [ "99", 100, { "a": null }, null, true ], { "a": [ 1, 2, 3 ] } ] }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.1.adm
new file mode 100644
index 0000000..f8c0d3e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.1.adm
@@ -0,0 +1 @@
+{ "t1": { "p_null": null, "p_bool": true, "p_int": 42, "p_dec": 42.5, "p_dbl": 4250.0, "p_str": "hello", "p_arr": [ "99", 100, { "a": null }, null, true ], "p_obj": { "a": [ 1, 2, 3 ] } } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.2.adm
new file mode 100644
index 0000000..5a2e691
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.2.adm
@@ -0,0 +1 @@
+{ "t2": { "p_null_type": true, "p_bool_type": true, "p_int_type": true, "p_dec_type": true, "p_dbl_type": true, "p_str_type": true, "p_arr_type": true, "p_obj_type": true } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.3.adm
new file mode 100644
index 0000000..84e880e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_02/positional_02.3.adm
@@ -0,0 +1 @@
+{ "t3": [ null, true, 42, 42.5, 4250.0, "hello", [ "99", 100, { "a": null }, null, true ], { "a": [ 1, 2, 3 ] } ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_05/postitional_05.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_05/postitional_05.1.adm
new file mode 100644
index 0000000..5494401
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/statement-params/positional_05/postitional_05.1.adm
@@ -0,0 +1 @@
+{ "$1": 4, "$2": 3 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/customer_q_06/customer_q_06.3.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/customer_q_06/customer_q_06.3.ast
index 0ebf373..b9e2111 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/customer_q_06/customer_q_06.3.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/customer_q_06/customer_q_06.3.ast
@@ -45,7 +45,7 @@
OrderedListConstructor [
IndexAccessor [
Variable [ Name=$m ]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
IndexAccessor [
Variable [ Name=$m ]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/customer_q_07/customer_q_07.3.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/customer_q_07/customer_q_07.3.ast
index 3c8d114..12e09be 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/customer_q_07/customer_q_07.3.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/customer_q_07/customer_q_07.3.ast
@@ -45,7 +45,7 @@
UnorderedListConstructor [
IndexAccessor [
Variable [ Name=$m ]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
IndexAccessor [
Variable [ Name=$m ]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/join_q_03/join_q_03.3.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/join_q_03/join_q_03.3.ast
index 6653361..a1dace8 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/join_q_03/join_q_03.3.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/join_q_03/join_q_03.3.ast
@@ -57,7 +57,7 @@
:
IndexAccessor [
Variable [ Name=$ul ]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
)
]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/order_q_05/order_q_05.3.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/order_q_05/order_q_05.3.ast
index 2682444..4ee2bc8 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/order_q_05/order_q_05.3.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/order_q_05/order_q_05.3.ast
@@ -49,7 +49,7 @@
:
IndexAccessor [
Variable [ Name=$c2 ]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
)
]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/order_q_06/order_q_06.3.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/order_q_06/order_q_06.3.ast
index 3aae7c8..c0ec9bf 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/order_q_06/order_q_06.3.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/custord/order_q_06/order_q_06.3.ast
@@ -7,7 +7,7 @@
:
IndexAccessor [
Variable [ Name=$c3 ]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
)
]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/employee/q_02/q_02.3.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/employee/q_02/q_02.3.ast
index 43344eb..7eb3a51 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/employee/q_02/q_02.3.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/employee/q_02/q_02.3.ast
@@ -28,7 +28,7 @@
Variable [ Name=$e ]
Field=interests
]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
)
(
@@ -39,7 +39,7 @@
Variable [ Name=$e ]
Field=children
]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
)
(
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/list/any-collection-member_01/any-collection-member_01.3.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/list/any-collection-member_01/any-collection-member_01.3.ast
index b96b43b..fa9bf57 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/list/any-collection-member_01/any-collection-member_01.3.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/list/any-collection-member_01/any-collection-member_01.3.ast
@@ -6,5 +6,5 @@
LiteralExpr [LONG] [1]
LiteralExpr [LONG] [1]
]
- Index: ANY
+ Index: LiteralExpr [LONG] [0]
]
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 4376ca6..21c14d1 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -6050,6 +6050,56 @@
</compilation-unit>
</test-case>
</test-group>
+ <test-group name="statement-params">
+ <test-case FilePath="statement-params">
+ <compilation-unit name="mixed_01">
+ <output-dir compare="Text">mixed_01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="statement-params">
+ <compilation-unit name="named_01">
+ <output-dir compare="Text">named_01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="statement-params">
+ <compilation-unit name="named_02">
+ <output-dir compare="Text">named_01</output-dir>
+ <expected-error>ASX1086: No value for parameter: $p2</expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="statement-params">
+ <compilation-unit name="named_03">
+ <output-dir compare="Text">named_03</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="statement-params">
+ <compilation-unit name="positional_01">
+ <output-dir compare="Text">positional_01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="statement-params">
+ <compilation-unit name="positional_02">
+ <output-dir compare="Text">positional_02</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="statement-params">
+ <compilation-unit name="positional_03">
+ <output-dir compare="Text">positional_02</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="statement-params">
+ <compilation-unit name="positional_04">
+ <output-dir compare="Text">positional_02</output-dir>
+ <expected-error>ASX1086: No value for parameter: $2</expected-error>
+ <expected-error>ASX1086: No value for parameter: $3</expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="statement-params">
+ <compilation-unit name="positional_05">
+ <output-dir compare="Text">positional_05</output-dir>
+ </compilation-unit>
+ </test-case>
+ </test-group>
<test-group name="string">
<test-case FilePath="string">
<compilation-unit name="codepoint-to-string1">
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index de399eb..ae59ddc 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -166,6 +166,7 @@
public static final int UNKNOWN_INDEX = 1083;
public static final int INDEX_EXISTS = 1084;
public static final int TYPE_EXISTS = 1085;
+ public static final int PARAMETER_NO_VALUE = 1086;
// Feed errors
public static final int DATAFLOW_ILLEGAL_STATE = 3001;
diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index f0a36bf..01e217e 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -153,6 +153,7 @@
1083 = Cannot find index with name %1$s
1084 = An index with this name %1$s already exists
1085 = A datatype with this name %1$s already exists
+1086 = No value for parameter: %1$s
# Feed Errors
3001 = Illegal state.
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/2_expr.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/2_expr.md
index 8fe379d..a1f0420 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/2_expr.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/2_expr.md
@@ -19,7 +19,7 @@
SQL++ is a highly composable expression language. Each SQL++ expression returns zero or more data model instances.
There are three major kinds of expressions in SQL++. At the topmost level, a SQL++ expression can be an
-OperatorExpression (similar to a mathematical expression), or a QuantifiedExpression (which yields a boolean value).
+OperatorExpression (similar to a mathematical expression), or a QuantifiedExpression (which yields a boolean value).
Each will be detailed as we explore the full SQL++ grammar.
Expression ::= OperatorExpression | QuantifiedExpression
@@ -201,13 +201,14 @@
PathExpression ::= PrimaryExpression ( Field | Index )*
Field ::= "." Identifier
- Index ::= "[" ( Expression | "?" ) "]"
+ Index ::= "[" Expression "]"
Components of complex types in the data model are accessed via path expressions. Path access can be applied to the result
of a SQL++ expression that yields an instance of a complex type, for example, a object or array instance. For objects,
-path access is based on field names. For arrays, path access is based on (zero-based) array-style indexing.
-SQL++ also supports an "I'm feeling lucky" style index accessor, [?], for selecting an arbitrary element from an array.
+path access is based on field names. For arrays path access is based on (zero-based) array-style indexing.
Attempts to access non-existent fields or out-of-bound array elements produce the special value `MISSING`.
+For multisets path access is also zero-based and returns an arbitrary multiset element if the index
+is within the size of the multiset or `MISSING` otherwise.
Type errors will be raised for inappropriate use of a path expression, such as applying a field
accessor to a numeric value.
@@ -227,15 +228,16 @@
PrimaryExpr ::= Literal
| VariableReference
+ | ParameterReference
| ParenthesizedExpression
| FunctionCallExpression
| CaseExpression
| Constructor
The most basic building block for any SQL++ expression is PrimaryExpression. This can be a simple literal (constant)
-value, a reference to a query variable that is in scope, a parenthesized expression, a function call, a conditional
-(case) expression, or a newly constructed instance of the data model (such as a newly constructed object, array,
-or multiset of data model instances).
+value, a reference to a query variable that is in scope, a statement parameter, a parenthesized expression,
+a function call, a conditional (case) expression, or a newly constructed instance of the data model
+(such as a newly constructed object, array, or multiset of data model instances).
## <a id="Literals">Literals</a>
@@ -301,7 +303,7 @@
### <a id="Variable_references">Variable References</a>
- VariableReference ::= <IDENTIFIER>|<DelimitedIdentifier>
+ VariableReference ::= <IDENTIFIER> | <DelimitedIdentifier>
<IDENTIFIER> ::= (<LETTER> | "_") (<LETTER> | <DIGIT> | "_" | "$")*
<LETTER> ::= ["A" - "Z", "a" - "z"]
DelimitedIdentifier ::= "`" (<EscapeQuot>
@@ -327,6 +329,22 @@
`SELECT`
`my-function`
+### <a id="Parameter_references">Parameter References</a>
+
+ ParameterReference ::= NamedParameterReference | PositionalParameterReference
+ NamedParameterReference ::= "$" (<IDENTIFIER> | <DelimitedIdentifier>)
+ PositionalParameterReference ::= ("$" <DIGITS>) | "?"
+
+A statement parameter is an external variable which value is provided through the [statement execution API](../api.html#queryservice).
+An error will be raised if the parameter is not bound at the query execution time. Positional parameter numbering starts at 1.
+"?" parameters are interpreted as $1, .. $N in the order in which they appear in the statement.
+
+##### Examples
+
+ $id
+ $1
+ ?
+
### <a id="Parenthesized_expressions">Parenthesized Expressions</a>
ParenthesizedExpression ::= "(" Expression ")" | Subquery
diff --git a/asterixdb/asterix-doc/src/site/markdown/api.md b/asterixdb/asterix-doc/src/site/markdown/api.md
index 848f2c3..6853938 100644
--- a/asterixdb/asterix-doc/src/site/markdown/api.md
+++ b/asterixdb/asterix-doc/src/site/markdown/api.md
@@ -43,6 +43,8 @@
If the delivery mode is `immediate` the query result is returned with the response.
If the delivery mode is `deferred` the response contains a handle to the <a href="#queryresult">result</a>.
If the delivery mode is `async` the response contains a handle to the query's <a href="#querystatus">status</a>.
+* `args` - (SQL++ only) A JSON array where each item is a value of a [positional query parameter](sqlpp/manual.html#Parameter_references)
+* `$parameter_name` - (SQL++ only) a JSON value of a [named query parameter](sqlpp/manual.html#Parameter_references).
__Command (immediate result delivery)__
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/JSONDataParser.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/JSONDataParser.java
index 209ba34..554bb2f 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/JSONDataParser.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/JSONDataParser.java
@@ -50,6 +50,8 @@
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.TreeTraversingParser;
/**
* JSON format parser using Jakson parser.
@@ -102,7 +104,15 @@
@Override
public void setInputStream(InputStream in) throws IOException {
- jsonParser = jsonFactory.createParser(in);
+ setInput(jsonFactory.createParser(in));
+ }
+
+ public void setInputNode(JsonNode node) {
+ setInput(new TreeTraversingParser(node));
+ }
+
+ private void setInput(JsonParser parser) {
+ jsonParser = parser;
geometryCoParser.reset(jsonParser);
}
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 dd7061f..967fdae 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
@@ -19,6 +19,7 @@
package org.apache.asterix.lang.aql.rewrites;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -69,8 +70,8 @@
@Override
public void rewrite(List<FunctionDecl> declaredFunctions, IReturningStatement topStatement,
- MetadataProvider metadataProvider, LangRewritingContext context, boolean inlineUdfs)
- throws CompilationException {
+ MetadataProvider metadataProvider, LangRewritingContext context, boolean inlineUdfs,
+ Collection<VarIdentifier> externalVars) throws CompilationException {
setup(declaredFunctions, topStatement, metadataProvider, context);
if (topStatement.isTopLevel()) {
wrapInLets();
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java
index a89e8bd..5ca91b6 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java
@@ -36,4 +36,9 @@
stmt.accept(visitor, null);
}
}
+
+ @Override
+ public String toExternalVariableName(String statementParameterName) {
+ return null;
+ }
}
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 05ab836..8f3b8a9 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
@@ -18,6 +18,7 @@
*/
package org.apache.asterix.lang.common.base;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -25,24 +26,27 @@
import org.apache.asterix.lang.common.expression.CallExpr;
import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.metadata.declared.MetadataProvider;
public interface IQueryRewriter {
/**
* Rewrite a query at the AST level.
- *
* @param declaredFunctions,
- * a list of declared functions associated with the query.
+ * a list of declared functions associated with the query.
* @param topExpr,
- * the query to be rewritten.
+ * the query to be rewritten.
* @param metadataProvider,
- * providing the definition of created (i.e., stored) user-defined functions.
- * @param context,
- * manages ids of variables and guarantees uniqueness of variables.
+ * providing the definition of created (i.e., stored) user-defined functions.
+ * @param context
+ * rewriting context
+ * @param externalVars
+ * external variables
*/
void rewrite(List<FunctionDecl> declaredFunctions, IReturningStatement topExpr, MetadataProvider metadataProvider,
- LangRewritingContext context, boolean inlineUdfs) throws CompilationException;
+ LangRewritingContext context, boolean inlineUdfs, Collection<VarIdentifier> externalVars)
+ throws CompilationException;
/**
* Find the function calls used by a given expression
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IReturningStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IReturningStatement.java
index d31b765..02e5267 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IReturningStatement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IReturningStatement.java
@@ -19,8 +19,6 @@
package org.apache.asterix.lang.common.base;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-
import java.util.List;
/**
@@ -66,16 +64,4 @@
* the main body expression.
*/
void setBody(Expression expr);
-
- /**
- * @return external (pre-defined) variables for the statement
- */
- List<VarIdentifier> getExternalVars();
-
- /**
- * Sets external (pre-defined) variables for the statement
- *
- * @param externalVars external variables
- */
- void setExternalVars(List<VarIdentifier> externalVars);
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
index 7de67f7..0584665 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
@@ -26,6 +26,7 @@
* @param statement,
* a non-query statement.
*/
- public void rewrite(Statement statement) throws CompilationException;
+ void rewrite(Statement statement) throws CompilationException;
+ String toExternalVariableName(String statementParameterName);
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
index 7dadd67..f332b0a 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
@@ -303,7 +303,8 @@
}
protected String getLine(int line) {
- return inputLines[line - 1];
+ int idx = line - 1;
+ return idx >= 0 && idx < inputLines.length ? inputLines[idx] : "";
}
protected String extractFragment(int beginLine, int beginColumn, int endLine, int endColumn) {
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/InsertStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/InsertStatement.java
index 20aea67..7bb2cbe 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/InsertStatement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/InsertStatement.java
@@ -29,7 +29,6 @@
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.lang.common.expression.VariableExpr;
import org.apache.asterix.lang.common.struct.Identifier;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
public class InsertStatement extends AbstractStatement implements IReturningStatement {
@@ -116,16 +115,6 @@
}
@Override
- public List<VarIdentifier> getExternalVars() {
- return null;
- }
-
- @Override
- public void setExternalVars(List<VarIdentifier> externalVars) {
- throw new UnsupportedOperationException();
- }
-
- @Override
public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws CompilationException {
return visitor.visit(this, arg);
}
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 6b532fe..8b67556 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
@@ -27,14 +27,12 @@
import org.apache.asterix.lang.common.base.Expression;
import org.apache.asterix.lang.common.base.IReturningStatement;
import org.apache.asterix.lang.common.base.Statement;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
public class Query extends AbstractStatement implements IReturningStatement {
private final boolean explain;
private boolean topLevel = true;
private Expression body;
- private List<VarIdentifier> externalVars;
private int varCounter;
public Query(boolean explain) {
@@ -42,15 +40,10 @@
}
public Query(boolean explain, boolean topLevel, Expression body, int varCounter) {
- this(explain, topLevel, body, varCounter, null);
- }
-
- public Query(boolean explain, boolean topLevel, Expression body, int varCounter, List<VarIdentifier> externalVars) {
this.explain = explain;
this.topLevel = topLevel;
this.body = body;
this.varCounter = varCounter;
- this.externalVars = externalVars;
}
@Override
@@ -87,16 +80,6 @@
return topLevel;
}
- @Override
- public List<VarIdentifier> getExternalVars() {
- return externalVars;
- }
-
- @Override
- public void setExternalVars(List<VarIdentifier> externalVars) {
- this.externalVars = externalVars;
- }
-
public boolean isExplain() {
return explain;
}
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 c43824d..bf9cf89 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
@@ -337,7 +337,6 @@
wrappedQuery.setSourceLocation(sourceLoc);
wrappedQuery.setBody(fnDecl.getFuncBody());
wrappedQuery.setTopLevel(false);
- wrappedQuery.setExternalVars(fnDecl.getParamList());
String fnNamespace = fnDecl.getSignature().getNamespace();
Dataverse defaultDataverse = metadataProvider.getDefaultDataverse();
@@ -356,7 +355,8 @@
metadataProvider.setDefaultDataverse(fnDataverse);
try {
IQueryRewriter queryRewriter = rewriterFactory.createQueryRewriter();
- queryRewriter.rewrite(declaredFunctions, wrappedQuery, metadataProvider, context, true);
+ queryRewriter.rewrite(declaredFunctions, wrappedQuery, metadataProvider, context, true,
+ fnDecl.getParamList());
return wrappedQuery.getBody();
} finally {
metadataProvider.setDefaultDataverse(defaultDataverse);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
index 7858e58..0c0ebd6 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
@@ -18,22 +18,24 @@
*/
package org.apache.asterix.lang.sqlpp.rewrites;
+import java.util.Collection;
import java.util.List;
import org.apache.asterix.common.exceptions.CompilationException;
import org.apache.asterix.lang.common.base.IReturningStatement;
import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.metadata.declared.MetadataProvider;
class SqlppFunctionBodyRewriter extends SqlppQueryRewriter {
@Override
public void rewrite(List<FunctionDecl> declaredFunctions, IReturningStatement topStatement,
- MetadataProvider metadataProvider, LangRewritingContext context, boolean inlineUdfs)
- throws CompilationException {
+ MetadataProvider metadataProvider, LangRewritingContext context, boolean inlineUdfs,
+ Collection<VarIdentifier> externalVars) throws CompilationException {
// Sets up parameters.
- setup(declaredFunctions, topStatement, metadataProvider, context);
+ setup(declaredFunctions, topStatement, metadataProvider, context, externalVars);
// Inlines column aliases.
inlineColumnAlias();
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 647b50e..09a9f90 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
@@ -19,6 +19,7 @@
package org.apache.asterix.lang.sqlpp.rewrites;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -31,6 +32,7 @@
import org.apache.asterix.lang.common.expression.CallExpr;
import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.lang.common.util.FunctionUtil;
import org.apache.asterix.lang.common.visitor.GatherFunctionCallsVisitor;
import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
@@ -76,25 +78,27 @@
private List<FunctionDecl> declaredFunctions;
private LangRewritingContext context;
private MetadataProvider metadataProvider;
+ private Collection<VarIdentifier> externalVars;
protected void setup(List<FunctionDecl> declaredFunctions, IReturningStatement topExpr,
- MetadataProvider metadataProvider, LangRewritingContext context) {
+ MetadataProvider metadataProvider, LangRewritingContext context, Collection<VarIdentifier> externalVars) {
this.topExpr = topExpr;
this.context = context;
this.declaredFunctions = declaredFunctions;
this.metadataProvider = metadataProvider;
+ this.externalVars = externalVars;
}
@Override
public void rewrite(List<FunctionDecl> declaredFunctions, IReturningStatement topStatement,
- MetadataProvider metadataProvider, LangRewritingContext context, boolean inlineUdfs)
- throws CompilationException {
+ MetadataProvider metadataProvider, LangRewritingContext context, boolean inlineUdfs,
+ Collection<VarIdentifier> externalVars) throws CompilationException {
if (topStatement == null) {
return;
}
// Sets up parameters.
- setup(declaredFunctions, topStatement, metadataProvider, context);
+ setup(declaredFunctions, topStatement, metadataProvider, context, externalVars);
// Inlines column aliases.
inlineColumnAlias();
@@ -206,7 +210,7 @@
protected void variableCheckAndRewrite() throws CompilationException {
VariableCheckAndRewriteVisitor variableCheckAndRewriteVisitor =
- new VariableCheckAndRewriteVisitor(context, metadataProvider, topExpr.getExternalVars());
+ new VariableCheckAndRewriteVisitor(context, metadataProvider, externalVars);
topExpr.accept(variableCheckAndRewriteVisitor, null);
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
index 5667415..7908636 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
@@ -21,6 +21,7 @@
import org.apache.asterix.common.exceptions.CompilationException;
import org.apache.asterix.lang.common.base.IStatementRewriter;
import org.apache.asterix.lang.common.base.Statement;
+import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
import org.apache.asterix.lang.sqlpp.visitor.SqlppDeleteRewriteVisitor;
class SqlppStatementRewriter implements IStatementRewriter {
@@ -36,4 +37,9 @@
stmt.accept(visitor, null);
}
}
+
+ @Override
+ public String toExternalVariableName(String statementParameterName) {
+ return SqlppVariableUtil.toExternalVariableName(statementParameterName);
+ }
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
index 5af284b..20071e3 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
@@ -19,6 +19,7 @@
package org.apache.asterix.lang.sqlpp.rewrites.visitor;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -56,7 +57,7 @@
* @param context, manages ids of variables and guarantees uniqueness of variables.
*/
public VariableCheckAndRewriteVisitor(LangRewritingContext context, MetadataProvider metadataProvider,
- List<VarIdentifier> externalVars) {
+ Collection<VarIdentifier> externalVars) {
super(context, externalVars);
this.metadataProvider = metadataProvider;
}
@@ -96,9 +97,9 @@
private Expression resolve(VariableExpr varExpr, String dataverseName, String datasetName,
Expression originalExprWithUndefinedIdentifier, ILangExpression parent) throws CompilationException {
+ VarIdentifier varId = varExpr.getVar();
+ String varName = varId.getValue();
SourceLocation sourceLoc = varExpr.getSourceLocation();
-
- String varName = varExpr.getVar().getValue();
VarIdentifier var = lookupVariable(varName, sourceLoc);
if (var != null) {
// Exists such an identifier
@@ -107,6 +108,11 @@
return varExpr;
}
+ if (SqlppVariableUtil.isExternalVariableIdentifier(varId)) {
+ throw new CompilationException(ErrorCode.PARAMETER_NO_VALUE, sourceLoc,
+ SqlppVariableUtil.variableNameToDisplayedFieldName(varId.getValue()));
+ }
+
boolean resolveToDatasetOnly = resolveToDatasetOnly(originalExprWithUndefinedIdentifier, parent);
if (resolveToDatasetOnly) {
return resolveAsDataset(dataverseName, datasetName, sourceLoc);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/ExpressionToVariableUtil.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/ExpressionToVariableUtil.java
index c0eb2d9..4842026 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/ExpressionToVariableUtil.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/ExpressionToVariableUtil.java
@@ -40,7 +40,8 @@
private static String getGeneratedIdentifier(Expression expr) throws ParseException {
if (expr.getKind() == Kind.VARIABLE_EXPRESSION) {
VariableExpr bindingVarExpr = (VariableExpr) expr;
- return bindingVarExpr.getVar().getValue();
+ VarIdentifier var = bindingVarExpr.getVar();
+ return SqlppVariableUtil.isExternalVariableIdentifier(var) ? null : var.getValue();
} else if (expr.getKind() == Kind.FIELD_ACCESSOR_EXPRESSION) {
FieldAccessor fa = (FieldAccessor) expr;
return SqlppVariableUtil.toInternalVariableName(fa.getIdent().getValue());
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java
index 519627c..3dbdde5 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java
@@ -40,6 +40,8 @@
private static final String USER_VAR_PREFIX = "$";
+ private static final String EXTERNAL_VAR_PREFIX = "?";
+
private SqlppVariableUtil() {
}
@@ -79,7 +81,15 @@
}
public static VarIdentifier toInternalVariableIdentifier(String idName) {
- return new VarIdentifier(USER_VAR_PREFIX + idName);
+ return new VarIdentifier(toInternalVariableName(idName));
+ }
+
+ public static String toExternalVariableName(String varName) {
+ return EXTERNAL_VAR_PREFIX + varName;
+ }
+
+ public static boolean isExternalVariableIdentifier(VarIdentifier varId) {
+ return varId.getValue().startsWith(EXTERNAL_VAR_PREFIX);
}
public static Collection<VariableExpr> getFreeVariables(ILangExpression langExpr) throws CompilationException {
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 6635a0e..fbe9eb5 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
@@ -256,8 +256,8 @@
@Override
public Query visit(Query q, Void arg) throws CompilationException {
- Query copy = new Query(q.isExplain(), q.isTopLevel(), (Expression) q.getBody().accept(this, arg),
- q.getVarCounter(), q.getExternalVars());
+ Query copy =
+ new Query(q.isExplain(), q.isTopLevel(), (Expression) q.getBody().accept(this, arg), q.getVarCounter());
copy.setSourceLocation(q.getSourceLocation());
return copy;
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
index 81b21c8..6d9430b 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
@@ -18,8 +18,8 @@
*/
package org.apache.asterix.lang.sqlpp.visitor.base;
+import java.util.Collection;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -76,7 +76,7 @@
* @param externalVars
* pre-defined (external) variables that must be added to the initial scope
*/
- public AbstractSqlppExpressionScopingVisitor(LangRewritingContext context, List<VarIdentifier> externalVars) {
+ public AbstractSqlppExpressionScopingVisitor(LangRewritingContext context, Collection<VarIdentifier> externalVars) {
this.context = context;
this.scopeChecker.setVarCounter(context.getVarCounter());
if (externalVars != null) {
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 6d9976a..e2a8759 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -209,6 +209,8 @@
// error configuration
protected static final boolean REPORT_EXPECTED_TOKENS = false;
+ private int externalVarCounter;
+
private static class IndexParams {
public IndexType type;
public int gramLength;
@@ -2325,9 +2327,6 @@
}
}
}
-
- | <QUES> // ANY
-
)
<RIGHTBRACKET>
@@ -2347,6 +2346,7 @@
| expr = CaseExpr()
| expr = Literal()
| expr = VariableRef()
+ | expr = ExternalVariableRef()
| expr = ListConstructor()
| expr = RecordConstructor()
| expr = ParenthesizedExpression()
@@ -2458,6 +2458,33 @@
}
}
+VariableExpr ExternalVariableRef() throws ParseException:
+{
+ String name = null;
+}
+{
+ (
+ (
+ <DOLLAR>
+ (
+ <INTEGER_LITERAL> { name = token.image; } |
+ <IDENTIFIER> { name = token.image; } |
+ name = QuotedString()
+ )
+ )
+ |
+ (
+ <QUES> { name = String.valueOf(++externalVarCounter); }
+ )
+ )
+ {
+ String idName = SqlppVariableUtil.toExternalVariableName(name);
+ VarIdentifier id = new VarIdentifier(idName);
+ VariableExpr varExp = new VariableExpr(id);
+ return addSourceLocation(varExp, token);
+ }
+}
+
Expression ListConstructor() throws ParseException:
{
Expression expr = null;
@@ -3410,6 +3437,7 @@
| <ATT : "@">
| <COLON : ":">
| <COMMA : ",">
+ | <DOLLAR: "$">
| <DOT : ".">
| <PERCENT: "%">
| <QUES : "?">
@@ -3459,8 +3487,8 @@
<DEFAULT,IN_DBL_BRACE>
TOKEN [IGNORE_CASE]:
{
- <MISSING : "missing">
- | <NULL : "null">
+ <MISSING : "missing">
+ | <NULL : "null">
| <TRUE : "true">
| <FALSE : "false">
}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java
index 6eb7d4c..04ee28b 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ACastVisitor.java
@@ -75,7 +75,8 @@
laccessorToCaster.put(accessor, caster);
}
if (arg.second.getTypeTag().equals(ATypeTag.ANY)) {
- arg.second = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
+ arg.second = accessor.ordered() ? DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE
+ : DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
}
caster.castList(accessor, arg.first, (AbstractCollectionType) arg.second, this);
return null;
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java
index 7fa987f..8aad9d7 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java
@@ -19,12 +19,12 @@
package org.apache.asterix.om.typecomputer.base;
+import org.apache.asterix.common.exceptions.CompilationException;
import org.apache.asterix.om.exceptions.IncompatibleTypeException;
import org.apache.asterix.om.typecomputer.impl.TypeComputeUtils;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.IAType;
import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
public class TypeCastUtils {
@@ -33,7 +33,7 @@
}
public static boolean setRequiredAndInputTypes(AbstractFunctionCallExpression expr, IAType requiredType,
- IAType inputType) throws AlgebricksException {
+ IAType inputType) throws CompilationException {
boolean changed = false;
Object[] opaqueParameters = expr.getOpaqueParameters();
if (opaqueParameters == null) {
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/GetItemDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/GetItemDescriptor.java
index aa641ff..70b0891 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/GetItemDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/GetItemDescriptor.java
@@ -22,6 +22,7 @@
import java.io.IOException;
import org.apache.asterix.dataflow.data.nontagged.serde.AOrderedListSerializerDeserializer;
+import org.apache.asterix.dataflow.data.nontagged.serde.AUnorderedListSerializerDeserializer;
import org.apache.asterix.om.functions.BuiltinFunctions;
import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
@@ -44,6 +45,7 @@
public class GetItemDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
+
public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
@Override
public IFunctionDescriptor createFunctionDescriptor() {
@@ -66,9 +68,6 @@
private static final long serialVersionUID = 1L;
private IScalarEvaluatorFactory listEvalFactory;
private IScalarEvaluatorFactory indexEvalFactory;
- private byte serItemTypeTag;
- private ATypeTag itemTag;
- private boolean selfDescList = false;
public GetItemEvalFactory(IScalarEvaluatorFactory[] args) {
this.listEvalFactory = args[0];
@@ -86,9 +85,6 @@
private IScalarEvaluator evalList = listEvalFactory.createScalarEvaluator(ctx);
private IScalarEvaluator evalIdx = indexEvalFactory.createScalarEvaluator(ctx);
private byte[] missingBytes = new byte[] { ATypeTag.SERIALIZED_MISSING_TYPE_TAG };
- private int itemIndex;
- private int itemOffset;
- private int itemLength;
@Override
public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
@@ -96,48 +92,51 @@
evalList.evaluate(tuple, inputArgList);
evalIdx.evaluate(tuple, inputArgIdx);
- byte[] serOrderedList = inputArgList.getByteArray();
+ byte[] serList = inputArgList.getByteArray();
int offset = inputArgList.getStartOffset();
byte[] indexBytes = inputArgIdx.getByteArray();
int indexOffset = inputArgIdx.getStartOffset();
- if (serOrderedList[offset] == ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG) {
- itemIndex = ATypeHierarchy.getIntegerValue(BuiltinFunctions.GET_ITEM.getName(), 0,
- indexBytes, indexOffset);
+ int itemCount;
+ byte serListTypeTag = serList[offset];
+ if (serListTypeTag == ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG) {
+ itemCount = AOrderedListSerializerDeserializer.getNumberOfItems(serList, offset);
+ } else if (serListTypeTag == ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG) {
+ itemCount = AUnorderedListSerializerDeserializer.getNumberOfItems(serList, offset);
} else {
- throw new TypeMismatchException(sourceLoc, BuiltinFunctions.GET_ITEM, 0,
- serOrderedList[offset], ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG);
+ throw new TypeMismatchException(sourceLoc, BuiltinFunctions.GET_ITEM, 0, serListTypeTag,
+ ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG,
+ ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG);
}
- if (itemIndex < 0 || itemIndex >= AOrderedListSerializerDeserializer
- .getNumberOfItems(serOrderedList, offset)) {
+ int itemIndex = ATypeHierarchy.getIntegerValue(BuiltinFunctions.GET_ITEM.getName(), 0,
+ indexBytes, indexOffset);
+
+ if (itemIndex < 0 || itemIndex >= itemCount) {
// Out-of-bound index access should return MISSING.
result.set(missingBytes, 0, 1);
return;
}
- itemTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(serOrderedList[offset + 1]);
- if (itemTag == ATypeTag.ANY) {
- selfDescList = true;
- } else {
- serItemTypeTag = serOrderedList[offset + 1];
- }
+ byte serItemTypeTag = serList[offset + 1];
+ ATypeTag itemTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(serItemTypeTag);
+ boolean selfDescList = itemTag == ATypeTag.ANY;
- itemOffset =
- AOrderedListSerializerDeserializer.getItemOffset(serOrderedList, offset, itemIndex);
+ int itemOffset = serListTypeTag == ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG
+ ? AOrderedListSerializerDeserializer.getItemOffset(serList, offset, itemIndex)
+ : AUnorderedListSerializerDeserializer.getItemOffset(serList, offset, 0);
if (selfDescList) {
- itemTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(serOrderedList[itemOffset]);
- itemLength =
- NonTaggedFormatUtil.getFieldValueLength(serOrderedList, itemOffset, itemTag, true)
- + 1;
- result.set(serOrderedList, itemOffset, itemLength);
+ itemTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(serList[itemOffset]);
+ int itemLength =
+ NonTaggedFormatUtil.getFieldValueLength(serList, itemOffset, itemTag, true) + 1;
+ result.set(serList, itemOffset, itemLength);
} else {
- itemLength =
- NonTaggedFormatUtil.getFieldValueLength(serOrderedList, itemOffset, itemTag, false);
+ int itemLength =
+ NonTaggedFormatUtil.getFieldValueLength(serList, itemOffset, itemTag, false);
resultStorage.reset();
output.writeByte(serItemTypeTag);
- output.write(serOrderedList, itemOffset, itemLength);
+ output.write(serList, itemOffset, itemLength);
result.set(resultStorage);
}
} catch (IOException e) {
diff --git a/asterixdb/asterix-test-framework/src/main/resources/Catalog.xsd b/asterixdb/asterix-test-framework/src/main/resources/Catalog.xsd
index 7a4feea..b6bc7bf 100644
--- a/asterixdb/asterix-test-framework/src/main/resources/Catalog.xsd
+++ b/asterixdb/asterix-test-framework/src/main/resources/Catalog.xsd
@@ -141,6 +141,7 @@
<xs:complexType>
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="value" type="xs:string" />
+ <xs:attribute name="type" type="test:parameter-type-enum" />
</xs:complexType>
</xs:element>
<xs:element name="output-dir" minOccurs="0">
@@ -269,4 +270,20 @@
</xs:restriction>
</xs:simpleType>
+ <!-- parameter-type-enum type -->
+ <!-- Identify the type of a parameter value -->
+
+ <xs:simpleType name="parameter-type-enum">
+ <xs:annotation>
+ <xs:documentation>
+ Identify the type of a parameter value
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="string"/>
+ <xs:enumeration value="json"/>
+ </xs:restriction>
+ </xs:simpleType>
+
</xs:schema>