| /* |
| * 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(); |
| } |
| |
| } |
| } |