blob: 6d0b35a67f1828347d8b8004151f118e370b90bb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.vxquery.xmlquery.translator;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.namespace.QName;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
import org.apache.hyracks.algebricks.core.algebra.base.OperatorAnnotations;
import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.AggregateFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistributeResultOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
import org.apache.hyracks.algebricks.core.algebra.typing.ITypingContext;
import org.apache.hyracks.data.std.primitive.DoublePointable;
import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
import org.apache.hyracks.data.std.util.ByteArrayAccessibleOutputStream;
import org.apache.vxquery.compiler.CompilerControlBlock;
import org.apache.vxquery.compiler.algebricks.VXQueryConstantValue;
import org.apache.vxquery.context.StaticContext;
import org.apache.vxquery.context.StaticContextImpl;
import org.apache.vxquery.context.ThinStaticContextImpl;
import org.apache.vxquery.context.XQueryVariable;
import org.apache.vxquery.datamodel.builders.atomic.StringValueBuilder;
import org.apache.vxquery.datamodel.values.ValueTag;
import org.apache.vxquery.exceptions.ErrorCode;
import org.apache.vxquery.exceptions.SystemException;
import org.apache.vxquery.functions.BuiltinFunctions;
import org.apache.vxquery.functions.BuiltinOperators;
import org.apache.vxquery.functions.ExternalFunction;
import org.apache.vxquery.functions.Function;
import org.apache.vxquery.functions.Signature;
import org.apache.vxquery.functions.UserDefinedXQueryFunction;
import org.apache.vxquery.metadata.QueryResultSetDataSink;
import org.apache.vxquery.runtime.functions.cast.CastToDecimalOperation;
import org.apache.vxquery.types.AnyItemType;
import org.apache.vxquery.types.AnyNodeType;
import org.apache.vxquery.types.AnyType;
import org.apache.vxquery.types.AtomicType;
import org.apache.vxquery.types.AttributeType;
import org.apache.vxquery.types.BuiltinTypeConstants;
import org.apache.vxquery.types.BuiltinTypeRegistry;
import org.apache.vxquery.types.CommentType;
import org.apache.vxquery.types.DocumentType;
import org.apache.vxquery.types.ElementType;
import org.apache.vxquery.types.EmptySequenceType;
import org.apache.vxquery.types.ItemType;
import org.apache.vxquery.types.NameTest;
import org.apache.vxquery.types.NodeType;
import org.apache.vxquery.types.ProcessingInstructionType;
import org.apache.vxquery.types.Quantifier;
import org.apache.vxquery.types.SchemaType;
import org.apache.vxquery.types.SequenceType;
import org.apache.vxquery.types.TextType;
import org.apache.vxquery.types.TypeUtils;
import org.apache.vxquery.xmlquery.ast.ASTNode;
import org.apache.vxquery.xmlquery.ast.ASTTag;
import org.apache.vxquery.xmlquery.ast.ArgumentListNode;
import org.apache.vxquery.xmlquery.ast.ArrayConstructor;
import org.apache.vxquery.xmlquery.ast.AtomicTypeNode;
import org.apache.vxquery.xmlquery.ast.AttributeTestNode;
import org.apache.vxquery.xmlquery.ast.AxisStepNode;
import org.apache.vxquery.xmlquery.ast.BaseUriDeclNode;
import org.apache.vxquery.xmlquery.ast.BoundarySpaceDeclNode;
import org.apache.vxquery.xmlquery.ast.CDataSectionNode;
import org.apache.vxquery.xmlquery.ast.ComputedAttributeConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedCommentConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedDocumentConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedElementConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedPIConstructorNode;
import org.apache.vxquery.xmlquery.ast.ComputedTextConstructorNode;
import org.apache.vxquery.xmlquery.ast.ConstructionDeclNode;
import org.apache.vxquery.xmlquery.ast.ContentCharsNode;
import org.apache.vxquery.xmlquery.ast.CopyNamespacesDeclNode;
import org.apache.vxquery.xmlquery.ast.DefaultCollationDeclNode;
import org.apache.vxquery.xmlquery.ast.DefaultElementNamespaceDeclNode;
import org.apache.vxquery.xmlquery.ast.DefaultFunctionNamespaceDeclNode;
import org.apache.vxquery.xmlquery.ast.DirectAttributeConstructorNode;
import org.apache.vxquery.xmlquery.ast.DirectCommentConstructorNode;
import org.apache.vxquery.xmlquery.ast.DirectElementConstructorNode;
import org.apache.vxquery.xmlquery.ast.DirectPIConstructorNode;
import org.apache.vxquery.xmlquery.ast.DocumentTestNode;
import org.apache.vxquery.xmlquery.ast.ElementTestNode;
import org.apache.vxquery.xmlquery.ast.EmptyOrderDeclNode;
import org.apache.vxquery.xmlquery.ast.EnclosedExprNode;
import org.apache.vxquery.xmlquery.ast.ExprNode;
import org.apache.vxquery.xmlquery.ast.ExtensionExprNode;
import org.apache.vxquery.xmlquery.ast.FLWORClauseNode;
import org.apache.vxquery.xmlquery.ast.FLWORExprNode;
import org.apache.vxquery.xmlquery.ast.ForClauseNode;
import org.apache.vxquery.xmlquery.ast.ForVarDeclNode;
import org.apache.vxquery.xmlquery.ast.FunctionDeclNode;
import org.apache.vxquery.xmlquery.ast.FunctionExprNode;
import org.apache.vxquery.xmlquery.ast.GroupSpecNode;
import org.apache.vxquery.xmlquery.ast.GroupbyClauseNode;
import org.apache.vxquery.xmlquery.ast.IfExprNode;
import org.apache.vxquery.xmlquery.ast.InfixExprNode;
import org.apache.vxquery.xmlquery.ast.InfixExprNode.InfixOperator;
import org.apache.vxquery.xmlquery.ast.LetClauseNode;
import org.apache.vxquery.xmlquery.ast.LetVarDeclNode;
import org.apache.vxquery.xmlquery.ast.LibraryModuleNode;
import org.apache.vxquery.xmlquery.ast.LiteralNode;
import org.apache.vxquery.xmlquery.ast.MainModuleNode;
import org.apache.vxquery.xmlquery.ast.ModuleImportNode;
import org.apache.vxquery.xmlquery.ast.ModuleNode;
import org.apache.vxquery.xmlquery.ast.NCNameNode;
import org.apache.vxquery.xmlquery.ast.NameTestNode;
import org.apache.vxquery.xmlquery.ast.NamespaceDeclNode;
import org.apache.vxquery.xmlquery.ast.ObjectConstructor;
import org.apache.vxquery.xmlquery.ast.OptionDeclNode;
import org.apache.vxquery.xmlquery.ast.OrderSpecNode;
import org.apache.vxquery.xmlquery.ast.OrderbyClauseNode;
import org.apache.vxquery.xmlquery.ast.OrderedExprNode;
import org.apache.vxquery.xmlquery.ast.OrderingModeDeclNode;
import org.apache.vxquery.xmlquery.ast.PITestNode;
import org.apache.vxquery.xmlquery.ast.PairConstructor;
import org.apache.vxquery.xmlquery.ast.ParamNode;
import org.apache.vxquery.xmlquery.ast.ParenthesizedExprNode;
import org.apache.vxquery.xmlquery.ast.PathExprNode;
import org.apache.vxquery.xmlquery.ast.PostfixExprNode;
import org.apache.vxquery.xmlquery.ast.PrologNode;
import org.apache.vxquery.xmlquery.ast.QNameNode;
import org.apache.vxquery.xmlquery.ast.QuantifiedExprNode;
import org.apache.vxquery.xmlquery.ast.QuantifiedExprNode.QuantifierType;
import org.apache.vxquery.xmlquery.ast.QuantifiedVarDeclNode;
import org.apache.vxquery.xmlquery.ast.QueryBodyNode;
import org.apache.vxquery.xmlquery.ast.RelativePathExprNode;
import org.apache.vxquery.xmlquery.ast.SchemaImportNode;
import org.apache.vxquery.xmlquery.ast.SequenceTypeNode;
import org.apache.vxquery.xmlquery.ast.SimpleObjectUnionConstructor;
import org.apache.vxquery.xmlquery.ast.SingleTypeNode;
import org.apache.vxquery.xmlquery.ast.TypeDeclNode;
import org.apache.vxquery.xmlquery.ast.TypeExprNode;
import org.apache.vxquery.xmlquery.ast.UnaryExprNode;
import org.apache.vxquery.xmlquery.ast.UnorderedExprNode;
import org.apache.vxquery.xmlquery.ast.ValidateExprNode;
import org.apache.vxquery.xmlquery.ast.VarDeclNode;
import org.apache.vxquery.xmlquery.ast.VarRefNode;
import org.apache.vxquery.xmlquery.ast.VersionDeclNode;
import org.apache.vxquery.xmlquery.ast.WhereClauseNode;
import org.apache.vxquery.xmlquery.query.Module;
import org.apache.vxquery.xmlquery.query.ModuleType;
import org.apache.vxquery.xmlquery.query.XMLQueryCompilerConstants;
import org.apache.vxquery.xmlquery.query.XQueryConstants;
import org.apache.vxquery.xmlquery.query.XQueryConstants.PathType;
import org.apache.vxquery.xmlquery.query.XQueryConstants.TypeQuantifier;
public class XMLQueryTranslator {
private static final Pattern UNQUOTER = Pattern
.compile("(<)|(>)|(')|(&)|(")|(\"\")|('')|(&#\\d+;)|(&#x(?:[A-Fa-f0-9])+;)");
private final CompilerControlBlock ccb;
private final StaticContext rootCtx;
private StaticContext moduleCtx;
private IVariableScope rootVarScope;
private StaticContext currCtx;
private int varCounter;
private final ByteArrayAccessibleOutputStream baaos;
private final DataOutput dOut;
private final StringValueBuilder stringVB;
public XMLQueryTranslator(CompilerControlBlock ccb) {
this.ccb = ccb;
varCounter = 0;
rootCtx = ccb.getStaticContext();
baaos = new ByteArrayAccessibleOutputStream();
dOut = new DataOutputStream(baaos);
stringVB = new StringValueBuilder();
}
private void pushContext() {
currCtx = new ThinStaticContextImpl(currCtx);
}
private void popContext() {
currCtx = currCtx.getParent();
}
public Module translateModule(ModuleNode moduleNode) throws SystemException {
Module module = new Module();
moduleCtx = new StaticContextImpl(rootCtx);
moduleCtx.registerVariable(new XQueryVariable(XMLQueryCompilerConstants.DOT_VAR_NAME,
SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_ONE), newLogicalVariable()));
rootVarScope = new RootVariableScope();
currCtx = moduleCtx;
module.setModuleContext(moduleCtx);
module.setCompilerControlBlock(ccb);
VersionDeclNode ver = moduleNode.getVersion();
if (ver != null) {
if (!"1.0".equals(ver.getVersion())) {
throw new SystemException(ErrorCode.XQST0031, ver.getSourceLocation());
}
}
switch (moduleNode.getTag()) {
case LIBRARY_MODULE: {
module.setModuleType(ModuleType.LIBRARY);
LibraryModuleNode lmNode = (LibraryModuleNode) moduleNode;
String prefix = lmNode.getModuleDecl().getPrefix();
String uri = unquote(lmNode.getModuleDecl().getTargetNS());
if (prefix != null) {
currCtx.registerNamespaceUri(prefix, uri);
}
module.setNamespaceUri(uri);
break;
}
case MAIN_MODULE: {
module.setModuleType(ModuleType.MAIN);
break;
}
default:
throw new IllegalStateException("Unknown module type: " + moduleNode.getTag());
}
PrologNode prologNode = moduleNode.getProlog();
parsePrologPass1(prologNode);
parsePrologPass2(prologNode);
ILogicalPlan plan = null;
switch (moduleNode.getTag()) {
case LIBRARY_MODULE:
throw new SystemException(ErrorCode.TODO);
case MAIN_MODULE:
plan = translateMainModule((MainModuleNode) moduleNode);
}
module.setBody(plan);
return module;
}
@SuppressWarnings("unchecked")
private void parsePrologPass1(PrologNode prologNode) throws SystemException {
if (prologNode != null) {
List<ASTNode> decls = prologNode.getDecls();
for (ASTNode d : decls) {
switch (d.getTag()) {
case DEFAULT_ELEMENT_NAMESPACE_DECLARATION: {
DefaultElementNamespaceDeclNode node = (DefaultElementNamespaceDeclNode) d;
moduleCtx.setDefaultElementNamespaceUri(node.getUri());
break;
}
case DEFAULT_FUNCTION_NAMESPACE_DECLARATION: {
DefaultFunctionNamespaceDeclNode node = (DefaultFunctionNamespaceDeclNode) d;
moduleCtx.setDefaultFunctionNamespaceUri(node.getUri());
break;
}
case BOUNDARY_SPACE_DECLARATION: {
BoundarySpaceDeclNode node = (BoundarySpaceDeclNode) d;
moduleCtx.setBoundarySpaceProperty(node.getMode());
break;
}
case DEFAULT_COLLATION_DECLARATION: {
DefaultCollationDeclNode node = (DefaultCollationDeclNode) d;
moduleCtx.setDefaultCollation(node.getCollation());
break;
}
case BASE_URI_DECLARATION: {
BaseUriDeclNode node = (BaseUriDeclNode) d;
moduleCtx.setBaseUri(node.getUri());
break;
}
case CONSTRUCTION_DECLARATION: {
ConstructionDeclNode node = (ConstructionDeclNode) d;
moduleCtx.setConstructionModeProperty(node.getMode());
break;
}
case ORDERING_MODE_DECLARATION: {
OrderingModeDeclNode node = (OrderingModeDeclNode) d;
moduleCtx.setOrderingModeProperty(node.getMode());
break;
}
case EMPTY_ORDER_DECLARATION: {
EmptyOrderDeclNode node = (EmptyOrderDeclNode) d;
moduleCtx.setEmptyOrderProperty(node.getMode());
break;
}
case COPY_NAMESPACES_DECLARATION: {
CopyNamespacesDeclNode node = (CopyNamespacesDeclNode) d;
moduleCtx.setCopyNamespacesModeProperty(node.getMode());
break;
}
case NAMESPACE_DECLARATION: {
NamespaceDeclNode node = (NamespaceDeclNode) d;
moduleCtx.registerNamespaceUri(node.getPrefix(), unquote(node.getUri()));
break;
}
case SCHEMA_IMPORT: {
SchemaImportNode node = (SchemaImportNode) d;
if (node.isDefaultElementNamespace()) {
moduleCtx.setDefaultElementNamespaceUri(node.getTargetNS());
}
if (node.getPrefix() != null) {
moduleCtx.registerNamespaceUri(node.getPrefix(), unquote(node.getTargetNS()));
}
moduleCtx.registerSchemaImport(node.getTargetNS(), node.getLocations());
break;
}
case MODULE_IMPORT: {
ModuleImportNode node = (ModuleImportNode) d;
if (node.getPrefix() != null) {
moduleCtx.registerNamespaceUri(node.getPrefix(), unquote(node.getTargetNS()));
}
moduleCtx.registerModuleImport(node.getTargetNS(), node.getLocations());
break;
}
case VARIABLE_DECLARATION: {
VarDeclNode node = (VarDeclNode) d;
QName name = createQName(node.getName());
SequenceType type = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
if (node.getType() != null) {
type = createSequenceType(node.getType());
}
LogicalVariable lVar = newLogicalVariable();
XQueryVariable var = new XQueryVariable(name, type, lVar);
moduleCtx.registerVariable(var);
break;
}
case FUNCTION_DECLARATION: {
FunctionDeclNode node = (FunctionDeclNode) d;
boolean external = node.getBody() == null;
QName name = createQName(node.getName(), moduleCtx.getDefaultFunctionNamespaceUri());
String uri = name.getNamespaceURI();
if (XQueryConstants.FN_NSURI.equals(uri) || XQueryConstants.XS_NSURI.equals(uri)
|| XQueryConstants.XSI_NSURI.equals(uri) || XQueryConstants.XML_NSURI.equals(uri)) {
throw new SystemException(ErrorCode.XQST0045, node.getSourceLocation());
}
SequenceType rType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
if (node.getReturnType() != null) {
rType = createSequenceType(node.getReturnType());
}
Pair<QName, SequenceType> paramTypes[] = new Pair[node.getParameters().size()];
for (int i = 0; i < paramTypes.length; ++i) {
ParamNode pNode = node.getParameters().get(i);
QName pName = createQName(pNode.getName());
SequenceType pType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
if (pNode.getType() != null) {
pType = createSequenceType(pNode.getType());
}
paramTypes[i] = Pair.<QName, SequenceType> of(pName, pType);
}
Signature sign = new Signature(rType, paramTypes);
Function f = external ? new ExternalFunction(name, sign)
: new UserDefinedXQueryFunction(name, sign, null);
moduleCtx.registerFunction(f);
break;
}
case OPTION_DECLARATION: {
OptionDeclNode node = (OptionDeclNode) d;
QName name = createQName(node.getName());
moduleCtx.setOption(name, node.getValue());
break;
}
default:
throw new IllegalStateException("Unknown node: " + d.getTag());
}
}
}
}
private void parsePrologPass2(PrologNode prologNode) throws SystemException {
if (prologNode != null) {
List<ASTNode> decls = prologNode.getDecls();
for (ASTNode d : decls) {
switch (d.getTag()) {
case VARIABLE_DECLARATION: {
VarDeclNode node = (VarDeclNode) d;
// TODO Support Global variables
break;
}
case FUNCTION_DECLARATION: {
FunctionDeclNode node = (FunctionDeclNode) d;
boolean external = node.getBody() == null;
if (!external) {
QName name = createQName(node.getName(), moduleCtx.getDefaultFunctionNamespaceUri());
int arity = node.getParameters().size();
UserDefinedXQueryFunction f = (UserDefinedXQueryFunction) moduleCtx.lookupFunction(name,
arity);
Signature sign = f.getSignature();
TranslationContext tCtx = new TranslationContext(null, new EmptyTupleSourceOperator());
XQueryVariable[] params = new XQueryVariable[arity];
for (int i = 0; i < arity; ++i) {
ParamNode pNode = node.getParameters().get(i);
QName pName = createQName(pNode.getName());
SequenceType pType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
if (pNode.getType() != null) {
pType = createSequenceType(pNode.getType());
}
XQueryVariable pVar = new XQueryVariable(pName, pType, newLogicalVariable());
params[i] = pVar;
tCtx.varScope.registerVariable(pVar);
}
f.setParameters(params);
LogicalVariable var = translateExpression(node.getBody(), tCtx);
ILogicalExpression expr = treat(vre(var), sign.getReturnType());
var = createAssignment(expr, tCtx);
f.setBody(new ALogicalPlanImpl(mutable(tCtx.op)));
}
break;
}
}
}
}
}
private SequenceType createSequenceType(ASTNode type) throws SystemException {
switch (type.getTag()) {
case TYPE_DECLARATION: {
TypeDeclNode tDecl = (TypeDeclNode) type;
return createSequenceType(tDecl.getType());
}
case SEQUENCE_TYPE: {
SequenceTypeNode sType = (SequenceTypeNode) type;
if (sType.getItemType() == null) {
return SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
}
TypeQuantifier tq = sType.getQuantifier();
Quantifier q = Quantifier.QUANT_ONE;
if (tq != null) {
switch (tq) {
case QUANT_QUESTION:
q = Quantifier.QUANT_QUESTION;
break;
case QUANT_PLUS:
q = Quantifier.QUANT_PLUS;
break;
case QUANT_STAR:
q = Quantifier.QUANT_STAR;
break;
}
}
ItemType iType = createItemType(sType.getItemType());
return SequenceType.create(iType, q);
}
case EMPTY_SEQUENCE_TYPE: {
return SequenceType.create(EmptySequenceType.INSTANCE, Quantifier.QUANT_ZERO);
}
case SINGLE_TYPE: {
SingleTypeNode stNode = (SingleTypeNode) type;
ItemType iType = createItemType(stNode.getAtomicType());
return SequenceType.create(iType,
stNode.isOptional() ? Quantifier.QUANT_QUESTION : Quantifier.QUANT_ONE);
}
default:
throw new IllegalStateException("Unknown node: " + type.getTag());
}
}
private ItemType createItemType(ASTNode itemType) throws SystemException {
switch (itemType.getTag()) {
case ITEM_TYPE:
return AnyItemType.INSTANCE;
case ATOMIC_TYPE: {
AtomicTypeNode atNode = (AtomicTypeNode) itemType;
QName tName = createQName(atNode.getName());
SchemaType sType = moduleCtx.lookupSchemaType(tName);
if (sType == null || !sType.isAtomicType()) {
throw new SystemException(ErrorCode.XPST0051, atNode.getSourceLocation());
}
return (ItemType) sType;
}
case ANY_NODE_TEST:
return AnyNodeType.INSTANCE;
case DOCUMENT_TEST: {
DocumentTestNode dt = (DocumentTestNode) itemType;
if (dt.getElementTest() == null) {
return DocumentType.ANYDOCUMENT;
}
ElementType eType = (ElementType) createItemType(dt.getElementTest());
return new DocumentType(eType);
}
case TEXT_TEST:
return TextType.INSTANCE;
case COMMENT_TEST:
return CommentType.INSTANCE;
case PI_TEST: {
PITestNode pit = (PITestNode) itemType;
if (pit.getTarget() == null) {
return ProcessingInstructionType.ANYPI;
}
return new ProcessingInstructionType(createUTF8String(pit.getTarget()));
}
case ATTRIBUTE_TEST: {
AttributeTestNode at = (AttributeTestNode) itemType;
if (at.getNameTest() == null) {
return AttributeType.ANYATTRIBUTE;
}
NameTestNode ntNode = at.getNameTest();
NameTest nt = NameTest.STAR_NAMETEST;
if (ntNode.getPrefix() == null && ntNode.getLocalName() == null) {
if (at.getTypeName() == null) {
return AttributeType.ANYATTRIBUTE;
}
} else {
String uri;
if (!"".equals(ntNode.getPrefix())) {
uri = currCtx.lookupNamespaceUri(ntNode.getPrefix());
if (uri == null) {
throw new SystemException(ErrorCode.XPST0081, ntNode.getSourceLocation());
}
} else {
uri = "";
}
nt = new NameTest(createUTF8String(uri), createUTF8String(ntNode.getLocalName()));
}
SchemaType cType = BuiltinTypeRegistry.XS_ANY_ATOMIC;
if (at.getTypeName() != null) {
cType = moduleCtx.lookupSchemaType(createQName(at.getTypeName()));
if (cType == null) {
throw new SystemException(ErrorCode.XPST0051, at.getSourceLocation());
}
}
return new AttributeType(nt, cType);
}
case SCHEMA_ATTRIBUTE_TEST: {
throw new UnsupportedOperationException("schema-attribute(...) is not supported");
}
case ELEMENT_TEST: {
ElementTestNode et = (ElementTestNode) itemType;
if (et.getNameTest() == null) {
return ElementType.ANYELEMENT;
}
NameTestNode ntNode = et.getNameTest();
NameTest nt = NameTest.STAR_NAMETEST;
if (ntNode.getPrefix() == null && ntNode.getLocalName() == null) {
if (et.getTypeName() == null) {
return ElementType.ANYELEMENT;
}
} else {
String uri;
if (!"".equals(ntNode.getPrefix())) {
uri = currCtx.lookupNamespaceUri(ntNode.getPrefix());
if (uri == null) {
throw new SystemException(ErrorCode.XPST0081, ntNode.getSourceLocation());
}
} else {
uri = "";
}
nt = new NameTest(createUTF8String(uri), createUTF8String(ntNode.getLocalName()));
}
SchemaType cType = AnyType.INSTANCE;
if (et.getTypeName() != null) {
cType = moduleCtx.lookupSchemaType(createQName(et.getTypeName()));
if (cType == null) {
throw new SystemException(ErrorCode.XPST0051, et.getSourceLocation());
}
}
return new ElementType(nt, cType, et.isNillable());
}
case SCHEMA_ELEMENT_TEST: {
throw new UnsupportedOperationException("schema-element(...) is not supported");
}
default:
throw new IllegalStateException("Unknown node: " + itemType.getTag());
}
}
private byte[] createUTF8String(String str) {
ArrayBackedValueStorage abvs = new ArrayBackedValueStorage();
StringValueBuilder svb = new StringValueBuilder();
try {
svb.write(str, abvs.getDataOutput());
} catch (IOException e) {
throw new IllegalStateException(e);
}
return Arrays.copyOf(abvs.getByteArray(), abvs.getLength());
}
private ILogicalPlan translateMainModule(MainModuleNode moduleNode) throws SystemException {
QueryBodyNode qbn = moduleNode.getQueryBody();
ASTNode queryBody = qbn.getExpression();
TranslationContext tCtx = new TranslationContext(null, new EmptyTupleSourceOperator());
LogicalVariable lVar = translateExpression(queryBody, tCtx);
LogicalVariable iLVar = newLogicalVariable();
UnnestOperator unnest = new UnnestOperator(iLVar, mutable(ufce(BuiltinOperators.ITERATE, vre(lVar))));
unnest.getInputs().add(mutable(tCtx.op));
List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
exprs.add(mutable(vre(iLVar)));
QueryResultSetDataSink sink = new QueryResultSetDataSink(ccb.getResultSetId(), null);
DistributeResultOperator op = new DistributeResultOperator(exprs, sink);
op.getInputs().add(mutable(unnest));
ALogicalPlanImpl lp = new ALogicalPlanImpl(mutable(op));
return lp;
}
private LogicalVariable translateExpression(ASTNode value, TranslationContext tCtx) throws SystemException {
switch (value.getTag()) {
case EXPRESSION: {
ExprNode node = (ExprNode) value;
return translateExprNode(tCtx, node);
}
case UNARY_EXPRESSION: {
UnaryExprNode ueNode = (UnaryExprNode) value;
return translateUnaryExprNode(tCtx, ueNode);
}
case INFIX_EXPRESSION: {
InfixExprNode ie = (InfixExprNode) value;
return translateInfixExprNode(tCtx, ie);
}
case ENCLOSED_EXPRESSION: {
EnclosedExprNode ee = (EnclosedExprNode) value;
return translateEnclosedExprNode(tCtx, ee);
}
case PATH_EXPRESSION:
return translatePathExpr((PathExprNode) value, tCtx);
case FUNCTION_EXPRESSION: {
FunctionExprNode fnNode = (FunctionExprNode) value;
return translateFunctionExprNode(tCtx, fnNode);
}
case TYPE_EXPRESSION: {
TypeExprNode teNode = (TypeExprNode) value;
return translateTypeExprNode(tCtx, teNode);
}
case EXTENSION_EXPRESSION: {
ExtensionExprNode eNode = (ExtensionExprNode) value;
return translateExtensionExprNode(tCtx, eNode);
}
case PARENTHESIZED_EXPRESSION: {
ParenthesizedExprNode peNode = (ParenthesizedExprNode) value;
return translateParenthisizedExprNode(tCtx, peNode);
}
case LITERAL: {
LiteralNode lNode = (LiteralNode) value;
return translateLiteralNode(tCtx, lNode);
}
case DIRECT_PI_CONSTRUCTOR: {
DirectPIConstructorNode dpicNode = (DirectPIConstructorNode) value;
return translateDirectPIConstructorNode(tCtx, dpicNode);
}
case DIRECT_COMMENT_CONSTRUCTOR: {
DirectCommentConstructorNode dccNode = (DirectCommentConstructorNode) value;
return translateDirectCommentConstructorNode(tCtx, dccNode);
}
case DIRECT_ELEMENT_CONSTRUCTOR: {
DirectElementConstructorNode decNode = (DirectElementConstructorNode) value;
return translateDirectElementConstructorNode(tCtx, decNode);
}
case DIRECT_ATTRIBUTE_CONSTRUCTOR: {
DirectAttributeConstructorNode dacNode = (DirectAttributeConstructorNode) value;
return translateDirectAttributeConstructorNode(tCtx, dacNode);
}
case CONTEXT_ITEM:
return tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME).getLogicalVariable();
case IF_EXPRESSION: {
IfExprNode ieNode = (IfExprNode) value;
return translateIfExprNode(tCtx, ieNode);
}
case VARIABLE_REFERENCE: {
VarRefNode vrNode = (VarRefNode) value;
return translateVarRefNode(tCtx, vrNode);
}
case FLWOR_EXPRESSION: {
FLWORExprNode fNode = (FLWORExprNode) value;
return translateFLWORExprNode(tCtx, fNode);
}
case QUANTIFIED_EXPRESSION: {
QuantifiedExprNode qeNode = (QuantifiedExprNode) value;
return translateQuantifiedExprNode(tCtx, qeNode);
}
/*
case TYPESWITCH_EXPRESSION: {
TypeswitchExprNode teNode = (TypeswitchExprNode) value;
Expression sExpr = translateExpression(teNode.getSwitchExpr());
ForLetVariable tVar = new ForLetVariable(VarTag.LET, createVarName(), sExpr);
tVar.setDeclaredStaticType(SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR));
pushVariableScope();
varScope.registerVariable(tVar);
List<TypeswitchExpression.Case> cases = new ArrayList<TypeswitchExpression.Case>();
for (CaseClauseNode ccNode : teNode.getCaseClauses()) {
SequenceType type = createSequenceType(ccNode.getType());
ForLetVariable caseVar = null;
pushVariableScope();
if (ccNode.getCaseVar() != null) {
caseVar = new ForLetVariable(VarTag.LET, createQName(ccNode.getCaseVar()), new TreatExpression(
currCtx, new VariableReferenceExpression(currCtx, tVar), type));
caseVar.setDeclaredStaticType(type);
varScope.registerVariable(caseVar);
}
Expression cExpr = translateExpression(ccNode.getValueExpr());
TypeswitchExpression.Case c = new TypeswitchExpression.Case(caseVar, type, cExpr);
cases.add(c);
popVariableScope();
}
Expression dExpr = translateExpression(teNode.getDefaultClause());
popVariableScope();
return new TypeswitchExpression(currCtx, tVar, cases, dExpr);
}
*/
case COMPUTED_TEXT_CONSTRUCTOR: {
ComputedTextConstructorNode cNode = (ComputedTextConstructorNode) value;
return translateComputedTextConstructorNode(tCtx, cNode);
}
case COMPUTED_PI_CONSTRUCTOR: {
ComputedPIConstructorNode cNode = (ComputedPIConstructorNode) value;
return translateComputedPIConstructorNode(tCtx, cNode);
}
case COMPUTED_COMMENT_CONSTRUCTOR: {
ComputedCommentConstructorNode cNode = (ComputedCommentConstructorNode) value;
return translateComputedCommentConstructorNode(tCtx, cNode);
}
case COMPUTED_DOCUMENT_CONSTRUCTOR: {
ComputedDocumentConstructorNode cNode = (ComputedDocumentConstructorNode) value;
return translateComputedDocumentConstructorNode(tCtx, cNode);
}
case COMPUTED_ELEMENT_CONSTRUCTOR: {
ComputedElementConstructorNode cNode = (ComputedElementConstructorNode) value;
return translateComputedElementConstructorNode(tCtx, cNode);
}
case ARRAY_CONSTRUCTOR: {
ArrayConstructor aNode = (ArrayConstructor) value;
return translateArrayConstructor(tCtx, aNode);
}
case COMPUTED_ATTRIBUTE_CONSTRUCTOR: {
ComputedAttributeConstructorNode cNode = (ComputedAttributeConstructorNode) value;
return translateComputedAttributeConstructorNode(tCtx, cNode);
}
case OBJECT_CONSTRUCTOR: {
ObjectConstructor obj = (ObjectConstructor) value;
return translateObjectConstructor(tCtx, obj);
}
case SIMPLE_OBJECT_UNION_CONSTRUCTOR: {
SimpleObjectUnionConstructor aNode = (SimpleObjectUnionConstructor) value;
return translateSimpleObjectUnionConstructor(tCtx, aNode);
}
case QNAME: {
QNameNode qnNode = (QNameNode) value;
return translateQNameNode(tCtx, qnNode);
}
case NCNAME: {
NCNameNode ncnNode = (NCNameNode) value;
return translateNCNameNode(tCtx, ncnNode);
}
case CDATA_SECTION: {
CDataSectionNode cdsNode = (CDataSectionNode) value;
return translateCDataSectionNode(tCtx, cdsNode);
}
case ORDERED_EXPRESSION: {
OrderedExprNode oeNode = (OrderedExprNode) value;
return translateOrderedExprNode(tCtx, oeNode);
}
case UNORDERED_EXPRESSION: {
UnorderedExprNode ueNode = (UnorderedExprNode) value;
return translateUnorderedExprNode(tCtx, ueNode);
}
case VALIDATE_EXPRESSION: {
ValidateExprNode vNode = (ValidateExprNode) value;
return translateValidateExprNode(tCtx, vNode);
}
default:
throw new IllegalStateException("Unknown node: " + value.getTag());
}
}
private LogicalVariable translateQuantifiedExprNode(TranslationContext tCtx, QuantifiedExprNode qeNode)
throws SystemException {
tCtx = tCtx.pushContext();
int pushCount = 0;
for (QuantifiedVarDeclNode qvdNode : qeNode.getVariables()) {
ILogicalExpression seq = vre(translateExpression(qvdNode.getSequence(), tCtx));
tCtx.pushVariableScope();
LogicalVariable forLVar = newLogicalVariable();
UnnestOperator unnest = new UnnestOperator(forLVar, mutable(ufce(BuiltinOperators.ITERATE, seq)));
SequenceType forVarType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_ONE);
if (qvdNode.getType() != null) {
forVarType = createSequenceType(qvdNode.getType());
}
XQueryVariable forVar = new XQueryVariable(createQName(qvdNode.getVariable()), forVarType, forLVar);
tCtx.varScope.registerVariable(forVar);
unnest.getInputs().add(mutable(tCtx.op));
tCtx.op = unnest;
++pushCount;
}
ILogicalExpression satExpr = sfce(BuiltinFunctions.FN_BOOLEAN_1,
vre(translateExpression(qeNode.getSatisfiesExpr(), tCtx)));
if (qeNode.getQuant() == QuantifierType.EVERY) {
satExpr = sfce(BuiltinFunctions.FN_NOT_1, satExpr);
}
SelectOperator select = new SelectOperator(mutable(satExpr), false, null);
select.getInputs().add(mutable(tCtx.op));
tCtx.op = select;
List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
LogicalVariable var = newLogicalVariable();
vars.add(var);
exprs.add(mutable(afce(BuiltinOperators.SEQUENCE, false,
ce(SequenceType.create(BuiltinTypeRegistry.XS_BOOLEAN, Quantifier.QUANT_ONE), Boolean.TRUE))));
AggregateOperator aop = new AggregateOperator(vars, exprs);
aop.getInputs().add(mutable(tCtx.op));
tCtx.op = aop;
for (int i = 0; i < pushCount; ++i) {
tCtx.popVariableScope();
}
tCtx = tCtx.popContext();
LogicalVariable lVar = createAssignment(sfce(
qeNode.getQuant() == QuantifierType.EVERY ? BuiltinFunctions.FN_EMPTY_1 : BuiltinFunctions.FN_EXISTS_1,
vre(var)), tCtx);
return lVar;
}
private LogicalVariable translateUnorderedExprNode(TranslationContext tCtx, UnorderedExprNode ueNode)
throws SystemException {
LogicalVariable lVar = createAssignment(
sfce(BuiltinOperators.UNORDERED, vre(translateExpression(ueNode.getExpr(), tCtx))), tCtx);
return lVar;
}
private LogicalVariable translateOrderedExprNode(TranslationContext tCtx, OrderedExprNode oeNode)
throws SystemException {
LogicalVariable lVar = createAssignment(
sfce(BuiltinOperators.ORDERED, vre(translateExpression(oeNode.getExpr(), tCtx))), tCtx);
return lVar;
}
private LogicalVariable translateCDataSectionNode(TranslationContext tCtx, CDataSectionNode cdsNode)
throws SystemException {
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.TEXT_CONSTRUCTOR,
ce(SequenceType.create(BuiltinTypeRegistry.XS_UNTYPED_ATOMIC, Quantifier.QUANT_ONE),
cdsNode.getContent())),
tCtx);
return lVar;
}
private LogicalVariable translateNCNameNode(TranslationContext tCtx, NCNameNode ncnNode) throws SystemException {
LogicalVariable lVar = createAssignment(
ce(SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE), ncnNode.getName()), tCtx);
return lVar;
}
private LogicalVariable translateQNameNode(TranslationContext tCtx, QNameNode qnNode) throws SystemException {
LogicalVariable lVar = createAssignment(
ce(SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE), createQName(qnNode)), tCtx);
return lVar;
}
private LogicalVariable translateValidateExprNode(TranslationContext tCtx, ValidateExprNode vNode)
throws SystemException {
XQueryConstants.ValidationMode mode = vNode.getMode();
Function fn = mode == null || XQueryConstants.ValidationMode.STRICT.equals(mode)
? BuiltinOperators.VALIDATE_STRICT : BuiltinOperators.VALIDATE_LAX;
LogicalVariable lVar = createAssignment(sfce(fn, vre(translateExpression(vNode.getExpr(), tCtx))), tCtx);
return lVar;
}
private LogicalVariable translateComputedAttributeConstructorNode(TranslationContext tCtx,
ComputedAttributeConstructorNode cNode) throws SystemException {
ILogicalExpression name = cast(vre(translateExpression(cNode.getName(), tCtx)),
SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE));
ASTNode content = cNode.getContent();
ILogicalExpression cExpr = content == null ? sfce(BuiltinOperators.CONCATENATE)
: vre(translateExpression(content, tCtx));
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ATTRIBUTE_CONSTRUCTOR, name, cExpr), tCtx);
return lVar;
}
private LogicalVariable translateComputedElementConstructorNode(TranslationContext tCtx,
ComputedElementConstructorNode cNode) throws SystemException {
ILogicalExpression name = cast(vre(translateExpression(cNode.getName(), tCtx)),
SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE));
ASTNode content = cNode.getContent();
ILogicalExpression cExpr = content == null ? sfce(BuiltinOperators.CONCATENATE)
: vre(translateExpression(content, tCtx));
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ELEMENT_CONSTRUCTOR, name, cExpr), tCtx);
return lVar;
}
private LogicalVariable translateArrayConstructor(TranslationContext tCtx, ArrayConstructor aNode)
throws SystemException {
ASTNode expression = aNode.getExpression();
ILogicalExpression aExpr = expression == null ? sfce(BuiltinOperators.CONCATENATE)
: vre(translateExpression(expression, tCtx));
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ARRAY_CONSTRUCTOR, aExpr), tCtx);
return lVar;
}
private LogicalVariable translateComputedDocumentConstructorNode(TranslationContext tCtx,
ComputedDocumentConstructorNode cNode) throws SystemException {
LogicalVariable lVar = createAssignment(
sfce(BuiltinOperators.DOCUMENT_CONSTRUCTOR, vre(translateExpression(cNode.getContent(), tCtx))), tCtx);
return lVar;
}
private LogicalVariable translateComputedCommentConstructorNode(TranslationContext tCtx,
ComputedCommentConstructorNode cNode) throws SystemException {
ASTNode content = cNode.getContent();
LogicalVariable lVar = createAssignment(
sfce(BuiltinOperators.COMMENT_CONSTRUCTOR,
content == null ? sfce(BuiltinOperators.CONCATENATE) : vre(translateExpression(content, tCtx))),
tCtx);
return lVar;
}
private LogicalVariable translateComputedPIConstructorNode(TranslationContext tCtx, ComputedPIConstructorNode cNode)
throws SystemException {
ASTNode content = cNode.getContent();
LogicalVariable lVar = createAssignment(
sfce(BuiltinOperators.PI_CONSTRUCTOR, vre(translateExpression(cNode.getTarget(), tCtx)),
content == null ? sfce(BuiltinOperators.CONCATENATE) : vre(translateExpression(content, tCtx))),
tCtx);
return lVar;
}
private LogicalVariable translateComputedTextConstructorNode(TranslationContext tCtx,
ComputedTextConstructorNode cNode) throws SystemException {
ASTNode content = cNode.getContent();
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.TEXT_CONSTRUCTOR,
content == null
? ce(SequenceType.create(BuiltinTypeRegistry.XS_UNTYPED_ATOMIC, Quantifier.QUANT_ONE), "")
: vre(translateExpression(content, tCtx))),
tCtx);
return lVar;
}
private LogicalVariable translateFLWORExprNode(TranslationContext tCtx, FLWORExprNode fNode)
throws SystemException {
tCtx = tCtx.pushContext();
List<FLWORClauseNode> cNodes = fNode.getClauses();
int pushCount = 0;
for (FLWORClauseNode cNode : cNodes) {
switch (cNode.getTag()) {
case FOR_CLAUSE: {
ForClauseNode fcNode = (ForClauseNode) cNode;
for (ForVarDeclNode fvdNode : fcNode.getVariables()) {
ILogicalExpression seq = vre(translateExpression(fvdNode.getSequence(), tCtx));
tCtx.pushVariableScope();
LogicalVariable forLVar = newLogicalVariable();
LogicalVariable posLVar = fvdNode.getPosVar() != null ? newLogicalVariable() : null;
UnnestOperator unnest = new UnnestOperator(forLVar,
mutable(ufce(BuiltinOperators.ITERATE, seq)), posLVar, BuiltinTypeRegistry.XS_INTEGER,
new VXQueryPositionWriter());
SequenceType forVarType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_ONE);
if (fvdNode.getType() != null) {
forVarType = createSequenceType(fvdNode.getType());
}
XQueryVariable forVar = new XQueryVariable(createQName(fvdNode.getForVar()), forVarType,
forLVar);
tCtx.varScope.registerVariable(forVar);
XQueryVariable posVar = null;
if (fvdNode.getPosVar() != null) {
posVar = new XQueryVariable(createQName(fvdNode.getPosVar()),
SequenceType.create(BuiltinTypeRegistry.XS_INTEGER, Quantifier.QUANT_ONE), posLVar);
tCtx.varScope.registerVariable(posVar);
}
assert fvdNode.getScoreVar() == null;
unnest.getInputs().add(mutable(tCtx.op));
tCtx.op = unnest;
++pushCount;
}
break;
}
case LET_CLAUSE: {
LetClauseNode lcNode = (LetClauseNode) cNode;
for (LetVarDeclNode lvdNode : lcNode.getVariables()) {
LogicalVariable seqVar = translateExpression(lvdNode.getSequence(), tCtx);
tCtx.pushVariableScope();
SequenceType letVarType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_STAR);
if (lvdNode.getType() != null) {
letVarType = createSequenceType(lvdNode.getType());
}
XQueryVariable letVar = new XQueryVariable(createQName(lvdNode.getLetVar()), letVarType,
seqVar);
tCtx.varScope.registerVariable(letVar);
++pushCount;
}
break;
}
case WHERE_CLAUSE: {
WhereClauseNode wcNode = (WhereClauseNode) cNode;
ILogicalExpression condExpr = sfce(BuiltinFunctions.FN_BOOLEAN_1,
vre(translateExpression(wcNode.getCondition(), tCtx)));
SelectOperator select = new SelectOperator(mutable(condExpr), false, null);
select.getInputs().add(mutable(tCtx.op));
tCtx.op = select;
break;
}
case ORDERBY_CLAUSE: {
OrderbyClauseNode ocNode = (OrderbyClauseNode) cNode;
List<org.apache.hyracks.algebricks.common.utils.Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>> oExprs = new ArrayList<org.apache.hyracks.algebricks.common.utils.Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>>();
List<String> collations = new ArrayList<String>();
for (OrderSpecNode osNode : ocNode.getOrderSpec()) {
ILogicalExpression aExpr = data(vre(translateExpression(osNode.getExpression(), tCtx)));
ILogicalExpression oExpr = vre(createAssignment(aExpr, tCtx));
OrderOperator.IOrder o = OrderOperator.ASC_ORDER;
XQueryConstants.OrderDirection oDir = osNode.getDirection();
if (oDir != null) {
switch (oDir) {
case ASCENDING:
o = OrderOperator.ASC_ORDER;
break;
case DESCENDING:
o = OrderOperator.DESC_ORDER;
break;
}
}
/*
StaticContext.EmptyOrderProperty eoProp = osNode.getEmptyOrder();
if (eoProp != null) {
switch (osNode.getEmptyOrder()) {
case GREATEST:
eOrders.add(FLWORExpression.EmptyOrder.GREATEST);
break;
case LEAST:
eOrders.add(FLWORExpression.EmptyOrder.LEAST);
break;
}
} else {
eOrders.add(FLWORExpression.EmptyOrder.DEFAULT);
}
collations.add(osNode.getCollation());
*/
oExprs.add(
new org.apache.hyracks.algebricks.common.utils.Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>(
o, mutable(oExpr)));
}
OrderOperator order = new OrderOperator(oExprs);
order.getInputs().add(mutable(tCtx.op));
tCtx.op = order;
break;
}
case GROUPBY_CLAUSE: {
GroupbyClauseNode gcNode = (GroupbyClauseNode) cNode;
GroupByOperator group = new GroupByOperator();
ArrayList<XQueryVariable> al = new ArrayList<XQueryVariable>();
ArrayList<ILogicalExpression> expr = new ArrayList<ILogicalExpression>();
ArrayList<QName> qvar = new ArrayList<QName>();
ArrayList<TypeDeclNode> stype = new ArrayList<TypeDeclNode>();
//set the groupbyexpression list of the group by operator
for (GroupSpecNode gsNode : gcNode.getGroupSpec()) {//data and createAssignment
if (gsNode.getExpr() != null) {
expr.add(vre(createAssignment(
zeroOrOne(data(vre(translateExpression(gsNode.getExpr(), tCtx)))), tCtx)));
} else {
XQueryVariable x = tCtx.varScope.lookupVariable(createQName(gsNode.getVar()));
expr.add(vre(createAssignment(data(vre(x.getLogicalVariable())), tCtx)));
}
qvar.add(createQName(gsNode.getVar()));
stype.add(gsNode.getType());
}
while (pushCount > 0) {
al.add(tCtx.varScope.listVariables().next());
tCtx.popVariableScope();
--pushCount;
}
group.getInputs().add(mutable(tCtx.op));
for (int i = 0; i < qvar.size(); i++) {
LogicalVariable groupVar = newLogicalVariable();
tCtx.pushVariableScope();
SequenceType groupVarType = SequenceType.create(BuiltinTypeRegistry.XS_ANY_ATOMIC,
Quantifier.QUANT_QUESTION);
if (stype.get(i) != null) {
groupVarType = createSequenceType(stype.get(i));
}
XQueryVariable z = new XQueryVariable(qvar.get(i), groupVarType, groupVar);
tCtx.varScope.registerVariable(z);
group.addGbyExpression(groupVar, expr.get(i));
++pushCount;
}
//set the nested plans of the group by operator
for (int j = 0; j < al.size(); j++) {
XQueryVariable xqv = al.get(j);
ILogicalExpression sequenceInput = vre(xqv.getLogicalVariable());
tCtx.pushVariableScope();
AggregateFunctionCallExpression fsequence = (AggregateFunctionCallExpression) afce(
BuiltinOperators.SEQUENCE, false, sequenceInput);
LogicalVariable aggVar = newLogicalVariable();
AggregateOperator agg = new AggregateOperator(mkSingletonArrayList(aggVar),
mkSingletonArrayList(new MutableObject<>(fsequence)));
agg.getInputs()
.add(new MutableObject<>(new NestedTupleSourceOperator(new MutableObject<>(group))));
ILogicalPlan plan = new ALogicalPlanImpl(new MutableObject<>(agg));
group.getNestedPlans().add(plan);
SequenceType aggVarType = SequenceType.create(xqv.getType().getItemType(),
Quantifier.QUANT_STAR);
XQueryVariable nagg = new XQueryVariable(xqv.getName(), aggVarType, aggVar);
tCtx.varScope.registerVariable(nagg);
pushCount++;
}
tCtx.op = group;
break;
}
default:
throw new IllegalStateException("Unknown clause: " + cNode.getTag());
}
}
ILogicalExpression rExpr = vre(translateExpression(fNode.getReturnExpr(), tCtx));
List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
LogicalVariable var = newLogicalVariable();
vars.add(var);
exprs.add(mutable(afce(BuiltinOperators.SEQUENCE, false, rExpr)));
AggregateOperator aop = new AggregateOperator(vars, exprs);
aop.getInputs().add(mutable(tCtx.op));
tCtx.op = aop;
for (int i = 0; i < pushCount; ++i) {
tCtx.popVariableScope();
}
tCtx = tCtx.popContext();
return var;
}
protected <T> List<T> mkSingletonArrayList(T item) {
ArrayList<T> array = new ArrayList<>(1);
array.add(item);
return array;
}
private LogicalVariable translateVarRefNode(TranslationContext tCtx, VarRefNode vrNode) throws SystemException {
QName vName = createQName(vrNode.getVariable());
XQueryVariable var = tCtx.varScope.lookupVariable(vName);
if (var == null) {
throw new SystemException(ErrorCode.XPST0008, vrNode.getSourceLocation());
}
LogicalVariable lVar = createAssignment(treat(vre(var.getLogicalVariable()), var.getType()), tCtx);
return lVar;
}
private LogicalVariable translateIfExprNode(TranslationContext tCtx, IfExprNode ieNode) throws SystemException {
ILogicalExpression cond = sfce(BuiltinFunctions.FN_BOOLEAN_1,
vre(translateExpression(ieNode.getIfExpr(), tCtx)));
ILogicalExpression tExpr = vre(translateExpression(ieNode.getThenExpr(), tCtx));
ILogicalExpression eExpr = vre(translateExpression(ieNode.getElseExpr(), tCtx));
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.IF_THEN_ELSE, cond, tExpr, eExpr), tCtx);
return lVar;
}
private LogicalVariable translateDirectAttributeConstructorNode(TranslationContext tCtx,
DirectAttributeConstructorNode dacNode) throws SystemException {
QName aQName = createQName(dacNode.getName());
ILogicalExpression name = ce(SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE), aQName);
List<ILogicalExpression> content = new ArrayList<ILogicalExpression>();
for (ASTNode aVal : dacNode.getValue()) {
switch (aVal.getTag()) {
case CONTENT_CHARS: {
String contentChars = ((ContentCharsNode) aVal).getContent();
ILogicalExpression cce = ce(
SequenceType.create(BuiltinTypeRegistry.XS_UNTYPED_ATOMIC, Quantifier.QUANT_ONE),
contentChars);
content.add(cce);
break;
}
default:
content.add(data(vre(translateExpression(aVal, tCtx))));
}
}
ILogicalExpression contentExpr = content.size() == 1 ? content.get(0)
: sfce(BuiltinOperators.CONCATENATE, content.toArray(new ILogicalExpression[content.size()]));
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ATTRIBUTE_CONSTRUCTOR, name, contentExpr), tCtx);
return lVar;
}
private LogicalVariable translateObjectConstructor(TranslationContext tCtx, ObjectConstructor obj)
throws SystemException {
List<ILogicalExpression> content = new ArrayList<ILogicalExpression>();
PairConstructor pc;
for (ASTNode aVal : obj.getContent()) {
pc = (PairConstructor) aVal;
ILogicalExpression ke = string(data(vre(translateExpression(pc.getKey(), tCtx))));
content.add(ke);
ILogicalExpression ve = vre(translateExpression(pc.getValue(), tCtx));
content.add(ve);
ILogicalExpression qmce = ce(SequenceType.create(BuiltinTypeRegistry.XS_BOOLEAN, Quantifier.QUANT_ONE),
pc.isQuestionMarkColon());
content.add(qmce);
}
return createAssignment(
sfce(BuiltinOperators.OBJECT_CONSTRUCTOR, content.toArray(new ILogicalExpression[content.size()])),
tCtx);
}
private LogicalVariable translateSimpleObjectUnionConstructor(TranslationContext tCtx,
SimpleObjectUnionConstructor aNode) throws SystemException {
ASTNode expression = aNode.getExpression();
ILogicalExpression aExpr = expression == null ? sfce(BuiltinOperators.CONCATENATE)
: vre(translateExpression(expression, tCtx));
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.SIMPLE_OBJECT_UNION, aExpr), tCtx);
return lVar;
}
private LogicalVariable translateDirectElementConstructorNode(TranslationContext tCtx,
DirectElementConstructorNode decNode) throws SystemException {
QNameNode startName = decNode.getStartTagName();
QNameNode endName = decNode.getEndTagName();
if (endName != null && (!startName.getPrefix().equals(endName.getPrefix())
|| !startName.getLocalName().equals(endName.getLocalName()))) {
throw new SystemException(ErrorCode.XPST0003, endName.getSourceLocation());
}
pushContext();
for (DirectAttributeConstructorNode acNode : decNode.getAttributes()) {
QNameNode aName = acNode.getName();
if ("xmlns".equals(aName.getPrefix())) {
List<ASTNode> values = acNode.getValue();
if (values.size() != 1 || !ASTTag.CONTENT_CHARS.equals(values.get(0).getTag())) {
throw new SystemException(ErrorCode.XQST0022, acNode.getSourceLocation());
}
currCtx.registerNamespaceUri(aName.getLocalName(),
unquote(((ContentCharsNode) values.get(0)).getContent()));
}
}
List<ILogicalExpression> content = new ArrayList<ILogicalExpression>();
for (DirectAttributeConstructorNode acNode : decNode.getAttributes()) {
QNameNode aName = acNode.getName();
if (!"xmlns".equals(aName.getPrefix())) {
content.add(vre(translateExpression(acNode, tCtx)));
}
}
ILogicalExpression name = ce(SequenceType.create(BuiltinTypeRegistry.XS_QNAME, Quantifier.QUANT_ONE),
createQName(startName, moduleCtx.getDefaultElementNamespaceUri()));
for (ASTNode cVal : decNode.getContent()) {
switch (cVal.getTag()) {
case CONTENT_CHARS: {
String contentChars = ((ContentCharsNode) cVal).getContent();
ILogicalExpression cce = ce(
SequenceType.create(BuiltinTypeRegistry.XS_UNTYPED_ATOMIC, Quantifier.QUANT_ONE),
contentChars);
content.add(sfce(BuiltinOperators.TEXT_CONSTRUCTOR, cce));
break;
}
default:
content.add(vre(translateExpression(cVal, tCtx)));
}
}
popContext();
ILogicalExpression contentExpr = content.size() == 1 ? content.get(0)
: sfce(BuiltinOperators.CONCATENATE, content.toArray(new ILogicalExpression[content.size()]));
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.ELEMENT_CONSTRUCTOR, name, contentExpr), tCtx);
return lVar;
}
private LogicalVariable translateDirectCommentConstructorNode(TranslationContext tCtx,
DirectCommentConstructorNode dccNode) throws SystemException {
String content = dccNode.getContent();
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.COMMENT_CONSTRUCTOR,
ce(SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE), content)), tCtx);
return lVar;
}
private LogicalVariable translateDirectPIConstructorNode(TranslationContext tCtx, DirectPIConstructorNode dpicNode)
throws SystemException {
String target = dpicNode.getTarget();
String content = dpicNode.getContent();
LogicalVariable lVar = createAssignment(sfce(BuiltinOperators.PI_CONSTRUCTOR,
ce(SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE), target),
ce(SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE), content)), tCtx);
return lVar;
}
private LogicalVariable translateLiteralNode(TranslationContext tCtx, LiteralNode lNode) throws SystemException {
String image = lNode.getImage();
LiteralNode.LiteralType lType = lNode.getType();
SequenceType t = null;
Object value = null;
switch (lType) {
case DECIMAL:
t = SequenceType.create(BuiltinTypeRegistry.XS_DECIMAL, Quantifier.QUANT_ONE);
value = Double.parseDouble(image);
break;
case DOUBLE:
t = SequenceType.create(BuiltinTypeRegistry.XS_DOUBLE, Quantifier.QUANT_ONE);
value = Double.parseDouble(image);
break;
case INTEGER:
t = SequenceType.create(BuiltinTypeRegistry.XS_INTEGER, Quantifier.QUANT_ONE);
try {
value = Long.parseLong(image);
} catch (NumberFormatException nfe) {
throw new SystemException(ErrorCode.FOAR0002);
}
break;
case STRING:
t = SequenceType.create(BuiltinTypeRegistry.XS_STRING, Quantifier.QUANT_ONE);
value = unquote(image);
break;
case NULL:
t = SequenceType.create(BuiltinTypeRegistry.JS_NULL, Quantifier.QUANT_ONE);
value = null;
break;
default:
throw new IllegalStateException("Unknown type: " + lType);
}
LogicalVariable lVar = createAssignment(ce(t, value), tCtx);
return lVar;
}
private LogicalVariable translateParenthisizedExprNode(TranslationContext tCtx, ParenthesizedExprNode peNode)
throws SystemException {
ASTNode eNode = peNode.getExpr();
if (eNode == null) {
return createConcatenation(Collections.<LogicalVariable> emptyList(), tCtx);
}
return translateExpression(peNode.getExpr(), tCtx);
}
private LogicalVariable translateExtensionExprNode(TranslationContext tCtx, ExtensionExprNode eNode)
throws SystemException {
if (eNode.getExpr() == null) {
throw new SystemException(ErrorCode.XQST0079, eNode.getSourceLocation());
}
return translateExpression(eNode.getExpr(), tCtx);
}
private LogicalVariable translateTypeExprNode(TranslationContext tCtx, TypeExprNode teNode) throws SystemException {
LogicalVariable var = translateExpression(teNode.getExpr(), tCtx);
SequenceType type = createSequenceType(teNode.getType());
ILogicalExpression expr = null;
switch (teNode.getOperator()) {
case CAST:
expr = cast(vre(var), type);
break;
case CASTABLE:
expr = castable(vre(var), type);
break;
case INSTANCEOF:
expr = instanceOf(vre(var), type);
break;
case TREAT:
expr = treat(vre(var), type);
break;
default:
throw new IllegalStateException("Unknown type operator: " + teNode.getOperator());
}
LogicalVariable lVar = createAssignment(expr, tCtx);
return lVar;
}
private LogicalVariable translateFunctionExprNode(TranslationContext tCtx, FunctionExprNode fnNode)
throws SystemException {
List<LogicalVariable> args = new ArrayList<LogicalVariable>();
for (ASTNode an : fnNode.getArguments()) {
args.add(translateExpression(an, tCtx));
}
QName name = createQName(fnNode.getName());
SchemaType type = moduleCtx.lookupSchemaType(name);
if (type != null && args.size() < 2) {
if (!type.isAtomicType()) {
throw new SystemException(ErrorCode.XPST0051, fnNode.getName().getSourceLocation());
}
LogicalVariable var = args.isEmpty()
? tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME).getLogicalVariable()
: args.get(0);
ILogicalExpression expr = cast(vre(var), SequenceType.create((ItemType) type, Quantifier.QUANT_QUESTION));
return createAssignment(expr, tCtx);
}
QName fName = createQName(fnNode.getName(), moduleCtx.getDefaultFunctionNamespaceUri());
if (BuiltinFunctions.FN_POSITION_QNAME.equals(fName)) {
XQueryVariable var = tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.POS_VAR_NAME);
return var.getLogicalVariable();
}
if (BuiltinFunctions.FN_LAST_QNAME.equals(fName)) {
XQueryVariable var = tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.LAST_VAR_NAME);
return var.getLogicalVariable();
}
int nArgs = fnNode.getArguments().size();
Function fn = moduleCtx.lookupFunction(fName, nArgs);
if (fn != null && fn.useContextImplicitly()) {
args.add(tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME).getLogicalVariable());
fn = moduleCtx.lookupFunction(fName, nArgs + 1);
}
if (fn == null) {
Function[] fns = moduleCtx.lookupFunctions(fName);
if (fns != null) {
for (int i = 0; i < fns.length && i <= nArgs; ++i) {
if (fns[i] != null && fns[i].getSignature().isVarArgs()) {
fn = fns[i];
break;
}
}
}
}
if (fn == null) {
throw new SystemException(ErrorCode.XPST0017, fnNode.getName().getSourceLocation());
}
Signature sign = fn.getSignature();
List<Mutable<ILogicalExpression>> argExprs = new ArrayList<Mutable<ILogicalExpression>>();
for (int i = 0; i < args.size(); ++i) {
SequenceType argType = sign.getParameterType(i);
argExprs.add(mutable(normalize(vre(args.get(i)), argType)));
}
LogicalVariable lVar = createAssignment(new ScalarFunctionCallExpression(fn, argExprs), tCtx);
return lVar;
}
private LogicalVariable translateEnclosedExprNode(TranslationContext tCtx, EnclosedExprNode ee)
throws SystemException {
return translateExpression(ee.getExpression(), tCtx);
}
private LogicalVariable translateInfixExprNode(TranslationContext tCtx, InfixExprNode ie) throws SystemException {
Function operator = getOperator(ie.getOperator());
Signature sign = operator.getSignature();
LogicalVariable varLeft = translateExpression(ie.getLeftExpr(), tCtx);
LogicalVariable varRight = translateExpression(ie.getRightExpr(), tCtx);
ILogicalExpression arg1 = normalize(vre(varLeft), sign.getParameterType(0));
ILogicalExpression arg2 = normalize(vre(varRight), sign.getParameterType(1));
if (BuiltinOperators.EXCEPT.equals(operator) || BuiltinOperators.INTERSECT.equals(operator)) {
arg1 = sfce(BuiltinOperators.SORT_DISTINCT_NODES_ASC, arg1);
arg2 = sfce(BuiltinOperators.SORT_DISTINCT_NODES_ASC, arg2);
}
ILogicalExpression result = sfce(operator, arg1, arg2);
if (BuiltinOperators.UNION.equals(operator)) {
result = sfce(BuiltinOperators.SORT_DISTINCT_NODES_ASC, result);
}
LogicalVariable lVar = createAssignment(result, tCtx);
return lVar;
}
private LogicalVariable translateUnaryExprNode(TranslationContext tCtx, UnaryExprNode ueNode)
throws SystemException {
boolean neg = false;
for (UnaryExprNode.Sign s : ueNode.getSigns()) {
if (UnaryExprNode.Sign.MINUS.equals(s)) {
neg = !neg;
}
}
LogicalVariable var = translateExpression(ueNode.getExpr(), tCtx);
if (neg) {
ILogicalExpression nExpr = normalize(vre(var),
BuiltinOperators.NUMERIC_UNARY_MINUS.getSignature().getParameterType(0));
ILogicalExpression negExpr = sfce(BuiltinOperators.NUMERIC_UNARY_MINUS, nExpr);
var = createAssignment(negExpr, tCtx);
}
return var;
}
private LogicalVariable translateExprNode(TranslationContext tCtx, ExprNode node) throws SystemException {
return createConcatenation(translateExpressionList(node.getExpressions(), tCtx), tCtx);
}
private LogicalVariable translatePathExpr(PathExprNode pe, TranslationContext tCtx) throws SystemException {
ILogicalExpression ctxExpr = null;
PathType type = pe.getPathType();
if (type != null) {
XQueryVariable dotVar = tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME);
ILogicalExpression root = sfce(BuiltinFunctions.FN_ROOT_1, vre(dotVar.getLogicalVariable()));
if (PathType.SLASH.equals(type)) {
ctxExpr = root;
} else {
ctxExpr = sfce(BuiltinOperators.DESCENDANT_OR_SELF,
treat(root, SequenceType.create(AnyNodeType.INSTANCE, Quantifier.QUANT_STAR)));
}
}
if (pe.getPaths() != null) {
for (RelativePathExprNode rpen : pe.getPaths()) {
boolean asc = true;
if (PathType.SLASH_SLASH.equals(rpen.getPathType())) {
tCtx = tCtx.pushContext();
tCtx.pushVariableScope();
iterateOver(ctxExpr, tCtx);
ctxExpr = vre(
tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME).getLogicalVariable());
ctxExpr = sfce(BuiltinOperators.DESCENDANT_OR_SELF,
treat(ctxExpr, SequenceType.create(AnyNodeType.INSTANCE, Quantifier.QUANT_STAR)));
List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
LogicalVariable var = newLogicalVariable();
vars.add(var);
exprs.add(mutable(afce(BuiltinOperators.SEQUENCE, false, ctxExpr)));
AggregateOperator aop = new AggregateOperator(vars, exprs);
aop.getInputs().add(mutable(tCtx.op));
tCtx.op = aop;
tCtx = tCtx.popContext();
ctxExpr = vre(var);
}
boolean popScope = false;
if (ctxExpr != null) {
popScope = true;
tCtx = tCtx.pushContext();
tCtx.pushVariableScope();
iterateOver(ctxExpr, tCtx);
ctxExpr = null;
}
List<ASTNode> predicates = null;
ASTNode pathNode = rpen.getPath();
if (ASTTag.AXIS_STEP.equals(pathNode.getTag())) {
AxisStepNode axisNode = (AxisStepNode) pathNode;
predicates = axisNode.getPredicates();
AxisStepNode.Axis axis = axisNode.getAxis();
if (ctxExpr == null) {
ctxExpr = vre(tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME)
.getLogicalVariable());
}
Function axisFn = translateAxis(axis);
NodeType nt = translateNodeTest(axis, axisNode.getNodeTest());
int ntCode = currCtx.encodeSequenceType(SequenceType.create(nt, Quantifier.QUANT_ONE));
ctxExpr = sfce(axisFn,
treat(ctxExpr, SequenceType.create(AnyNodeType.INSTANCE, Quantifier.QUANT_STAR)),
ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), ntCode));
asc = isForwardAxis(axis);
} else if (ASTTag.POSTFIX_EXPRESSION.equals(pathNode.getTag())) {
PostfixExprNode postfixNode = (PostfixExprNode) pathNode;
List<ASTNode> args = postfixNode.getArgs();
ILogicalExpression expr = vre(translateExpression(postfixNode.getExpr(), tCtx));
List<ILogicalExpression> arguments = new ArrayList<ILogicalExpression>();
if (args != null && !args.isEmpty()) {
for (ASTNode an : args) {
if (an.getTag() == ASTTag.ARGUMENT_LIST) {
ArgumentListNode argNode = (ArgumentListNode) an;
arguments.clear();
for (ASTNode en : argNode.getArg()) {
ILogicalExpression argument = vre(translateExpression(en, tCtx));
arguments.add(argument);
//if this is the first argument, then the first parameter in the value
//is the whole expression,
//otherwise it is the result of the value function
if (an == args.get(0)) {
ctxExpr = sfce(BuiltinOperators.VALUE, expr, argument);
} else {
ctxExpr = sfce(BuiltinOperators.VALUE, ctxExpr, argument);
}
}
if (arguments.size() == 0) {
if (ctxExpr == null) {
ctxExpr = vre(createAssignment(expr, tCtx));
ctxExpr = sfce(BuiltinOperators.KEYS_OR_MEMBERS, expr);
} else {
ctxExpr = vre(createAssignment(ctxExpr, tCtx));
ctxExpr = sfce(BuiltinOperators.KEYS_OR_MEMBERS, ctxExpr);
}
}
} else {
predicates = postfixNode.getArgs();
ctxExpr = expr;
}
}
} else {
ctxExpr = expr;
}
} else {
throw new IllegalStateException("Unknown path node: " + pathNode.getTag());
}
if (predicates != null && !predicates.isEmpty()) {
ctxExpr = vre(createAssignment(ctxExpr, tCtx));
ctxExpr = sfce(asc ? BuiltinOperators.SORT_DISTINCT_NODES_ASC_OR_ATOMICS
: BuiltinOperators.SORT_DISTINCT_NODES_DESC_OR_ATOMICS, ctxExpr);
iterateOver(ctxExpr, tCtx);
int i = 0;
ILogicalExpression selectCondition = null;
for (ASTNode pn : predicates) {
// Handles integer, boolean expression, path expression exists
// TODO Support inner focus between predicates.
LogicalVariable pLVar = translateExpression(pn, tCtx);
ILogicalExpression tTest = instanceOf(vre(pLVar),
SequenceType.create(BuiltinTypeRegistry.XSEXT_NUMERIC, Quantifier.QUANT_ONE));
ILogicalExpression posTest = sfce(BuiltinOperators.VALUE_EQ, vre(pLVar), vre(tCtx.varScope
.lookupVariable(XMLQueryCompilerConstants.POS_VAR_NAME).getLogicalVariable()));
ILogicalExpression boolTestTmp = vre(pLVar);
if (tCtx.op.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
ILogicalExpression expression = ((AssignOperator) tCtx.op).getExpressions().get(0)
.getValue();
if (expression.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL
&& ((AbstractFunctionCallExpression) expression).getFunctionIdentifier()
.equals(BuiltinOperators.CHILD.getFunctionIdentifier())) {
boolTestTmp = sfce(BuiltinFunctions.FN_COUNT_1, boolTestTmp);
}
}
ILogicalExpression boolTest = sfce(BuiltinFunctions.FN_BOOLEAN_1, boolTestTmp);
ILogicalExpression condition = sfce(BuiltinOperators.IF_THEN_ELSE, tTest, posTest, boolTest);
if (i++ == 0) {
selectCondition = condition;
} else {
selectCondition = sfce(BuiltinOperators.AND, selectCondition, condition);
}
}
SelectOperator select = new SelectOperator(mutable(selectCondition), false, null);
select.getInputs().add(mutable(tCtx.op));
tCtx.op = select;
ctxExpr = vre(
tCtx.varScope.lookupVariable(XMLQueryCompilerConstants.DOT_VAR_NAME).getLogicalVariable());
}
if (popScope) {
tCtx.popVariableScope();
List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
List<Mutable<ILogicalExpression>> exprs = new ArrayList<Mutable<ILogicalExpression>>();
LogicalVariable var = newLogicalVariable();
vars.add(var);
exprs.add(mutable(afce(BuiltinOperators.SEQUENCE, false, ctxExpr)));
AggregateOperator aop = new AggregateOperator(vars, exprs);
aop.getInputs().add(mutable(tCtx.op));
tCtx.op = aop;
tCtx = tCtx.popContext();
ctxExpr = vre(var);
ctxExpr = sfce(asc ? BuiltinOperators.SORT_DISTINCT_NODES_ASC_OR_ATOMICS
: BuiltinOperators.SORT_DISTINCT_NODES_DESC_OR_ATOMICS, vre(var));
}
}
}
LogicalVariable lVar = createAssignment(ctxExpr, tCtx);
return lVar;
}
private void iterateOver(ILogicalExpression ctxExpr, TranslationContext tCtx) {
LogicalVariable seqLVar = createAssignment(ctxExpr, tCtx);
LogicalVariable lastLVar = createAssignment(sfce(BuiltinFunctions.FN_COUNT_1, vre(seqLVar)), tCtx);
tCtx.varScope.registerVariable(new XQueryVariable(XMLQueryCompilerConstants.LAST_VAR_NAME,
SequenceType.create(BuiltinTypeRegistry.XS_INTEGER, Quantifier.QUANT_ONE), lastLVar));
LogicalVariable forLVar = newLogicalVariable();
LogicalVariable posLVar = newLogicalVariable();
UnnestOperator unnest = new UnnestOperator(forLVar, mutable(ufce(BuiltinOperators.ITERATE, vre(seqLVar))),
posLVar, BuiltinTypeRegistry.XS_INTEGER, new VXQueryPositionWriter());
SequenceType forVarType = SequenceType.create(AnyItemType.INSTANCE, Quantifier.QUANT_ONE);
XQueryVariable forVar = new XQueryVariable(XMLQueryCompilerConstants.DOT_VAR_NAME, forVarType, forLVar);
tCtx.varScope.registerVariable(forVar);
SequenceType posVarType = SequenceType.create(BuiltinTypeRegistry.XS_INTEGER, Quantifier.QUANT_ONE);
XQueryVariable posVar = new XQueryVariable(XMLQueryCompilerConstants.POS_VAR_NAME, posVarType, posLVar);
tCtx.varScope.registerVariable(posVar);
unnest.getInputs().add(mutable(tCtx.op));
tCtx.op = unnest;
}
private boolean isForwardAxis(AxisStepNode.Axis axis) {
switch (axis) {
case ABBREV:
case CHILD:
case ABBREV_ATTRIBUTE:
case ATTRIBUTE:
case DESCENDANT:
case DESCENDANT_OR_SELF:
case FOLLOWING:
case FOLLOWING_SIBLING:
case SELF:
return true;
case ANCESTOR:
case ANCESTOR_OR_SELF:
case DOT_DOT:
case PARENT:
case PRECEDING:
case PRECEDING_SIBLING:
return false;
default:
throw new IllegalStateException("Unknown axis: " + axis);
}
}
private NodeType translateNodeTest(AxisStepNode.Axis axis, ASTNode nodeTest) throws SystemException {
NodeType nt = AnyNodeType.INSTANCE;
if (nodeTest != null) {
switch (nodeTest.getTag()) {
case NAME_TEST: {
NameTestNode ntn = (NameTestNode) nodeTest;
String uri = null;
if (ntn.getPrefix() != null) {
if (!"".equals(ntn.getPrefix())) {
uri = currCtx.lookupNamespaceUri(ntn.getPrefix());
if (uri == null) {
throw new SystemException(ErrorCode.XPST0081, ntn.getSourceLocation());
}
} else {
uri = "";
}
}
String localName = ntn.getLocalName();
NameTest nameTest = new NameTest(uri == null ? null : createUTF8String(uri),
localName == null ? null : createUTF8String(ntn.getLocalName()));
if (axis == AxisStepNode.Axis.ATTRIBUTE || axis == AxisStepNode.Axis.ABBREV_ATTRIBUTE) {
nt = new AttributeType(nameTest, BuiltinTypeRegistry.XS_ANY_ATOMIC);
} else {
nt = new ElementType(nameTest, AnyType.INSTANCE, true);
}
break;
}
case ANY_NODE_TEST:
case DOCUMENT_TEST:
case TEXT_TEST:
case COMMENT_TEST:
case PI_TEST:
case ATTRIBUTE_TEST:
case SCHEMA_ATTRIBUTE_TEST:
case ELEMENT_TEST:
case SCHEMA_ELEMENT_TEST:
nt = (NodeType) createItemType(nodeTest);
break;
default:
throw new IllegalStateException("Unknown node: " + nodeTest.getTag());
}
}
return nt;
}
private Function translateAxis(AxisStepNode.Axis axis) {
switch (axis) {
case ABBREV:
case CHILD:
return BuiltinOperators.CHILD;
case ABBREV_ATTRIBUTE:
case ATTRIBUTE:
return BuiltinOperators.ATTRIBUTE;
case ANCESTOR:
return BuiltinOperators.ANCESTOR;
case ANCESTOR_OR_SELF:
return BuiltinOperators.ANCESTOR_OR_SELF;
case DESCENDANT:
return BuiltinOperators.DESCENDANT;
case DESCENDANT_OR_SELF:
return BuiltinOperators.DESCENDANT_OR_SELF;
case DOT_DOT:
case PARENT:
return BuiltinOperators.PARENT;
case FOLLOWING:
return BuiltinOperators.FOLLOWING;
case FOLLOWING_SIBLING:
return BuiltinOperators.FOLLOWING_SIBLING;
case PRECEDING:
return BuiltinOperators.PRECEDING;
case PRECEDING_SIBLING:
return BuiltinOperators.PRECEDING_SIBLING;
case SELF:
return BuiltinOperators.SELF;
default:
throw new IllegalStateException("Unknown axis: " + axis);
}
}
private static String unquote(String image) throws SystemException {
StringBuilder buffer = new StringBuilder();
char quoteChar = image.charAt(0);
image = image.substring(1, image.length() - 1);
Matcher m = UNQUOTER.matcher(image);
int i = 0;
while (m.find()) {
int start = m.start();
int end = m.end();
if (i < start) {
buffer.append(image, i, start);
}
if (m.start(1) >= 0) {
buffer.append('<');
} else if (m.start(2) >= 0) {
buffer.append('>');
} else if (m.start(3) >= 0) {
buffer.append('\'');
} else if (m.start(4) >= 0) {
buffer.append('&');
} else if (m.start(5) >= 0) {
buffer.append('"');
} else if (m.start(6) >= 0) {
buffer.append(quoteChar == '"' ? '"' : "\"\"");
} else if (m.start(7) >= 0) {
buffer.append(quoteChar == '\'' ? '\'' : "''");
} else if (m.start(8) >= 0) {
try {
buffer.appendCodePoint(Integer.parseInt(image.substring(start + 2, end - 1)));
} catch (NumberFormatException e) {
throw new SystemException(ErrorCode.XQST0090);
}
} else if (m.start(9) >= 0) {
try {
buffer.appendCodePoint(Integer.parseInt(image.substring(start + 3, end - 1), 16));
} catch (NumberFormatException e) {
throw new SystemException(ErrorCode.XQST0090);
}
}
i = m.end();
}
if (i < image.length()) {
buffer.append(image, i, image.length());
}
return buffer.toString();
}
private QName createQName(QNameNode qnNode) throws SystemException {
return createQName(qnNode, "");
}
private QName createQName(QNameNode qnNode, String defaultUri) throws SystemException {
String prefix = qnNode.getPrefix();
String local = qnNode.getLocalName();
String uri;
if (!"".equals(prefix)) {
uri = currCtx.lookupNamespaceUri(prefix);
if (uri == null) {
throw new SystemException(ErrorCode.XPST0081, qnNode.getSourceLocation());
}
} else {
uri = defaultUri;
}
return new QName(uri, local, prefix);
}
private static ILogicalExpression afce(Function fn, boolean isTwoStep, ILogicalExpression... argExprs) {
List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>();
for (ILogicalExpression e : argExprs) {
args.add(mutable(e));
}
return new AggregateFunctionCallExpression(fn, isTwoStep, args);
}
private static ILogicalExpression ufce(Function fn, ILogicalExpression... argExprs) {
List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>();
for (ILogicalExpression e : argExprs) {
args.add(mutable(e));
}
return new UnnestingFunctionCallExpression(fn, args);
}
private static ILogicalExpression sfce(Function fn, ILogicalExpression... argExprs) {
List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>();
for (ILogicalExpression e : argExprs) {
args.add(mutable(e));
}
return new ScalarFunctionCallExpression(fn, args);
}
private Function getOperator(InfixOperator operator) {
switch (operator) {
case AND:
return BuiltinOperators.AND;
case DIV:
return BuiltinOperators.DIVIDE;
case EXCEPT:
return BuiltinOperators.EXCEPT;
case FOLLOWS:
return BuiltinOperators.NODE_AFTER;
case GENERAL_EQ:
return BuiltinOperators.GENERAL_EQ;
case GENERAL_GE:
return BuiltinOperators.GENERAL_GE;
case GENERAL_GT:
return BuiltinOperators.GENERAL_GT;
case GENERAL_LE:
return BuiltinOperators.GENERAL_LE;
case GENERAL_LT:
return BuiltinOperators.GENERAL_LT;
case GENERAL_NE:
return BuiltinOperators.GENERAL_NE;
case IDIV:
return BuiltinOperators.IDIV;
case INTERSECT:
return BuiltinOperators.INTERSECT;
case IS:
return BuiltinOperators.IS_SAME_NODE;
case MINUS:
return BuiltinOperators.SUBTRACT;
case MOD:
return BuiltinOperators.MOD;
case MULTIPLY:
return BuiltinOperators.MULTIPLY;
case OR:
return BuiltinOperators.OR;
case PLUS:
return BuiltinOperators.ADD;
case PRECEDES:
return BuiltinOperators.NODE_BEFORE;
case RANGE:
return BuiltinOperators.TO;
case UNION:
return BuiltinOperators.UNION;
case VALUE_EQ:
return BuiltinOperators.VALUE_EQ;
case VALUE_GE:
return BuiltinOperators.VALUE_GE;
case VALUE_GT:
return BuiltinOperators.VALUE_GT;
case VALUE_LE:
return BuiltinOperators.VALUE_LE;
case VALUE_LT:
return BuiltinOperators.VALUE_LT;
case VALUE_NE:
return BuiltinOperators.VALUE_NE;
}
throw new IllegalStateException("Unknown operator: " + operator);
}
private ILogicalExpression ce(SequenceType type, Object value) throws SystemException {
try {
ItemType it = type.getItemType();
if (it.isAtomicType()) {
AtomicType at = (AtomicType) it;
byte[] bytes = null;
switch (at.getTypeId()) {
case BuiltinTypeConstants.XS_BOOLEAN_TYPE_ID: {
baaos.reset();
dOut.write((byte) ValueTag.XS_BOOLEAN_TAG);
dOut.writeByte(((Boolean) value).booleanValue() ? 1 : 0);
break;
}
case BuiltinTypeConstants.XS_INT_TYPE_ID: {
baaos.reset();
dOut.write((byte) ValueTag.XS_INT_TAG);
dOut.writeInt(((Number) value).intValue());
break;
}
case BuiltinTypeConstants.XS_INTEGER_TYPE_ID: {
baaos.reset();
dOut.write((byte) ValueTag.XS_INTEGER_TAG);
dOut.writeLong(((Number) value).longValue());
break;
}
case BuiltinTypeConstants.XS_DOUBLE_TYPE_ID: {
baaos.reset();
dOut.write((byte) ValueTag.XS_DOUBLE_TAG);
dOut.writeDouble(((Number) value).doubleValue());
break;
}
case BuiltinTypeConstants.XS_STRING_TYPE_ID: {
baaos.reset();
dOut.write((byte) ValueTag.XS_STRING_TAG);
stringVB.write((CharSequence) value, dOut);
break;
}
case BuiltinTypeConstants.XS_DECIMAL_TYPE_ID: {
baaos.reset();
// TODO Remove the creation of the separate byte array.
DoublePointable doublep = (DoublePointable) DoublePointable.FACTORY.createPointable();
doublep.set(new byte[DoublePointable.TYPE_TRAITS.getFixedLength()], 0,
DoublePointable.TYPE_TRAITS.getFixedLength());
doublep.setDouble(((Number) value).doubleValue());
CastToDecimalOperation castToDecimal = new CastToDecimalOperation();
castToDecimal.convertDouble(doublep, dOut);
break;
}
case BuiltinTypeConstants.XS_QNAME_TYPE_ID: {
QName qname = (QName) value;
baaos.reset();
dOut.write((byte) ValueTag.XS_QNAME_TAG);
stringVB.write(qname.getNamespaceURI(), dOut);
stringVB.write(qname.getPrefix(), dOut);
stringVB.write(qname.getLocalPart(), dOut);
break;
}
case BuiltinTypeConstants.XS_UNTYPED_ATOMIC_TYPE_ID: {
baaos.reset();
dOut.write((byte) ValueTag.XS_UNTYPED_ATOMIC_TAG);
stringVB.write((CharSequence) value, dOut);
break;
}
case BuiltinTypeConstants.JS_NULL_TYPE_ID: {
baaos.reset();
dOut.write((byte) ValueTag.JS_NULL_TAG);
break;
}
default:
throw new SystemException(ErrorCode.SYSE0001);
}
bytes = Arrays.copyOf(baaos.getByteArray(), baaos.size());
return new ConstantExpression(new VXQueryConstantValue(type, bytes));
}
throw new UnsupportedOperationException();
} catch (IOException e) {
throw new SystemException(ErrorCode.SYSE0001, e);
}
}
private static ILogicalExpression vre(LogicalVariable var) {
if (var == null) {
throw new NullPointerException();
}
return new VariableReferenceExpression(var);
}
private LogicalVariable createConcatenation(List<LogicalVariable> vars, TranslationContext tCtx) {
if (vars.size() == 1) {
return vars.get(0);
}
return createFunctionCall(BuiltinOperators.CONCATENATE, vars, tCtx);
}
private LogicalVariable createFunctionCall(Function fn, List<LogicalVariable> vars, TranslationContext tCtx) {
return createAssignment(createFunctionCall(fn, vars), tCtx);
}
private LogicalVariable createAssignment(ILogicalExpression expr, TranslationContext tCtx) {
if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
return ((VariableReferenceExpression) expr).getVariableReference();
}
LogicalVariable result = newLogicalVariable();
AssignOperator aOp = new AssignOperator(result, mutable(expr));
aOp.getInputs().add(mutable(tCtx.op));
tCtx.op = aOp;
return result;
}
private static ILogicalExpression createFunctionCall(Function fn, List<LogicalVariable> vars) {
List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>();
for (LogicalVariable var : vars) {
args.add(mutable(new VariableReferenceExpression(var)));
}
return new ScalarFunctionCallExpression(fn, args);
}
private ILogicalExpression normalize(ILogicalExpression expr, SequenceType type) throws SystemException {
if (type.getItemType().isAtomicType()) {
ILogicalExpression atomizedExpr = new ScalarFunctionCallExpression(BuiltinFunctions.FN_DATA_1,
Collections.singletonList(mutable(expr)));
AtomicType aType = (AtomicType) type.getItemType();
if (TypeUtils.isSubtypeTypeOf(aType, BuiltinTypeRegistry.XS_BOOLEAN)) {
return new ScalarFunctionCallExpression(BuiltinFunctions.FN_BOOLEAN_1,
Collections.singletonList(mutable(atomizedExpr)));
}
return promote(atomizedExpr, type);
} else {
return treat(expr, type);
}
}
private ILogicalExpression data(ILogicalExpression expr) throws SystemException {
return new ScalarFunctionCallExpression(BuiltinFunctions.FN_DATA_1, Collections.singletonList(mutable(expr)));
}
private ILogicalExpression zeroOrOne(ILogicalExpression expr) throws SystemException {
return new ScalarFunctionCallExpression(BuiltinFunctions.FN_ZERO_OR_ONE_1,
Collections.singletonList(mutable(expr)));
}
private ILogicalExpression string(ILogicalExpression expr) throws SystemException {
return new ScalarFunctionCallExpression(BuiltinFunctions.FN_STRING_1, Collections.singletonList(mutable(expr)));
}
private ILogicalExpression promote(ILogicalExpression expr, SequenceType type) throws SystemException {
int typeCode = currCtx.lookupSequenceType(type);
return sfce(BuiltinOperators.PROMOTE, expr,
ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
}
private ILogicalExpression treat(ILogicalExpression expr, SequenceType type) throws SystemException {
int typeCode = currCtx.lookupSequenceType(type);
return sfce(BuiltinOperators.TREAT, expr,
ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
}
private ILogicalExpression cast(ILogicalExpression expr, SequenceType type) throws SystemException {
int typeCode = currCtx.lookupSequenceType(type);
return sfce(BuiltinOperators.CAST, data(expr),
ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
}
private ILogicalExpression castable(ILogicalExpression expr, SequenceType type) throws SystemException {
int typeCode = currCtx.lookupSequenceType(type);
return sfce(BuiltinOperators.CASTABLE, expr,
ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
}
private ILogicalExpression instanceOf(ILogicalExpression expr, SequenceType type) throws SystemException {
int typeCode = currCtx.lookupSequenceType(type);
return sfce(BuiltinOperators.INSTANCE_OF, expr,
ce(SequenceType.create(BuiltinTypeRegistry.XS_INT, Quantifier.QUANT_ONE), typeCode));
}
private List<LogicalVariable> translateExpressionList(List<ASTNode> expressions, TranslationContext tCtx)
throws SystemException {
List<LogicalVariable> result = new ArrayList<>();
for (ASTNode e : expressions) {
result.add(translateExpression(e, tCtx));
}
return result;
}
private static Mutable<ILogicalExpression> mutable(ILogicalExpression expr) {
return new MutableObject<>(expr);
}
private static Mutable<ILogicalOperator> mutable(ILogicalOperator op) {
return new MutableObject<>(op);
}
private LogicalVariable newLogicalVariable() {
return new LogicalVariable(varCounter++);
}
private class RootVariableScope implements IVariableScope {
@Override
public IVariableScope getParentScope() {
return null;
}
@Override
public XQueryVariable lookupVariable(QName name) {
return moduleCtx.lookupVariable(name);
}
@Override
public void registerVariable(XQueryVariable var) {
moduleCtx.registerVariable(var);
}
@Override
public Iterator<XQueryVariable> listVariables() {
return moduleCtx.listVariables();
}
}
private class TranslationContext {
private final TranslationContext parent;
private ILogicalOperator op;
private IVariableScope varScope;
public TranslationContext(TranslationContext parent, ILogicalOperator op) {
this.parent = parent;
this.op = op;
varScope = parent == null ? rootVarScope : parent.varScope;
}
TranslationContext pushContext() {
SubplanOperator sOp = new SubplanOperator();
sOp.getInputs().add(mutable(op));
op = sOp;
NestedTupleSourceOperator ntsOp = new NestedTupleSourceOperator(mutable(sOp));
TranslationContext childCtx = new TranslationContext(this, ntsOp);
return childCtx;
}
TranslationContext popContext() {
SubplanOperator sOp = (SubplanOperator) parent.op;
sOp.setRootOp(mutable(op));
return parent;
}
void pushVariableScope() {
varScope = new ExpressionVariableScope(varScope);
}
void popVariableScope() {
varScope = varScope.getParentScope();
}
}
private interface IVariableScope {
public IVariableScope getParentScope();
public XQueryVariable lookupVariable(QName name);
public void registerVariable(XQueryVariable var);
public Iterator<XQueryVariable> listVariables();
}
private static class ExpressionVariableScope implements IVariableScope {
private final IVariableScope parent;
private final Map<QName, XQueryVariable> varMap;
public ExpressionVariableScope(IVariableScope parent) {
this.parent = parent;
varMap = new HashMap<QName, XQueryVariable>();
}
@Override
public IVariableScope getParentScope() {
return parent;
}
@Override
public XQueryVariable lookupVariable(QName name) {
if (varMap.containsKey(name)) {
return varMap.get(name);
}
return parent.lookupVariable(name);
}
@Override
public void registerVariable(XQueryVariable var) {
varMap.put(var.getName(), var);
}
public Iterator<XQueryVariable> listVariables() {
return varMap.values().iterator();
}
}
}