0001: /*
0002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
0003: *
0004: * Licensed under the Aduna BSD-style license.
0005: */
0006: package org.openrdf.query.algebra.evaluation.impl;
0007:
0008: import java.math.BigDecimal;
0009: import java.math.BigInteger;
0010: import java.math.RoundingMode;
0011: import java.util.HashSet;
0012: import java.util.List;
0013: import java.util.Set;
0014: import java.util.regex.Pattern;
0015:
0016: import info.aduna.iteration.CloseableIteration;
0017: import info.aduna.iteration.ConvertingIteration;
0018: import info.aduna.iteration.DelayedIteration;
0019: import info.aduna.iteration.DistinctIteration;
0020: import info.aduna.iteration.EmptyIteration;
0021: import info.aduna.iteration.FilterIteration;
0022: import info.aduna.iteration.IntersectIteration;
0023: import info.aduna.iteration.Iteration;
0024: import info.aduna.iteration.LimitIteration;
0025: import info.aduna.iteration.MinusIteration;
0026: import info.aduna.iteration.OffsetIteration;
0027: import info.aduna.iteration.SingletonIteration;
0028: import info.aduna.iteration.UnionIteration;
0029:
0030: import org.openrdf.model.BNode;
0031: import org.openrdf.model.Literal;
0032: import org.openrdf.model.Resource;
0033: import org.openrdf.model.Statement;
0034: import org.openrdf.model.URI;
0035: import org.openrdf.model.Value;
0036: import org.openrdf.model.datatypes.XMLDatatypeUtil;
0037: import org.openrdf.model.impl.BooleanLiteralImpl;
0038: import org.openrdf.model.impl.DecimalLiteralImpl;
0039: import org.openrdf.model.impl.IntegerLiteralImpl;
0040: import org.openrdf.model.impl.NumericLiteralImpl;
0041: import org.openrdf.model.vocabulary.XMLSchema;
0042: import org.openrdf.query.BindingSet;
0043: import org.openrdf.query.Dataset;
0044: import org.openrdf.query.QueryEvaluationException;
0045: import org.openrdf.query.algebra.And;
0046: import org.openrdf.query.algebra.BNodeGenerator;
0047: import org.openrdf.query.algebra.BinaryTupleOperator;
0048: import org.openrdf.query.algebra.Bound;
0049: import org.openrdf.query.algebra.Compare;
0050: import org.openrdf.query.algebra.CompareAll;
0051: import org.openrdf.query.algebra.CompareAny;
0052: import org.openrdf.query.algebra.Datatype;
0053: import org.openrdf.query.algebra.Difference;
0054: import org.openrdf.query.algebra.Distinct;
0055: import org.openrdf.query.algebra.EmptySet;
0056: import org.openrdf.query.algebra.Exists;
0057: import org.openrdf.query.algebra.Extension;
0058: import org.openrdf.query.algebra.Filter;
0059: import org.openrdf.query.algebra.FunctionCall;
0060: import org.openrdf.query.algebra.Group;
0061: import org.openrdf.query.algebra.In;
0062: import org.openrdf.query.algebra.Intersection;
0063: import org.openrdf.query.algebra.IsBNode;
0064: import org.openrdf.query.algebra.IsLiteral;
0065: import org.openrdf.query.algebra.IsResource;
0066: import org.openrdf.query.algebra.IsURI;
0067: import org.openrdf.query.algebra.Join;
0068: import org.openrdf.query.algebra.Label;
0069: import org.openrdf.query.algebra.Lang;
0070: import org.openrdf.query.algebra.LangMatches;
0071: import org.openrdf.query.algebra.LeftJoin;
0072: import org.openrdf.query.algebra.Like;
0073: import org.openrdf.query.algebra.LocalName;
0074: import org.openrdf.query.algebra.MathExpr;
0075: import org.openrdf.query.algebra.MultiProjection;
0076: import org.openrdf.query.algebra.Namespace;
0077: import org.openrdf.query.algebra.Not;
0078: import org.openrdf.query.algebra.Or;
0079: import org.openrdf.query.algebra.Order;
0080: import org.openrdf.query.algebra.Projection;
0081: import org.openrdf.query.algebra.QueryRoot;
0082: import org.openrdf.query.algebra.Regex;
0083: import org.openrdf.query.algebra.SameTerm;
0084: import org.openrdf.query.algebra.SingletonSet;
0085: import org.openrdf.query.algebra.Slice;
0086: import org.openrdf.query.algebra.StatementPattern;
0087: import org.openrdf.query.algebra.Str;
0088: import org.openrdf.query.algebra.TupleExpr;
0089: import org.openrdf.query.algebra.UnaryTupleOperator;
0090: import org.openrdf.query.algebra.Union;
0091: import org.openrdf.query.algebra.ValueConstant;
0092: import org.openrdf.query.algebra.ValueExpr;
0093: import org.openrdf.query.algebra.Var;
0094: import org.openrdf.query.algebra.MathExpr.MathOp;
0095: import org.openrdf.query.algebra.StatementPattern.Scope;
0096: import org.openrdf.query.algebra.evaluation.EvaluationStrategy;
0097: import org.openrdf.query.algebra.evaluation.QueryBindingSet;
0098: import org.openrdf.query.algebra.evaluation.TripleSource;
0099: import org.openrdf.query.algebra.evaluation.ValueExprEvaluationException;
0100: import org.openrdf.query.algebra.evaluation.function.Function;
0101: import org.openrdf.query.algebra.evaluation.function.FunctionRegistry;
0102: import org.openrdf.query.algebra.evaluation.iterator.CompatibleBindingSetFilter;
0103: import org.openrdf.query.algebra.evaluation.iterator.ExtensionIterator;
0104: import org.openrdf.query.algebra.evaluation.iterator.FilterIterator;
0105: import org.openrdf.query.algebra.evaluation.iterator.GroupIterator;
0106: import org.openrdf.query.algebra.evaluation.iterator.JoinIterator;
0107: import org.openrdf.query.algebra.evaluation.iterator.LeftJoinIterator;
0108: import org.openrdf.query.algebra.evaluation.iterator.MultiProjectionIterator;
0109: import org.openrdf.query.algebra.evaluation.iterator.OrderIterator;
0110: import org.openrdf.query.algebra.evaluation.iterator.ProjectionIterator;
0111: import org.openrdf.query.algebra.evaluation.util.OrderComparator;
0112: import org.openrdf.query.algebra.evaluation.util.QueryEvaluationUtil;
0113: import org.openrdf.query.algebra.evaluation.util.ValueComparator;
0114:
0115: /**
0116: * Evaluates the TupleExpr and ValueExpr using Iterators and common tripleSource
0117: * API.
0118: *
0119: * @author James Leigh
0120: * @author Arjohn Kampman
0121: * @author David Huynh
0122: */
0123: public class EvaluationStrategyImpl implements EvaluationStrategy {
0124:
0125: /*-----------*
0126: * Constants *
0127: *-----------*/
0128:
0129: private final TripleSource tripleSource;
0130:
0131: private final Dataset dataset;
0132:
0133: /*--------------*
0134: * Constructors *
0135: *--------------*/
0136:
0137: public EvaluationStrategyImpl(TripleSource tripleSource) {
0138: this (tripleSource, null);
0139: }
0140:
0141: public EvaluationStrategyImpl(TripleSource tripleSource,
0142: Dataset dataset) {
0143: this .tripleSource = tripleSource;
0144: this .dataset = dataset;
0145: }
0146:
0147: /*---------*
0148: * Methods *
0149: *---------*/
0150:
0151: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0152: TupleExpr expr, BindingSet bindings)
0153: throws QueryEvaluationException {
0154: if (expr instanceof StatementPattern) {
0155: return evaluate((StatementPattern) expr, bindings);
0156: } else if (expr instanceof UnaryTupleOperator) {
0157: return evaluate((UnaryTupleOperator) expr, bindings);
0158: } else if (expr instanceof BinaryTupleOperator) {
0159: return evaluate((BinaryTupleOperator) expr, bindings);
0160: } else if (expr instanceof SingletonSet) {
0161: return evaluate((SingletonSet) expr, bindings);
0162: } else if (expr instanceof EmptySet) {
0163: return evaluate((EmptySet) expr, bindings);
0164: } else if (expr == null) {
0165: throw new IllegalArgumentException("expr must not be null");
0166: } else {
0167: throw new QueryEvaluationException(
0168: "Unsupported tuple expr type: " + expr.getClass());
0169: }
0170: }
0171:
0172: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0173: StatementPattern sp, final BindingSet bindings)
0174: throws QueryEvaluationException {
0175: final Var subjVar = sp.getSubjectVar();
0176: final Var predVar = sp.getPredicateVar();
0177: final Var objVar = sp.getObjectVar();
0178: final Var conVar = sp.getContextVar();
0179:
0180: Value subjValue = getVarValue(subjVar, bindings);
0181: Value predValue = getVarValue(predVar, bindings);
0182: Value objValue = getVarValue(objVar, bindings);
0183: Value contextValue = getVarValue(conVar, bindings);
0184:
0185: CloseableIteration<? extends Statement, QueryEvaluationException> stIter = null;
0186:
0187: try {
0188: Resource[] contexts;
0189:
0190: if (dataset != null) {
0191: Set<URI> graphs;
0192: if (sp.getScope() == Scope.DEFAULT_CONTEXTS) {
0193: graphs = dataset.getDefaultGraphs();
0194: } else {
0195: graphs = dataset.getNamedGraphs();
0196: }
0197:
0198: if (graphs.isEmpty()) {
0199: // Search zero contexts
0200: return new EmptyIteration<BindingSet, QueryEvaluationException>();
0201: } else if (contextValue != null) {
0202: if (graphs.contains(contextValue)) {
0203: contexts = new Resource[] { (Resource) contextValue };
0204: } else {
0205: // Statement pattern specifies a context that is not part of
0206: // the dataset
0207: return new EmptyIteration<BindingSet, QueryEvaluationException>();
0208: }
0209: } else {
0210: contexts = graphs.toArray(new Resource[graphs
0211: .size()]);
0212: }
0213: } else if (contextValue != null) {
0214: contexts = new Resource[] { (Resource) contextValue };
0215: } else {
0216: contexts = new Resource[0];
0217: }
0218:
0219: stIter = tripleSource.getStatements((Resource) subjValue,
0220: (URI) predValue, objValue, contexts);
0221:
0222: if (contexts.length == 0
0223: && sp.getScope() == Scope.NAMED_CONTEXTS) {
0224: // Named contexts are matched by retrieving all statements from
0225: // the store and filtering out the statements that do not have a
0226: // context.
0227: stIter = new FilterIteration<Statement, QueryEvaluationException>(
0228: stIter) {
0229:
0230: @Override
0231: protected boolean accept(Statement st) {
0232: return st.getContext() != null;
0233: }
0234:
0235: }; // end anonymous class
0236: }
0237: } catch (ClassCastException e) {
0238: // Invalid value type for subject, predicate and/or context
0239: return new EmptyIteration<BindingSet, QueryEvaluationException>();
0240: }
0241:
0242: // The same variable might have been used multiple times in this
0243: // StatementPattern, verify value equality in those cases.
0244: stIter = new FilterIteration<Statement, QueryEvaluationException>(
0245: stIter) {
0246:
0247: @Override
0248: protected boolean accept(Statement st) {
0249: Resource subj = st.getSubject();
0250: URI pred = st.getPredicate();
0251: Value obj = st.getObject();
0252: Resource context = st.getContext();
0253:
0254: if (subjVar != null) {
0255: if (subjVar.equals(predVar) && !subj.equals(pred)) {
0256: return false;
0257: }
0258: if (subjVar.equals(objVar) && !subj.equals(obj)) {
0259: return false;
0260: }
0261: if (subjVar.equals(conVar) && !subj.equals(context)) {
0262: return false;
0263: }
0264: }
0265:
0266: if (predVar != null) {
0267: if (predVar.equals(objVar) && !pred.equals(obj)) {
0268: return false;
0269: }
0270: if (predVar.equals(conVar) && !pred.equals(context)) {
0271: return false;
0272: }
0273: }
0274:
0275: if (objVar != null) {
0276: if (objVar.equals(conVar) && !obj.equals(context)) {
0277: return false;
0278: }
0279: }
0280:
0281: return true;
0282: }
0283: };
0284:
0285: // Return an iterator that converts the statements to var bindings
0286: return new ConvertingIteration<Statement, BindingSet, QueryEvaluationException>(
0287: stIter) {
0288:
0289: @Override
0290: protected BindingSet convert(Statement st) {
0291: QueryBindingSet result = new QueryBindingSet(bindings);
0292:
0293: if (subjVar != null
0294: && !result.hasBinding(subjVar.getName())) {
0295: result.addBinding(subjVar.getName(), st
0296: .getSubject());
0297: }
0298: if (predVar != null
0299: && !result.hasBinding(predVar.getName())) {
0300: result.addBinding(predVar.getName(), st
0301: .getPredicate());
0302: }
0303: if (objVar != null
0304: && !result.hasBinding(objVar.getName())) {
0305: result.addBinding(objVar.getName(), st.getObject());
0306: }
0307: if (conVar != null
0308: && !result.hasBinding(conVar.getName())
0309: && st.getContext() != null) {
0310: result
0311: .addBinding(conVar.getName(), st
0312: .getContext());
0313: }
0314:
0315: return result;
0316: }
0317: };
0318: }
0319:
0320: private Value getVarValue(Var var, BindingSet bindings) {
0321: if (var == null) {
0322: return null;
0323: } else if (var.hasValue()) {
0324: return var.getValue();
0325: } else {
0326: return bindings.getValue(var.getName());
0327: }
0328: }
0329:
0330: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0331: UnaryTupleOperator expr, BindingSet bindings)
0332: throws QueryEvaluationException {
0333: if (expr instanceof Projection) {
0334: return evaluate((Projection) expr, bindings);
0335: } else if (expr instanceof MultiProjection) {
0336: return evaluate((MultiProjection) expr, bindings);
0337: } else if (expr instanceof Filter) {
0338: return evaluate((Filter) expr, bindings);
0339: } else if (expr instanceof Slice) {
0340: return evaluate((Slice) expr, bindings);
0341: } else if (expr instanceof Extension) {
0342: return evaluate((Extension) expr, bindings);
0343: } else if (expr instanceof Distinct) {
0344: return evaluate((Distinct) expr, bindings);
0345: } else if (expr instanceof Group) {
0346: return evaluate((Group) expr, bindings);
0347: } else if (expr instanceof Order) {
0348: return evaluate((Order) expr, bindings);
0349: } else if (expr instanceof QueryRoot) {
0350: return evaluate(((QueryRoot) expr).getArg(), bindings);
0351: } else if (expr == null) {
0352: throw new IllegalArgumentException("expr must not be null");
0353: } else {
0354: throw new QueryEvaluationException(
0355: "Unknown unary tuple operator type: "
0356: + expr.getClass());
0357: }
0358: }
0359:
0360: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0361: Projection projection, BindingSet bindings)
0362: throws QueryEvaluationException {
0363: CloseableIteration<BindingSet, QueryEvaluationException> result;
0364: result = this .evaluate(projection.getArg(), bindings);
0365: result = new ProjectionIterator(projection, result, bindings);
0366: return result;
0367: }
0368:
0369: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0370: MultiProjection multiProjection, BindingSet bindings)
0371: throws QueryEvaluationException {
0372: CloseableIteration<BindingSet, QueryEvaluationException> result;
0373: result = this .evaluate(multiProjection.getArg(), bindings);
0374: result = new MultiProjectionIterator(multiProjection, result,
0375: bindings);
0376: return result;
0377: }
0378:
0379: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0380: Filter filter, BindingSet bindings)
0381: throws QueryEvaluationException {
0382: CloseableIteration<BindingSet, QueryEvaluationException> result;
0383: result = this .evaluate(filter.getArg(), bindings);
0384: result = new FilterIterator(filter, result, this );
0385: return result;
0386: }
0387:
0388: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0389: Slice slice, BindingSet bindings)
0390: throws QueryEvaluationException {
0391: CloseableIteration<BindingSet, QueryEvaluationException> result = evaluate(
0392: slice.getArg(), bindings);
0393:
0394: if (slice.hasOffset()) {
0395: result = new OffsetIteration<BindingSet, QueryEvaluationException>(
0396: result, slice.getOffset());
0397: }
0398:
0399: if (slice.hasLimit()) {
0400: result = new LimitIteration<BindingSet, QueryEvaluationException>(
0401: result, slice.getLimit());
0402: }
0403:
0404: return result;
0405: }
0406:
0407: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0408: Extension extension, BindingSet bindings)
0409: throws QueryEvaluationException {
0410: CloseableIteration<BindingSet, QueryEvaluationException> result;
0411: result = this .evaluate(extension.getArg(), bindings);
0412: result = new ExtensionIterator(extension, result, this );
0413: return result;
0414: }
0415:
0416: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0417: Distinct distinct, BindingSet bindings)
0418: throws QueryEvaluationException {
0419: return new DistinctIteration<BindingSet, QueryEvaluationException>(
0420: evaluate(distinct.getArg(), bindings));
0421: }
0422:
0423: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0424: Group node, BindingSet bindings)
0425: throws QueryEvaluationException {
0426: return new GroupIterator(this , node, bindings);
0427: }
0428:
0429: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0430: Order node, BindingSet bindings)
0431: throws QueryEvaluationException {
0432: ValueComparator vcmp = new ValueComparator();
0433: OrderComparator cmp = new OrderComparator(this , node, vcmp);
0434: return new OrderIterator(evaluate(node.getArg(), bindings), cmp);
0435: }
0436:
0437: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0438: BinaryTupleOperator expr, BindingSet bindings)
0439: throws QueryEvaluationException {
0440: if (expr instanceof Join) {
0441: return evaluate((Join) expr, bindings);
0442: } else if (expr instanceof LeftJoin) {
0443: return evaluate((LeftJoin) expr, bindings);
0444: } else if (expr instanceof Union) {
0445: return evaluate((Union) expr, bindings);
0446: } else if (expr instanceof Intersection) {
0447: return evaluate((Intersection) expr, bindings);
0448: } else if (expr instanceof Difference) {
0449: return evaluate((Difference) expr, bindings);
0450: } else if (expr == null) {
0451: throw new IllegalArgumentException("expr must not be null");
0452: } else {
0453: throw new QueryEvaluationException(
0454: "Unsupported binary tuple operator type: "
0455: + expr.getClass());
0456: }
0457: }
0458:
0459: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0460: Join join, BindingSet bindings)
0461: throws QueryEvaluationException {
0462: return new JoinIterator(this , join, bindings);
0463: }
0464:
0465: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0466: LeftJoin leftJoin, BindingSet bindings)
0467: throws QueryEvaluationException {
0468: // Check whether optional join is "well designed" as defined in section
0469: // 4.2 of "Semantics and Complexity of SPARQL", 2006, Jorge Pérez et al.
0470: Set<String> boundVars = bindings.getBindingNames();
0471: Set<String> leftVars = leftJoin.getLeftArg().getBindingNames();
0472: Set<String> optionalVars = leftJoin.getRightArg()
0473: .getBindingNames();
0474:
0475: Set<String> problemVars = new HashSet<String>(boundVars);
0476: problemVars.retainAll(optionalVars);
0477: problemVars.removeAll(leftVars);
0478:
0479: if (problemVars.isEmpty()) {
0480: // left join is "well designed"
0481: return new LeftJoinIterator(this , leftJoin, bindings);
0482: } else {
0483: QueryBindingSet filteredBindings = new QueryBindingSet(
0484: bindings);
0485: filteredBindings.removeAll(problemVars);
0486: CloseableIteration<BindingSet, QueryEvaluationException> iter;
0487:
0488: iter = new LeftJoinIterator(this , leftJoin,
0489: filteredBindings);
0490: iter = new CompatibleBindingSetFilter(iter, bindings);
0491:
0492: return iter;
0493: }
0494: }
0495:
0496: @SuppressWarnings("unchecked")
0497: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0498: final Union union, final BindingSet bindings)
0499: throws QueryEvaluationException {
0500: Iteration<BindingSet, QueryEvaluationException> leftArg, rightArg;
0501:
0502: leftArg = new DelayedIteration<BindingSet, QueryEvaluationException>() {
0503:
0504: @Override
0505: protected Iteration<BindingSet, QueryEvaluationException> createIteration()
0506: throws QueryEvaluationException {
0507: return evaluate(union.getLeftArg(), bindings);
0508: }
0509: };
0510:
0511: rightArg = new DelayedIteration<BindingSet, QueryEvaluationException>() {
0512:
0513: @Override
0514: protected Iteration<BindingSet, QueryEvaluationException> createIteration()
0515: throws QueryEvaluationException {
0516: return evaluate(union.getRightArg(), bindings);
0517: }
0518: };
0519:
0520: return new UnionIteration<BindingSet, QueryEvaluationException>(
0521: leftArg, rightArg);
0522: }
0523:
0524: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0525: final Intersection intersection, final BindingSet bindings)
0526: throws QueryEvaluationException {
0527: Iteration<BindingSet, QueryEvaluationException> leftArg, rightArg;
0528:
0529: leftArg = new DelayedIteration<BindingSet, QueryEvaluationException>() {
0530:
0531: @Override
0532: protected Iteration<BindingSet, QueryEvaluationException> createIteration()
0533: throws QueryEvaluationException {
0534: return evaluate(intersection.getLeftArg(), bindings);
0535: }
0536: };
0537:
0538: rightArg = new DelayedIteration<BindingSet, QueryEvaluationException>() {
0539:
0540: @Override
0541: protected Iteration<BindingSet, QueryEvaluationException> createIteration()
0542: throws QueryEvaluationException {
0543: return evaluate(intersection.getRightArg(), bindings);
0544: }
0545: };
0546:
0547: return new IntersectIteration<BindingSet, QueryEvaluationException>(
0548: leftArg, rightArg);
0549: }
0550:
0551: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0552: final Difference difference, final BindingSet bindings)
0553: throws QueryEvaluationException {
0554: Iteration<BindingSet, QueryEvaluationException> leftArg, rightArg;
0555:
0556: leftArg = new DelayedIteration<BindingSet, QueryEvaluationException>() {
0557:
0558: @Override
0559: protected Iteration<BindingSet, QueryEvaluationException> createIteration()
0560: throws QueryEvaluationException {
0561: return evaluate(difference.getLeftArg(), bindings);
0562: }
0563: };
0564:
0565: rightArg = new DelayedIteration<BindingSet, QueryEvaluationException>() {
0566:
0567: @Override
0568: protected Iteration<BindingSet, QueryEvaluationException> createIteration()
0569: throws QueryEvaluationException {
0570: return evaluate(difference.getRightArg(), bindings);
0571: }
0572: };
0573:
0574: return new MinusIteration<BindingSet, QueryEvaluationException>(
0575: leftArg, rightArg);
0576: }
0577:
0578: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0579: SingletonSet singletonSet, BindingSet bindings)
0580: throws QueryEvaluationException {
0581: return new SingletonIteration<BindingSet, QueryEvaluationException>(
0582: bindings);
0583: }
0584:
0585: public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(
0586: EmptySet emptySet, BindingSet bindings)
0587: throws QueryEvaluationException {
0588: return new EmptyIteration<BindingSet, QueryEvaluationException>();
0589: }
0590:
0591: public Value evaluate(ValueExpr expr, BindingSet bindings)
0592: throws ValueExprEvaluationException,
0593: QueryEvaluationException {
0594: if (expr instanceof Var) {
0595: return evaluate((Var) expr, bindings);
0596: } else if (expr instanceof ValueConstant) {
0597: return evaluate((ValueConstant) expr, bindings);
0598: } else if (expr instanceof BNodeGenerator) {
0599: return evaluate((BNodeGenerator) expr, bindings);
0600: } else if (expr instanceof Bound) {
0601: return evaluate((Bound) expr, bindings);
0602: } else if (expr instanceof Str) {
0603: return evaluate((Str) expr, bindings);
0604: } else if (expr instanceof Label) {
0605: return evaluate((Label) expr, bindings);
0606: } else if (expr instanceof Lang) {
0607: return evaluate((Lang) expr, bindings);
0608: } else if (expr instanceof LangMatches) {
0609: return evaluate((LangMatches) expr, bindings);
0610: } else if (expr instanceof Datatype) {
0611: return evaluate((Datatype) expr, bindings);
0612: } else if (expr instanceof Namespace) {
0613: return evaluate((Namespace) expr, bindings);
0614: } else if (expr instanceof LocalName) {
0615: return evaluate((LocalName) expr, bindings);
0616: } else if (expr instanceof IsResource) {
0617: return evaluate((IsResource) expr, bindings);
0618: } else if (expr instanceof IsURI) {
0619: return evaluate((IsURI) expr, bindings);
0620: } else if (expr instanceof IsBNode) {
0621: return evaluate((IsBNode) expr, bindings);
0622: } else if (expr instanceof IsLiteral) {
0623: return evaluate((IsLiteral) expr, bindings);
0624: } else if (expr instanceof Regex) {
0625: return evaluate((Regex) expr, bindings);
0626: } else if (expr instanceof Like) {
0627: return evaluate((Like) expr, bindings);
0628: } else if (expr instanceof FunctionCall) {
0629: return evaluate((FunctionCall) expr, bindings);
0630: } else if (expr instanceof And) {
0631: return evaluate((And) expr, bindings);
0632: } else if (expr instanceof Or) {
0633: return evaluate((Or) expr, bindings);
0634: } else if (expr instanceof Not) {
0635: return evaluate((Not) expr, bindings);
0636: } else if (expr instanceof SameTerm) {
0637: return evaluate((SameTerm) expr, bindings);
0638: } else if (expr instanceof Compare) {
0639: return evaluate((Compare) expr, bindings);
0640: } else if (expr instanceof MathExpr) {
0641: return evaluate((MathExpr) expr, bindings);
0642: } else if (expr instanceof In) {
0643: return evaluate((In) expr, bindings);
0644: } else if (expr instanceof CompareAny) {
0645: return evaluate((CompareAny) expr, bindings);
0646: } else if (expr instanceof CompareAll) {
0647: return evaluate((CompareAll) expr, bindings);
0648: } else if (expr instanceof Exists) {
0649: return evaluate((Exists) expr, bindings);
0650: } else if (expr == null) {
0651: throw new IllegalArgumentException("expr must not be null");
0652: } else {
0653: throw new QueryEvaluationException(
0654: "Unsupported value expr type: " + expr.getClass());
0655: }
0656: }
0657:
0658: public Value evaluate(Var var, BindingSet bindings)
0659: throws ValueExprEvaluationException,
0660: QueryEvaluationException {
0661: Value value = var.getValue();
0662:
0663: if (value == null) {
0664: value = bindings.getValue(var.getName());
0665: }
0666:
0667: if (value == null) {
0668: throw new ValueExprEvaluationException();
0669: }
0670:
0671: return value;
0672: }
0673:
0674: public Value evaluate(ValueConstant valueConstant,
0675: BindingSet bindings) throws ValueExprEvaluationException,
0676: QueryEvaluationException {
0677: return valueConstant.getValue();
0678: }
0679:
0680: public Value evaluate(BNodeGenerator node, BindingSet bindings)
0681: throws ValueExprEvaluationException,
0682: QueryEvaluationException {
0683: return tripleSource.getValueFactory().createBNode();
0684: }
0685:
0686: public Value evaluate(Bound node, BindingSet bindings)
0687: throws QueryEvaluationException {
0688: try {
0689: Value argValue = evaluate(node.getArg(), bindings);
0690: return BooleanLiteralImpl.valueOf(argValue != null);
0691: } catch (ValueExprEvaluationException e) {
0692: return BooleanLiteralImpl.FALSE;
0693: }
0694: }
0695:
0696: public Value evaluate(Str node, BindingSet bindings)
0697: throws ValueExprEvaluationException,
0698: QueryEvaluationException {
0699: Value argValue = evaluate(node.getArg(), bindings);
0700:
0701: if (argValue instanceof URI) {
0702: return tripleSource.getValueFactory().createLiteral(
0703: argValue.toString());
0704: } else if (argValue instanceof Literal) {
0705: Literal literal = (Literal) argValue;
0706:
0707: if (QueryEvaluationUtil.isSimpleLiteral(literal)) {
0708: return literal;
0709: } else {
0710: return tripleSource.getValueFactory().createLiteral(
0711: literal.getLabel());
0712: }
0713: } else {
0714: throw new ValueExprEvaluationException();
0715: }
0716: }
0717:
0718: public Value evaluate(Label node, BindingSet bindings)
0719: throws ValueExprEvaluationException,
0720: QueryEvaluationException {
0721: // FIXME: deprecate Label in favour of Str(?)
0722: Value argValue = evaluate(node.getArg(), bindings);
0723:
0724: if (argValue instanceof Literal) {
0725: Literal literal = (Literal) argValue;
0726:
0727: if (QueryEvaluationUtil.isSimpleLiteral(literal)) {
0728: return literal;
0729: } else {
0730: return tripleSource.getValueFactory().createLiteral(
0731: literal.getLabel());
0732: }
0733: } else {
0734: throw new ValueExprEvaluationException();
0735: }
0736: }
0737:
0738: public Value evaluate(Lang node, BindingSet bindings)
0739: throws ValueExprEvaluationException,
0740: QueryEvaluationException {
0741: Value argValue = evaluate(node.getArg(), bindings);
0742:
0743: if (argValue instanceof Literal) {
0744: Literal literal = (Literal) argValue;
0745:
0746: String langTag = literal.getLanguage();
0747: if (langTag == null) {
0748: langTag = "";
0749: }
0750:
0751: return tripleSource.getValueFactory()
0752: .createLiteral(langTag);
0753: }
0754:
0755: throw new ValueExprEvaluationException();
0756: }
0757:
0758: public Value evaluate(Datatype node, BindingSet bindings)
0759: throws ValueExprEvaluationException,
0760: QueryEvaluationException {
0761: Value v = evaluate(node.getArg(), bindings);
0762:
0763: if (v instanceof Literal) {
0764: Literal literal = (Literal) v;
0765:
0766: if (literal.getDatatype() != null) {
0767: // literal with datatype
0768: return literal.getDatatype();
0769: } else if (literal.getLanguage() == null) {
0770: // simple literal
0771: return XMLSchema.STRING;
0772: }
0773: }
0774:
0775: throw new ValueExprEvaluationException();
0776: }
0777:
0778: public Value evaluate(Namespace node, BindingSet bindings)
0779: throws ValueExprEvaluationException,
0780: QueryEvaluationException {
0781: Value argValue = evaluate(node.getArg(), bindings);
0782:
0783: if (argValue instanceof URI) {
0784: URI uri = (URI) argValue;
0785: return tripleSource.getValueFactory().createURI(
0786: uri.getNamespace());
0787: } else {
0788: throw new ValueExprEvaluationException();
0789: }
0790: }
0791:
0792: public Value evaluate(LocalName node, BindingSet bindings)
0793: throws ValueExprEvaluationException,
0794: QueryEvaluationException {
0795: Value argValue = evaluate(node.getArg(), bindings);
0796:
0797: if (argValue instanceof URI) {
0798: URI uri = (URI) argValue;
0799: return tripleSource.getValueFactory().createLiteral(
0800: uri.getLocalName());
0801: } else {
0802: throw new ValueExprEvaluationException();
0803: }
0804: }
0805:
0806: /**
0807: * Determines whether the operand (a variable) contains a Resource.
0808: *
0809: * @return <tt>true</tt> if the operand contains a Resource, <tt>false</tt>
0810: * otherwise.
0811: */
0812: public Value evaluate(IsResource node, BindingSet bindings)
0813: throws ValueExprEvaluationException,
0814: QueryEvaluationException {
0815: Value argValue = evaluate(node.getArg(), bindings);
0816: return BooleanLiteralImpl.valueOf(argValue instanceof Resource);
0817: }
0818:
0819: /**
0820: * Determines whether the operand (a variable) contains a URI.
0821: *
0822: * @return <tt>true</tt> if the operand contains a URI, <tt>false</tt>
0823: * otherwise.
0824: */
0825: public Value evaluate(IsURI node, BindingSet bindings)
0826: throws ValueExprEvaluationException,
0827: QueryEvaluationException {
0828: Value argValue = evaluate(node.getArg(), bindings);
0829: return BooleanLiteralImpl.valueOf(argValue instanceof URI);
0830: }
0831:
0832: /**
0833: * Determines whether the operand (a variable) contains a BNode.
0834: *
0835: * @return <tt>true</tt> if the operand contains a BNode, <tt>false</tt>
0836: * otherwise.
0837: */
0838: public Value evaluate(IsBNode node, BindingSet bindings)
0839: throws ValueExprEvaluationException,
0840: QueryEvaluationException {
0841: Value argValue = evaluate(node.getArg(), bindings);
0842: return BooleanLiteralImpl.valueOf(argValue instanceof BNode);
0843: }
0844:
0845: /**
0846: * Determines whether the operand (a variable) contains a Literal.
0847: *
0848: * @return <tt>true</tt> if the operand contains a Literal, <tt>false</tt>
0849: * otherwise.
0850: */
0851: public Value evaluate(IsLiteral node, BindingSet bindings)
0852: throws ValueExprEvaluationException,
0853: QueryEvaluationException {
0854: Value argValue = evaluate(node.getArg(), bindings);
0855: return BooleanLiteralImpl.valueOf(argValue instanceof Literal);
0856: }
0857:
0858: /**
0859: * Determines whether the two operands match according to the
0860: * <code>regex</code> operator.
0861: *
0862: * @return <tt>true</tt> if the operands match according to the
0863: * <tt>regex</tt> operator, <tt>false</tt> otherwise.
0864: */
0865: public Value evaluate(Regex node, BindingSet bindings)
0866: throws ValueExprEvaluationException,
0867: QueryEvaluationException {
0868: Value arg = evaluate(node.getArg(), bindings);
0869: Value parg = evaluate(node.getPatternArg(), bindings);
0870: Value farg = null;
0871: ValueExpr flagsArg = node.getFlagsArg();
0872: if (flagsArg != null) {
0873: farg = evaluate(flagsArg, bindings);
0874: }
0875:
0876: if (QueryEvaluationUtil.isSimpleLiteral(arg)
0877: && QueryEvaluationUtil.isSimpleLiteral(parg)
0878: && (farg == null || QueryEvaluationUtil
0879: .isSimpleLiteral(farg))) {
0880: String text = ((Literal) arg).getLabel();
0881: String ptn = ((Literal) parg).getLabel();
0882: String flags = "";
0883: if (farg != null) {
0884: flags = ((Literal) farg).getLabel();
0885: }
0886: // TODO should this Pattern be cached?
0887: int f = 0;
0888: for (char c : flags.toCharArray()) {
0889: switch (c) {
0890: case 's':
0891: f |= Pattern.DOTALL;
0892: break;
0893: case 'm':
0894: f |= Pattern.MULTILINE;
0895: break;
0896: case 'i':
0897: f |= Pattern.CASE_INSENSITIVE;
0898: break;
0899: case 'x':
0900: f |= Pattern.COMMENTS;
0901: break;
0902: case 'd':
0903: f |= Pattern.UNIX_LINES;
0904: break;
0905: case 'u':
0906: f |= Pattern.UNICODE_CASE;
0907: break;
0908: default:
0909: throw new ValueExprEvaluationException(flags);
0910: }
0911: }
0912: Pattern pattern = Pattern.compile(ptn, f);
0913: boolean result = pattern.matcher(text).find();
0914: return BooleanLiteralImpl.valueOf(result);
0915: }
0916:
0917: throw new ValueExprEvaluationException();
0918: }
0919:
0920: public Value evaluate(LangMatches node, BindingSet bindings)
0921: throws ValueExprEvaluationException,
0922: QueryEvaluationException {
0923: Value langTagValue = evaluate(node.getLeftArg(), bindings);
0924: Value langRangeValue = evaluate(node.getRightArg(), bindings);
0925:
0926: if (QueryEvaluationUtil.isSimpleLiteral(langTagValue)
0927: && QueryEvaluationUtil.isSimpleLiteral(langRangeValue)) {
0928: String langTag = ((Literal) langTagValue).getLabel();
0929: String langRange = ((Literal) langRangeValue).getLabel();
0930:
0931: boolean result = false;
0932: if (langRange.equals("*")) {
0933: result = langTag.length() > 0;
0934: } else if (langTag.length() == langRange.length()) {
0935: result = langTag.equalsIgnoreCase(langRange);
0936: } else if (langTag.length() > langRange.length()) {
0937: // check if the range is a prefix of the tag
0938: String prefix = langTag
0939: .substring(0, langRange.length());
0940: result = prefix.equalsIgnoreCase(langRange)
0941: && langTag.charAt(langRange.length()) == '-';
0942: }
0943:
0944: return BooleanLiteralImpl.valueOf(result);
0945: }
0946:
0947: throw new ValueExprEvaluationException();
0948:
0949: }
0950:
0951: /**
0952: * Determines whether the two operands match according to the
0953: * <code>like</code> operator. The operator is defined as a string
0954: * comparison with the possible use of an asterisk (*) at the end and/or the
0955: * start of the second operand to indicate substring matching.
0956: *
0957: * @return <tt>true</tt> if the operands match according to the
0958: * <tt>like</tt> operator, <tt>false</tt> otherwise.
0959: */
0960: public Value evaluate(Like node, BindingSet bindings)
0961: throws ValueExprEvaluationException,
0962: QueryEvaluationException {
0963: Value val = evaluate(node.getArg(), bindings);
0964: String strVal = null;
0965:
0966: if (val instanceof URI) {
0967: strVal = ((URI) val).toString();
0968: } else if (val instanceof Literal) {
0969: strVal = ((Literal) val).getLabel();
0970: }
0971:
0972: if (strVal == null) {
0973: throw new ValueExprEvaluationException();
0974: }
0975:
0976: if (!node.isCaseSensitive()) {
0977: // Convert strVal to lower case, just like the pattern has been done
0978: strVal = strVal.toLowerCase();
0979: }
0980:
0981: int valIndex = 0;
0982: int prevPatternIndex = -1;
0983: int patternIndex = node.getOpPattern().indexOf('*');
0984:
0985: if (patternIndex == -1) {
0986: // No wildcards
0987: return BooleanLiteralImpl.valueOf(node.getOpPattern()
0988: .equals(strVal));
0989: }
0990:
0991: String snippet;
0992:
0993: if (patternIndex > 0) {
0994: // Pattern does not start with a wildcard, first part must match
0995: snippet = node.getOpPattern().substring(0, patternIndex);
0996: if (!strVal.startsWith(snippet)) {
0997: return BooleanLiteralImpl.FALSE;
0998: }
0999:
1000: valIndex += snippet.length();
1001: prevPatternIndex = patternIndex;
1002: patternIndex = node.getOpPattern().indexOf('*',
1003: patternIndex + 1);
1004: }
1005:
1006: while (patternIndex != -1) {
1007: // Get snippet between previous wildcard and this wildcard
1008: snippet = node.getOpPattern().substring(
1009: prevPatternIndex + 1, patternIndex);
1010:
1011: // Search for the snippet in the value
1012: valIndex = strVal.indexOf(snippet, valIndex);
1013: if (valIndex == -1) {
1014: return BooleanLiteralImpl.FALSE;
1015: }
1016:
1017: valIndex += snippet.length();
1018: prevPatternIndex = patternIndex;
1019: patternIndex = node.getOpPattern().indexOf('*',
1020: patternIndex + 1);
1021: }
1022:
1023: // Part after last wildcard
1024: snippet = node.getOpPattern().substring(prevPatternIndex + 1);
1025:
1026: if (snippet.length() > 0) {
1027: // Pattern does not end with a wildcard.
1028:
1029: // Search last occurence of the snippet.
1030: valIndex = strVal.indexOf(snippet, valIndex);
1031: int i;
1032: while ((i = strVal.indexOf(snippet, valIndex + 1)) != -1) {
1033: // A later occurence was found.
1034: valIndex = i;
1035: }
1036:
1037: if (valIndex == -1) {
1038: return BooleanLiteralImpl.FALSE;
1039: }
1040:
1041: valIndex += snippet.length();
1042:
1043: if (valIndex < strVal.length()) {
1044: // Some characters were not matched
1045: return BooleanLiteralImpl.FALSE;
1046: }
1047: }
1048:
1049: return BooleanLiteralImpl.TRUE;
1050: }
1051:
1052: /**
1053: * Evaluates a function.
1054: */
1055: public Value evaluate(FunctionCall node, BindingSet bindings)
1056: throws ValueExprEvaluationException,
1057: QueryEvaluationException {
1058: Function function = FunctionRegistry.getInstance().get(
1059: node.getURI());
1060:
1061: if (function == null) {
1062: throw new QueryEvaluationException("Unknown function '"
1063: + node.getURI() + "'");
1064: }
1065:
1066: List<ValueExpr> args = node.getArgs();
1067:
1068: Value[] argValues = new Value[args.size()];
1069:
1070: for (int i = 0; i < args.size(); i++) {
1071: argValues[i] = evaluate(args.get(i), bindings);
1072: }
1073:
1074: return function.evaluate(tripleSource.getValueFactory(),
1075: argValues);
1076: }
1077:
1078: public Value evaluate(And node, BindingSet bindings)
1079: throws ValueExprEvaluationException,
1080: QueryEvaluationException {
1081: try {
1082: Value leftValue = evaluate(node.getLeftArg(), bindings);
1083: if (QueryEvaluationUtil.getEffectiveBooleanValue(leftValue) == false) {
1084: // Left argument evaluates to false, we don't need to look any
1085: // further
1086: return BooleanLiteralImpl.FALSE;
1087: }
1088: } catch (ValueExprEvaluationException e) {
1089: // Failed to evaluate the left argument. Result is 'false' when
1090: // the right argument evaluates to 'false', failure otherwise.
1091: Value rightValue = evaluate(node.getRightArg(), bindings);
1092: if (QueryEvaluationUtil
1093: .getEffectiveBooleanValue(rightValue) == false) {
1094: return BooleanLiteralImpl.FALSE;
1095: } else {
1096: throw new ValueExprEvaluationException();
1097: }
1098: }
1099:
1100: // Left argument evaluated to 'true', result is determined
1101: // by the evaluation of the right argument.
1102: Value rightValue = evaluate(node.getRightArg(), bindings);
1103: return BooleanLiteralImpl.valueOf(QueryEvaluationUtil
1104: .getEffectiveBooleanValue(rightValue));
1105: }
1106:
1107: public Value evaluate(Or node, BindingSet bindings)
1108: throws ValueExprEvaluationException,
1109: QueryEvaluationException {
1110: try {
1111: Value leftValue = evaluate(node.getLeftArg(), bindings);
1112: if (QueryEvaluationUtil.getEffectiveBooleanValue(leftValue) == true) {
1113: // Left argument evaluates to true, we don't need to look any
1114: // further
1115: return BooleanLiteralImpl.TRUE;
1116: }
1117: } catch (ValueExprEvaluationException e) {
1118: // Failed to evaluate the left argument. Result is 'true' when
1119: // the right argument evaluates to 'true', failure otherwise.
1120: Value rightValue = evaluate(node.getRightArg(), bindings);
1121: if (QueryEvaluationUtil
1122: .getEffectiveBooleanValue(rightValue) == true) {
1123: return BooleanLiteralImpl.TRUE;
1124: } else {
1125: throw new ValueExprEvaluationException();
1126: }
1127: }
1128:
1129: // Left argument evaluated to 'false', result is determined
1130: // by the evaluation of the right argument.
1131: Value rightValue = evaluate(node.getRightArg(), bindings);
1132: return BooleanLiteralImpl.valueOf(QueryEvaluationUtil
1133: .getEffectiveBooleanValue(rightValue));
1134: }
1135:
1136: public Value evaluate(Not node, BindingSet bindings)
1137: throws ValueExprEvaluationException,
1138: QueryEvaluationException {
1139: Value argValue = evaluate(node.getArg(), bindings);
1140: boolean argBoolean = QueryEvaluationUtil
1141: .getEffectiveBooleanValue(argValue);
1142: return BooleanLiteralImpl.valueOf(!argBoolean);
1143: }
1144:
1145: public Value evaluate(SameTerm node, BindingSet bindings)
1146: throws ValueExprEvaluationException,
1147: QueryEvaluationException {
1148: Value leftVal = evaluate(node.getLeftArg(), bindings);
1149: Value rightVal = evaluate(node.getRightArg(), bindings);
1150:
1151: return BooleanLiteralImpl.valueOf(leftVal != null
1152: && leftVal.equals(rightVal));
1153: }
1154:
1155: public Value evaluate(Compare node, BindingSet bindings)
1156: throws ValueExprEvaluationException,
1157: QueryEvaluationException {
1158: Value leftVal = evaluate(node.getLeftArg(), bindings);
1159: Value rightVal = evaluate(node.getRightArg(), bindings);
1160:
1161: return BooleanLiteralImpl.valueOf(QueryEvaluationUtil.compare(
1162: leftVal, rightVal, node.getOperator()));
1163: }
1164:
1165: public Value evaluate(MathExpr node, BindingSet bindings)
1166: throws ValueExprEvaluationException,
1167: QueryEvaluationException {
1168: // Do the math
1169: Value leftVal = evaluate(node.getLeftArg(), bindings);
1170: Value rightVal = evaluate(node.getRightArg(), bindings);
1171:
1172: if (leftVal instanceof Literal && rightVal instanceof Literal) {
1173: return getValue((Literal) leftVal, (Literal) rightVal, node
1174: .getOperator());
1175: }
1176:
1177: return null;
1178: }
1179:
1180: public Value evaluate(In node, BindingSet bindings)
1181: throws ValueExprEvaluationException,
1182: QueryEvaluationException {
1183: Value leftValue = evaluate(node.getArg(), bindings);
1184:
1185: // Result is false until a match has been found
1186: boolean result = false;
1187:
1188: // Use first binding name from tuple expr to compare values
1189: String bindingName = node.getSubQuery().getBindingNames()
1190: .iterator().next();
1191:
1192: CloseableIteration<BindingSet, QueryEvaluationException> iter = evaluate(
1193: node.getSubQuery(), bindings);
1194: try {
1195: while (result == false && iter.hasNext()) {
1196: BindingSet bindingSet = iter.next();
1197:
1198: Value rightValue = bindingSet.getValue(bindingName);
1199:
1200: result = leftValue == null && rightValue == null
1201: || leftValue != null
1202: && leftValue.equals(rightValue);
1203: }
1204: } finally {
1205: iter.close();
1206: }
1207:
1208: return BooleanLiteralImpl.valueOf(result);
1209: }
1210:
1211: public Value evaluate(CompareAny node, BindingSet bindings)
1212: throws ValueExprEvaluationException,
1213: QueryEvaluationException {
1214: Value leftValue = evaluate(node.getArg(), bindings);
1215:
1216: // Result is false until a match has been found
1217: boolean result = false;
1218:
1219: // Use first binding name from tuple expr to compare values
1220: String bindingName = node.getSubQuery().getBindingNames()
1221: .iterator().next();
1222:
1223: CloseableIteration<BindingSet, QueryEvaluationException> iter = evaluate(
1224: node.getSubQuery(), bindings);
1225: try {
1226: while (result == false && iter.hasNext()) {
1227: BindingSet bindingSet = iter.next();
1228:
1229: Value rightValue = bindingSet.getValue(bindingName);
1230:
1231: try {
1232: result = QueryEvaluationUtil.compare(leftValue,
1233: rightValue, node.getOperator());
1234: } catch (ValueExprEvaluationException e) {
1235: // ignore, maybe next value will match
1236: }
1237: }
1238: } finally {
1239: iter.close();
1240: }
1241:
1242: return BooleanLiteralImpl.valueOf(result);
1243: }
1244:
1245: public Value evaluate(CompareAll node, BindingSet bindings)
1246: throws ValueExprEvaluationException,
1247: QueryEvaluationException {
1248: Value leftValue = evaluate(node.getArg(), bindings);
1249:
1250: // Result is true until a mismatch has been found
1251: boolean result = true;
1252:
1253: // Use first binding name from tuple expr to compare values
1254: String bindingName = node.getSubQuery().getBindingNames()
1255: .iterator().next();
1256:
1257: CloseableIteration<BindingSet, QueryEvaluationException> iter = evaluate(
1258: node.getSubQuery(), bindings);
1259: try {
1260: while (result == true && iter.hasNext()) {
1261: BindingSet bindingSet = iter.next();
1262:
1263: Value rightValue = bindingSet.getValue(bindingName);
1264:
1265: try {
1266: result = QueryEvaluationUtil.compare(leftValue,
1267: rightValue, node.getOperator());
1268: } catch (ValueExprEvaluationException e) {
1269: // Exception thrown by ValueCompare.isTrue(...)
1270: result = false;
1271: }
1272: }
1273: } finally {
1274: iter.close();
1275: }
1276:
1277: return BooleanLiteralImpl.valueOf(result);
1278: }
1279:
1280: public Value evaluate(Exists node, BindingSet bindings)
1281: throws ValueExprEvaluationException,
1282: QueryEvaluationException {
1283: CloseableIteration<BindingSet, QueryEvaluationException> iter = evaluate(
1284: node.getSubQuery(), bindings);
1285: try {
1286: return BooleanLiteralImpl.valueOf(iter.hasNext());
1287: } finally {
1288: iter.close();
1289: }
1290: }
1291:
1292: public boolean isTrue(ValueExpr expr, BindingSet bindings)
1293: throws QueryEvaluationException {
1294: try {
1295: Value value = evaluate(expr, bindings);
1296: return QueryEvaluationUtil.getEffectiveBooleanValue(value);
1297: } catch (ValueExprEvaluationException e) {
1298: return false;
1299: }
1300: }
1301:
1302: private static Literal getValue(Literal leftLit, Literal rightLit,
1303: MathOp op) {
1304: URI leftDatatype = leftLit.getDatatype();
1305: URI rightDatatype = rightLit.getDatatype();
1306:
1307: // Only numeric value can be used in math expressions
1308: if (leftDatatype != null && rightDatatype != null
1309: && XMLDatatypeUtil.isNumericDatatype(leftDatatype)
1310: && XMLDatatypeUtil.isNumericDatatype(rightDatatype)) {
1311: // Determine most specific datatype that the arguments have in common,
1312: // choosing from xsd:integer, xsd:decimal, xsd:float and xsd:double as
1313: // per the SPARQL/XPATH spec
1314: URI commonDatatype;
1315:
1316: if (leftDatatype.equals(XMLSchema.DOUBLE)
1317: || rightDatatype.equals(XMLSchema.DOUBLE)) {
1318: commonDatatype = XMLSchema.DOUBLE;
1319: } else if (leftDatatype.equals(XMLSchema.FLOAT)
1320: || rightDatatype.equals(XMLSchema.FLOAT)) {
1321: commonDatatype = XMLSchema.FLOAT;
1322: } else if (leftDatatype.equals(XMLSchema.DECIMAL)
1323: || rightDatatype.equals(XMLSchema.DECIMAL)) {
1324: commonDatatype = XMLSchema.DECIMAL;
1325: } else if (op == MathOp.DIVIDE) {
1326: // Result of integer divide is decimal and requires the arguments to
1327: // be handled as such, see for details:
1328: // http://www.w3.org/TR/xpath-functions/#func-numeric-divide
1329: commonDatatype = XMLSchema.DECIMAL;
1330: } else {
1331: commonDatatype = XMLSchema.INTEGER;
1332: }
1333:
1334: // Note: Java already handles cases like divide-by-zero appropriately
1335: // for floats and doubles, see:
1336: // http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Tech/Chapter02/floatingPt2.html
1337:
1338: try {
1339: if (commonDatatype.equals(XMLSchema.DOUBLE)) {
1340: double left = leftLit.doubleValue();
1341: double right = rightLit.doubleValue();
1342:
1343: switch (op) {
1344: case PLUS:
1345: return new NumericLiteralImpl(left + right);
1346: case MINUS:
1347: return new NumericLiteralImpl(left - right);
1348: case MULTIPLY:
1349: return new NumericLiteralImpl(left * right);
1350: case DIVIDE:
1351: return new NumericLiteralImpl(left / right);
1352: default:
1353: throw new IllegalArgumentException(
1354: "Unknown operator: " + op);
1355: }
1356: } else if (commonDatatype.equals(XMLSchema.FLOAT)) {
1357: float left = leftLit.floatValue();
1358: float right = rightLit.floatValue();
1359:
1360: switch (op) {
1361: case PLUS:
1362: return new NumericLiteralImpl(left + right);
1363: case MINUS:
1364: return new NumericLiteralImpl(left - right);
1365: case MULTIPLY:
1366: return new NumericLiteralImpl(left * right);
1367: case DIVIDE:
1368: return new NumericLiteralImpl(left / right);
1369: default:
1370: throw new IllegalArgumentException(
1371: "Unknown operator: " + op);
1372: }
1373: } else if (commonDatatype.equals(XMLSchema.DECIMAL)) {
1374: BigDecimal left = leftLit.decimalValue();
1375: BigDecimal right = rightLit.decimalValue();
1376:
1377: switch (op) {
1378: case PLUS:
1379: return new DecimalLiteralImpl(left.add(right));
1380: case MINUS:
1381: return new DecimalLiteralImpl(left
1382: .subtract(right));
1383: case MULTIPLY:
1384: return new DecimalLiteralImpl(left
1385: .multiply(right));
1386: case DIVIDE:
1387: // Divide by zero handled through NumberFormatException
1388: return new DecimalLiteralImpl(left.divide(
1389: right, RoundingMode.HALF_UP));
1390: default:
1391: throw new IllegalArgumentException(
1392: "Unknown operator: " + op);
1393: }
1394: } else { // XMLSchema.INTEGER
1395: BigInteger left = leftLit.integerValue();
1396: BigInteger right = rightLit.integerValue();
1397:
1398: switch (op) {
1399: case PLUS:
1400: return new IntegerLiteralImpl(left.add(right));
1401: case MINUS:
1402: return new IntegerLiteralImpl(left
1403: .subtract(right));
1404: case MULTIPLY:
1405: return new IntegerLiteralImpl(left
1406: .multiply(right));
1407: case DIVIDE:
1408: throw new RuntimeException(
1409: "Integer divisions should be processed as decimal divisions");
1410: default:
1411: throw new IllegalArgumentException(
1412: "Unknown operator: " + op);
1413: }
1414: }
1415: } catch (NumberFormatException e) {
1416: return null;
1417: } catch (ArithmeticException e) {
1418: return null;
1419: }
1420: }
1421:
1422: return null;
1423: }
1424: }
|