/// <summary> /// Gets the value of the function in the given Evaluation Context for the given Binding ID /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { INode temp = this._expr.Evaluate(context, bindingID); if (temp != null) { if (temp.NodeType == NodeType.Uri) { IUriNode u = (IUriNode)temp; if (!u.Uri.Fragment.Equals(String.Empty)) { return new StringNode(null, u.Uri.Fragment.Substring(1)); } else { #if SILVERLIGHT return new StringNode(null, u.Uri.Segments().Last()); #else return new StringNode(null, u.Uri.Segments.Last()); #endif } } else { throw new RdfQueryException("Cannot find the Local Name for a non-URI Node"); } } else { throw new RdfQueryException("Cannot find the Local Name for a null"); } }
/// <summary> /// Evaluates an ExistsJoin /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else { //Only execute the RHS if the LHS had results context.InputMultiset = lhsResult; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.ExistsJoin(rhsResult, this._mustExist); context.CheckTimeout(); } context.InputMultiset = context.OutputMultiset; return context.OutputMultiset; }
/// <summary> /// Gets the numeric value of the function in the given Evaluation Context for the given Binding ID /// </summary> /// <param name = "context">Evaluation Context</param> /// <param name = "bindingID">Binding ID</param> /// <returns></returns> public override object NumericValue(SparqlEvaluationContext context, int bindingID) { INode temp = _expr.Value(context, bindingID); if (temp != null) { if (temp.NodeType == NodeType.Literal) { ILiteralNode lit = (ILiteralNode) temp; if (lit.DataType != null) { if (lit.DataType.ToString().Equals(XmlSpecsHelper.XmlSchemaDataTypeDateTime) || lit.DataType.ToString().Equals(XmlSpecsHelper.XmlSchemaDataTypeDate)) { DateTimeOffset dt; if (DateTimeOffset.TryParse(lit.Value, out dt)) { return NumericValueInternal(dt); } throw new RdfQueryException( "Unable to evaluate an XPath Date Time function as the value of the Date Time typed literal couldn't be parsed as a Date Time"); } throw new RdfQueryException( "Unable to evaluate an XPath Date Time function on a typed literal which is not a Date Time"); } throw new RdfQueryException( "Unable to evaluate an XPath Date Time function on an untyped literal argument"); } throw new RdfQueryException( "Unable to evaluate an XPath Date Time function on a non-literal argument"); } throw new RdfQueryException("Unable to evaluate an XPath Date Time function on a null argument"); }
/// <summary> /// Returns the value of the Expression as evaluated for a given Binding as a Literal Node /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { INode result = this._expr.Evaluate(context, bindingID); if (result == null) { throw new RdfQueryException("Cannot return the Data Type URI of a NULL"); } else { switch (result.NodeType) { case NodeType.Literal: ILiteralNode lit = (ILiteralNode)result; if (lit.DataType == null) { if (!lit.Language.Equals(string.Empty)) { return new UriNode(null, UriFactory.Create(RdfSpecsHelper.RdfLangString)); } else { return new UriNode(null, UriFactory.Create(XmlSpecsHelper.XmlSchemaDataTypeString)); } } else { return new UriNode(null, lit.DataType); } default: throw new RdfQueryException("Cannot return the Data Type URI of Nodes which are not Literal Nodes"); } } }
/// <summary> /// Evaluates the Select Distinct Graphs optimisation /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { context.OutputMultiset = new Multiset(); String var; if (context.Query != null) { var = context.Query.Variables.First(v => v.IsResultVariable).Name; } else { var = this._graphVar; } foreach (Uri graphUri in context.Data.GraphUris) { Set s = new Set(); if (graphUri == null) { s.Add(var, null); } else { s.Add(var, new UriNode(null, graphUri)); } context.OutputMultiset.Add(s); } return context.OutputMultiset; }
/// <summary> /// Generates the Description for each of the Nodes to be described /// </summary> /// <param name="handler">RDF Handler</param> /// <param name="context">SPARQL Evaluation Context</param> /// <param name="nodes">Nodes to be described</param> protected override void DescribeInternal(IRdfHandler handler, SparqlEvaluationContext context, IEnumerable<INode> nodes) { //Rewrite Blank Node IDs for DESCRIBE Results Dictionary<String, INode> bnodeMapping = new Dictionary<string, INode>(); //Get Triples for this Subject Queue<INode> bnodes = new Queue<INode>(); HashSet<INode> expandedBNodes = new HashSet<INode>(); INode rdfsLabel = handler.CreateUriNode(UriFactory.Create(NamespaceMapper.RDFS + "label")); foreach (INode n in nodes) { //Get Triples where the Node is the Subject foreach (Triple t in context.Data.GetTriplesWithSubject(n)) { if (t.Object.NodeType == NodeType.Blank) { if (!expandedBNodes.Contains(t.Object)) bnodes.Enqueue(t.Object); } if (!handler.HandleTriple((this.RewriteDescribeBNodes(t, bnodeMapping, handler)))) ParserHelper.Stop(); } //Compute the Blank Node Closure for this Subject while (bnodes.Count > 0) { INode bsubj = bnodes.Dequeue(); if (expandedBNodes.Contains(bsubj)) continue; expandedBNodes.Add(bsubj); foreach (Triple t2 in context.Data.GetTriplesWithSubjectPredicate(bsubj, rdfsLabel)) { if (!handler.HandleTriple((this.RewriteDescribeBNodes(t2, bnodeMapping, handler)))) ParserHelper.Stop(); } } } }
/// <summary> /// Computes the Effective Boolean Value of this Expression as evaluated for a given Binding /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override bool EffectiveBooleanValue(SparqlEvaluationContext context, int bindingID) { //Lazy Evaluation for efficiency try { bool leftResult = this._leftExpr.EffectiveBooleanValue(context, bindingID); if (leftResult) { //If the LHS is true it doesn't matter about any subsequenct results return true; } else { //If the LHS is false then we have to evaluate the RHS return this._rightExpr.EffectiveBooleanValue(context, bindingID); } } catch { //If there's an Error on the LHS we return true only if the RHS evaluates to true //Otherwise we throw the Error bool rightResult = this._rightExpr.EffectiveBooleanValue(context, bindingID); if (rightResult) { return true; } else { throw; } } }
/// <summary> /// Evaluates a Filter in the given Evaluation Context /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlEvaluationContext context) { if (context.InputMultiset is NullMultiset) { //If we get a NullMultiset then the FILTER has no effect since there are already no results } else if (context.InputMultiset is IdentityMultiset) { if (!this._filter.Variables.Any()) { //If we get an IdentityMultiset then the FILTER only has an effect if there are no //variables - otherwise it is not in scope and is ignored try { if (!this._filter.Expression.EffectiveBooleanValue(context, 0)) { context.OutputMultiset = new NullMultiset(); return; } } catch { context.OutputMultiset = new NullMultiset(); return; } } } else { this._filter.Evaluate(context); } context.OutputMultiset = new IdentityMultiset(); }
/// <summary> /// Gets the Numeric Value of the function as evaluated in the given Context for the given Binding ID /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode a = this._expr.Evaluate(context, bindingID); if (a == null) throw new RdfQueryException("Cannot calculate an arithmetic expression on a null"); switch (a.NumericType) { case SparqlNumericType.Integer: return new LongNode(null, Math.Abs(a.AsInteger())); case SparqlNumericType.Decimal: return new DecimalNode(null, Math.Abs(a.AsDecimal())); case SparqlNumericType.Float: try { return new FloatNode(null, Convert.ToSingle(Math.Abs(a.AsDouble()))); } catch (RdfQueryException) { throw; } catch (Exception ex) { throw new RdfQueryException("Unable to cast absolute value of float to a float", ex); } case SparqlNumericType.Double: return new DoubleNode(null, Math.Abs(a.AsDouble())); default: throw new RdfQueryException("Cannot evalute an Arithmetic Expression when the Numeric Type of the expression cannot be determined"); } }
/// <summary> /// Calculates the Numeric Value of this Expression as evaluated for a given Binding /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode a = this._expr.Evaluate(context, bindingID); if (a == null) throw new RdfQueryException("Cannot apply unary minus to a null"); switch (a.NumericType) { case SparqlNumericType.Integer: return new LongNode(null, -1 * a.AsInteger()); case SparqlNumericType.Decimal: decimal decvalue = a.AsDecimal(); if (decvalue == Decimal.Zero) { return new DecimalNode(null, Decimal.Zero); } else { return new DecimalNode(null, -1 * decvalue); } case SparqlNumericType.Float: float fltvalue = a.AsFloat(); if (Single.IsNaN(fltvalue)) { return new FloatNode(null, Single.NaN); } else if (Single.IsPositiveInfinity(fltvalue)) { return new FloatNode(null, Single.NegativeInfinity); } else if (Single.IsNegativeInfinity(fltvalue)) { return new FloatNode(null, Single.PositiveInfinity); } else { return new FloatNode(null, -1.0f * fltvalue); } case SparqlNumericType.Double: double dblvalue = a.AsDouble(); if (Double.IsNaN(dblvalue)) { return new DoubleNode(null, Double.NaN); } else if (Double.IsPositiveInfinity(dblvalue)) { return new DoubleNode(null, Double.NegativeInfinity); } else if (Double.IsNegativeInfinity(dblvalue)) { return new DoubleNode(null, Double.PositiveInfinity); } else { return new DoubleNode(null, -1.0 * dblvalue); } default: throw new RdfQueryException("Cannot evalute an Arithmetic Expression when the Numeric Type of the expression cannot be determined"); } }
/// <summary> /// Gets the Numeric Value of the Function as evaluated in the given Context for the given Binding ID /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override object NumericValue(SparqlEvaluationContext context, int bindingID) { if (this._expr is ISparqlNumericExpression) { ISparqlNumericExpression a = (ISparqlNumericExpression)this._expr; SparqlNumericType type = a.NumericType(context, bindingID); switch (type) { case SparqlNumericType.Integer: return this.IntegerValueInternal(a.IntegerValue(context, bindingID)); case SparqlNumericType.Decimal: return this.DecimalValueInternal(a.DecimalValue(context, bindingID)); case SparqlNumericType.Double: return this.DoubleValueInternal(a.DoubleValue(context, bindingID)); case SparqlNumericType.NaN: default: throw new RdfQueryException("Unable to evaluate a Leviathan Numeric Expression since the inner expression did not evaluate to a Numeric Value"); } } else { throw new RdfQueryException("Unable to evaluate a Leviathan Numeric Expression since the inner expression is not a Numeric Expression"); } }
/// <summary> /// Calculates the Numeric Value of this Expression as evaluated for a given Binding /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode a = this._leftExpr.Evaluate(context, bindingID); IValuedNode b = this._rightExpr.Evaluate(context, bindingID); if (a == null || b == null) throw new RdfQueryException("Cannot apply division when one/both arguments are null"); SparqlNumericType type = (SparqlNumericType)Math.Max((int)a.NumericType, (int)b.NumericType); try { switch (type) { case SparqlNumericType.Integer: case SparqlNumericType.Decimal: //For Division Integers are treated as decimals decimal d = a.AsDecimal() / b.AsDecimal(); if (Decimal.Floor(d).Equals(d) && d >= Int64.MinValue && d <= Int64.MaxValue) { return new LongNode(null, Convert.ToInt64(d)); } return new DecimalNode(null, d); case SparqlNumericType.Float: return new FloatNode(null, a.AsFloat() / b.AsFloat()); case SparqlNumericType.Double: return new DoubleNode(null, a.AsDouble() / b.AsDouble()); default: throw new RdfQueryException("Cannot evalute an Arithmetic Expression when the Numeric Type of the expression cannot be determined"); } } catch (DivideByZeroException) { throw new RdfQueryException("Cannot evaluate a Division Expression where the divisor is Zero"); } }
/// <summary> /// Gets the Timezone of the Argument Expression as evaluated for the given Binding in the given Context /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode temp = this._expr.Evaluate(context, bindingID); if (temp != null) { DateTimeOffset dt = temp.AsDateTime(); //Regex based check to see if the value has a Timezone component //If not then the result is a null if (!Regex.IsMatch(temp.AsString(), "(Z|[+-]\\d{2}:\\d{2})$")) return new StringNode(null, string.Empty); //Now we have a DateTime we can try and return the Timezone if (dt.Offset.Equals(TimeSpan.Zero)) { //If Zero it was specified as Z (which means UTC so zero offset) return new StringNode(null, "Z"); } else { //If the Offset is outside the range -14 to 14 this is considered invalid if (dt.Offset.Hours < -14 || dt.Offset.Hours > 14) return null; //Otherwise it has an offset which is a given number of hours (and minutes) return new StringNode(null, dt.Offset.Hours.ToString("00") + ":" + dt.Offset.Minutes.ToString("00")); } } else { throw new RdfQueryException("Unable to evaluate a Date Time function on a null argument"); } }
/// <summary> /// Calculates the Numeric Value of this Expression as evaluated for a given Binding /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override object NumericValue(SparqlEvaluationContext context, int bindingID) { if (this._leftExpr is ISparqlNumericExpression && this._rightExpr is ISparqlNumericExpression) { ISparqlNumericExpression a, b; a = (ISparqlNumericExpression)this._leftExpr; b = (ISparqlNumericExpression)this._rightExpr; SparqlNumericType type = (SparqlNumericType)Math.Max((int)a.NumericType(context, bindingID), (int)b.NumericType(context, bindingID)); switch (type) { case SparqlNumericType.Integer: return a.IntegerValue(context, bindingID) + b.IntegerValue(context, bindingID); case SparqlNumericType.Decimal: return a.DecimalValue(context, bindingID) + b.DecimalValue(context, bindingID); case SparqlNumericType.Float: return a.FloatValue(context, bindingID) + b.FloatValue(context, bindingID); case SparqlNumericType.Double: return a.DoubleValue(context, bindingID) + b.DoubleValue(context, bindingID); default: throw new RdfQueryException("Cannot evalute an Arithmetic Expression when the Numeric Type of the expression cannot be determined"); } } else { throw new RdfQueryException("Cannot evalute an Arithmetic Expression where the two sub-expressions are not Numeric Expressions"); } }
/// <summary> /// Gets the Value of the function as evaluated in the given Context for the given Binding ID /// </summary> /// <param name="context">Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public INode Value(SparqlEvaluationContext context, int bindingID) { INode temp = this._expr.Value(context, bindingID); if (temp != null) { if (temp.NodeType == NodeType.Literal) { ILiteralNode lit = (ILiteralNode)temp; if (lit.DataType != null) { if (lit.DataType.ToString().Equals(XmlSpecsHelper.XmlSchemaDataTypeString)) { return this.ValueInternal(lit); } else { throw new RdfQueryException("Unable to evalaute an XPath String function on a non-string typed Literal"); } } else { return this.ValueInternal(lit); } } else { throw new RdfQueryException("Unable to evaluate an XPath String function on a non-Literal input"); } } else { throw new RdfQueryException("Unable to evaluate an XPath String function on a null input"); } }
/// <summary> /// Gets the Numeric Value of the function as evaluated in the given Context for the given Binding ID /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override object NumericValue(SparqlEvaluationContext context, int bindingID) { if (this._expr is ISparqlNumericExpression) { ISparqlNumericExpression a = (ISparqlNumericExpression)this._expr; switch (a.NumericType(context, bindingID)) { case SparqlNumericType.Integer: return Math.Abs(a.IntegerValue(context, bindingID)); case SparqlNumericType.Decimal: return Math.Abs(a.DecimalValue(context, bindingID)); case SparqlNumericType.Float: return (float)Math.Abs(a.DoubleValue(context, bindingID)); case SparqlNumericType.Double: return Math.Abs(a.DoubleValue(context, bindingID)); default: throw new RdfQueryException("Cannot evalute an Arithmetic Expression when the Numeric Type of the expression cannot be determined"); } } else { throw new RdfQueryException("Cannot evalute an Arithmetic Expression where the sub-expression is not a Numeric Expressions"); } }
/// <summary> /// Creates a new Path Evaluation Context /// </summary> /// <param name="context">SPARQL Evaluation Context</param> /// <param name="end">Start point of the Path</param> /// <param name="start">End point of the Path</param> public PathEvaluationContext(SparqlEvaluationContext context, PatternItem start, PatternItem end) { this._context = context; this._start = start; this._end = end; if (this._start.VariableName == null && this._end.VariableName == null) this._earlyAbort = true; }
/// <summary> /// Returns the Graph which is the Result of the Describe Query by computing the Concise Bounded Description for all Results /// </summary> /// <param name="context">SPARQL Evaluation Context</param> /// <returns></returns> public override IGraph Describe(SparqlEvaluationContext context) { //Get a new empty Graph and import the Base Uri and Namespace Map of the Query Graph g = new Graph(); g.BaseUri = context.Query.BaseUri; g.NamespaceMap.Import(context.Query.NamespaceMap); //Build a list of INodes to describe List<INode> nodes = new List<INode>(); foreach (IToken t in context.Query.DescribeVariables) { switch (t.TokenType) { case Token.QNAME: case Token.URI: //Resolve Uri/QName nodes.Add(new UriNode(g, new Uri(Tools.ResolveUriOrQName(t, g.NamespaceMap, g.BaseUri)))); break; case Token.VARIABLE: //Get Variable Values String var = t.Value.Substring(1); if (context.OutputMultiset.ContainsVariable(var)) { foreach (Set s in context.OutputMultiset.Sets) { INode temp = s[var]; if (temp != null) nodes.Add(temp); } } break; default: throw new RdfQueryException("Unexpected Token '" + t.GetType().ToString() + "' in DESCRIBE Variables list"); } } //Rewrite Blank Node IDs for DESCRIBE Results Dictionary<String, INode> bnodeMapping = new Dictionary<string, INode>(); //Get Triples for this Subject foreach (INode n in nodes) { //Get Triples where the Node is the Subject foreach (Triple t in context.Data.GetTriplesWithSubject(n)) { g.Assert(this.RewriteDescribeBNodes(t, bnodeMapping, g)); } //Get Triples where the Node is the Object foreach (Triple t in context.Data.GetTriplesWithObject(n)) { g.Assert(this.RewriteDescribeBNodes(t, bnodeMapping, g)); } } //Return the Graph g.BaseUri = null; return g; }
/// <summary> /// Evaluates the expression /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode temp = this._expr.Evaluate(context, bindingID); if (temp == null) throw new RdfQueryException("Cannot apply a trigonometric function to a null"); if (temp.NumericType == SparqlNumericType.NaN) throw new RdfQueryException("Cannot apply a trigonometric function to a non-numeric argument"); return new DoubleNode(null, this._func(temp.AsDouble())); }
/// <summary> /// Evaluates the subquery in the given context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Use the same algebra optimisers as the parent query (if any) if (context.Query != null) { this._subquery.AlgebraOptimisers = context.Query.AlgebraOptimisers; } if (context.InputMultiset is NullMultiset) { context.OutputMultiset = context.InputMultiset; } else if (context.InputMultiset.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else { SparqlEvaluationContext subcontext = new SparqlEvaluationContext(this._subquery, context.Data, context.Processor); subcontext.InputMultiset = context.InputMultiset; //Add any Named Graphs to the subquery if (context.Query != null) { foreach (Uri u in context.Query.NamedGraphs) { this._subquery.AddNamedGraph(u); } } ISparqlAlgebra query = this._subquery.ToAlgebra(); try { //Evaluate the Subquery context.OutputMultiset = subcontext.Evaluate(query); //If the Subquery contains a GROUP BY it may return a Group Multiset in which case we must flatten this to a Multiset if (context.OutputMultiset is GroupMultiset) { context.OutputMultiset = new Multiset((GroupMultiset)context.OutputMultiset); } //Strip out any Named Graphs from the subquery if (this._subquery.NamedGraphs.Any()) { this._subquery.ClearNamedGraphs(); } } catch (RdfQueryException queryEx) { throw new RdfQueryException("Query failed due to a failure in Subquery Execution:\n" + queryEx.Message, queryEx); } } return context.OutputMultiset; }
/// <summary> /// Gets the value of the function in the given Evaluation Context for the given Binding ID /// </summary> /// <param name = "context">Evaluation Context</param> /// <param name = "bindingID">Binding ID</param> /// <returns></returns> public INode Value(SparqlEvaluationContext context, int bindingID) { ILiteralNode input = CheckArgument(_expr, context, bindingID); ILiteralNode start = CheckArgument(_start, context, bindingID, XPathFunctionFactory.AcceptNumericArguments); if (_end != null) { ILiteralNode end = CheckArgument(_end, context, bindingID, XPathFunctionFactory.AcceptNumericArguments); if (input.Value.Equals(String.Empty)) return new LiteralNode(null, String.Empty, new Uri(XmlSpecsHelper.XmlSchemaDataTypeString)); try { int s = Convert.ToInt32(start.Value); int e = Convert.ToInt32(end.Value); if (s < 0) s = 0; if (e < s) { //If no/negative characters are being selected the empty string is returned return new LiteralNode(null, String.Empty, new Uri(XmlSpecsHelper.XmlSchemaDataTypeString)); } if (s > input.Value.Length) { //If the start is after the end of the string the empty string is returned return new LiteralNode(null, String.Empty, new Uri(XmlSpecsHelper.XmlSchemaDataTypeString)); } return e > input.Value.Length ? new LiteralNode(null, input.Value.Substring(s), new Uri(XmlSpecsHelper.XmlSchemaDataTypeString)) : new LiteralNode(null, input.Value.Substring(s, e - s), new Uri(XmlSpecsHelper.XmlSchemaDataTypeString)); } catch { throw new RdfQueryException("Unable to convert the Start/End argument to an Integer"); } } if (input.Value.Equals(String.Empty)) return new LiteralNode(null, String.Empty, new Uri(XmlSpecsHelper.XmlSchemaDataTypeString)); try { int s = Convert.ToInt32(start.Value); if (s < 0) s = 0; return new LiteralNode(null, input.Value.Substring(s), new Uri(XmlSpecsHelper.XmlSchemaDataTypeString)); } catch { throw new RdfQueryException("Unable to convert the Start argument to an Integer"); } }
/// <summary> /// Checks whether the pattern accepts the given Node /// </summary> /// <param name="context">SPARQL Evaluation Context</param> /// <param name="obj">Node to test</param> /// <returns></returns> protected internal override bool Accepts(SparqlEvaluationContext context, INode obj) { if (obj.NodeType == NodeType.Blank) { return ((IBlankNode)obj).InternalID.Equals(this._id); } else { return false; } }
/// <summary> /// Checks whether the given Node matches the Node this pattern was instantiated with /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="obj">Node to test</param> /// <returns></returns> protected internal override bool Accepts(SparqlEvaluationContext context, INode obj) { //if (context.RigorousEvaluation) //{ return this._node.Equals(obj); //} //else //{ // return true; //} }
/// <summary> /// Casts the results of the inner expression to a Literal Node typed xsd:string /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode n = this._expr.Evaluate(context, bindingID); if (n == null) { throw new RdfQueryException("Cannot cast a Null to a xsd:string"); } return new StringNode(null, n.AsString(), UriFactory.Create(XmlSpecsHelper.XmlSchemaDataTypeString)); }
/// <summary> /// Gets the numeric value of the function in the given Evaluation Context for the given Binding ID /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode temp = this._expr.Evaluate(context, bindingID); if (temp != null) { return this.ValueInternal(temp.AsDateTime()); } else { throw new RdfQueryException("Unable to evaluate an XPath Date Time function on a null argument"); } }
/// <summary> /// Computes the Effective Boolean Value of this Expression as evaluated for a given Binding /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { INode result = this._expr.Evaluate(context, bindingID); if (result == null) { return new BooleanNode(null, false); } else { return new BooleanNode(null, result.NodeType == NodeType.Uri); } }
public BaseMultiset Evaluate(SparqlEvaluationContext context) { //First evaluate the inner algebra BaseMultiset results = context.Evaluate(this._inner); context.OutputMultiset = new Multiset(); if (results is NullMultiset) { context.OutputMultiset = results; } else if (results is IdentityMultiset) { context.OutputMultiset.AddVariable(this._var); Set s = new Set(); try { INode temp = this._expr.Value(context, 0); s.Add(this._var, temp); } catch { //No assignment if there's an error s.Add(this._var, null); } context.OutputMultiset.Add(s); } else { if (results.ContainsVariable(this._var)) { throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query"); } context.OutputMultiset.AddVariable(this._var); foreach (int id in results.SetIDs.ToList()) { Set s = new Set(results[id]); try { //Make a new assignment INode temp = this._expr.Value(context, id); s.Add(this._var, temp); } catch { //No assignment if there's an error but the solution is preserved } context.OutputMultiset.Add(s); } } return context.OutputMultiset; }
/// <summary> /// Evaluates the Union /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Create a copy of the evaluation context for the RHS SparqlEvaluationContext context2 = new SparqlEvaluationContext(context.Query, context.Data, context.Processor); if (!(context.InputMultiset is IdentityMultiset)) { context2.InputMultiset = new Multiset(); foreach (ISet s in context.InputMultiset.Sets) { context2.InputMultiset.Add(s.Copy()); } } IGraph activeGraph = context.Data.ActiveGraph; IGraph defaultGraph = context.Data.DefaultGraph; ParallelEvaluateDelegate d = new ParallelEvaluateDelegate(this.ParallelEvaluate); IAsyncResult lhs = d.BeginInvoke(this._lhs, context, activeGraph, defaultGraph, null, null); IAsyncResult rhs = d.BeginInvoke(this._rhs, context2, activeGraph, defaultGraph, null, null); WaitHandle.WaitAll(new WaitHandle[] { lhs.AsyncWaitHandle, rhs.AsyncWaitHandle }); bool rhsOk = false; try { BaseMultiset lhsResult = d.EndInvoke(lhs); rhsOk = true; BaseMultiset rhsResult = d.EndInvoke(rhs); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return context.OutputMultiset; } catch { if (!rhsOk) { //Clean up the RHS evaluation call if the LHS has errored try { d.EndInvoke(rhs); } catch { //Ignore this error as we're already going to throw the other error } } throw; } }
public override object NumericValue(SparqlEvaluationContext context, int bindingID) { INode value = this._expr.Value(context, bindingID); if (value != null) { if (value.NodeType == NodeType.Literal) { ILiteralNode lit = (ILiteralNode)value; if (!lit.Language.Equals(String.Empty)) { //If there's a Language Tag implied type is string so no numeric value throw new RdfQueryException("Cannot calculate the Numeric Value of literal with a language specifier"); } else if (lit.DataType == null) { throw new RdfQueryException("Cannot calculate the Numeric Value of an untyped Literal"); } else { try { switch (SparqlSpecsHelper.GetNumericTypeFromDataTypeUri(lit.DataType)) { case SparqlNumericType.Decimal: return Decimal.Parse(lit.Value); case SparqlNumericType.Double: return Double.Parse(lit.Value); case SparqlNumericType.Float: return Single.Parse(lit.Value); case SparqlNumericType.Integer: return Int64.Parse(lit.Value); case SparqlNumericType.NaN: default: throw new RdfQueryException("Cannot calculate the Numeric Value of a literal since its Data Type URI does not correspond to a Data Type URI recognised as a Numeric Type in the SPARQL Specification"); } } catch (FormatException fEx) { throw new RdfQueryException("Cannot calculate the Numeric Value of a Literal since the Value contained is not a valid value in it's given Data Type", fEx); } } } else { throw new RdfQueryException("Cannot evaluate a numeric expression when the inner expression evaluates to a non-literal node"); } } else { throw new RdfQueryException("Cannot evaluate a numeric expression when the inner expression evaluates to null"); } }
/// <summary> /// Returns the value of the Expression as evaluated for a given Binding as a Literal Node /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { INode s = this._leftExpr.Evaluate(context, bindingID); INode dt = this._rightExpr.Evaluate(context, bindingID); if (s != null) { if (dt != null) { Uri dtUri; if (dt.NodeType == NodeType.Uri) { dtUri = ((IUriNode)dt).Uri; } else { throw new RdfQueryException("Cannot create a datatyped literal when the datatype is a non-URI Node"); } if (s.NodeType == NodeType.Literal) { ILiteralNode lit = (ILiteralNode)s; if (lit.DataType == null) { if (lit.Language.Equals(string.Empty)) { return new StringNode(null, lit.Value, dtUri); } else { throw new RdfQueryException("Cannot create a datatyped literal from a language specified literal"); } } else { throw new RdfQueryException("Cannot create a datatyped literal from a typed literal"); } } else { throw new RdfQueryException("Cannot create a datatyped literal from a non-literal Node"); } } else { throw new RdfQueryException("Cannot create a datatyped literal from a null string"); } } else { throw new RdfQueryException("Cannot create a datatyped literal from a null string"); } }
/// <summary> /// Evaluates the function /// </summary> /// <param name="context">Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { return(this._node); }
/// <summary> /// Evaluates the BGP against the Evaluation Context. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public override BaseMultiset Evaluate(SparqlEvaluationContext context) { bool halt; BaseMultiset results = null; int origRequired = _requiredResults; // May need to detect the actual amount of required results if not specified at instantation if (_requiredResults < 0) { if (context.Query != null) { if (context.Query.HasDistinctModifier || (context.Query.OrderBy != null && !context.Query.IsOptimisableOrderBy) || context.Query.GroupBy != null || context.Query.Having != null || context.Query.Bindings != null) { // If there's an DISTINCT/ORDER BY/GROUP BY/HAVING/BINDINGS present then can't do Lazy evaluation _requiredResults = -1; } else { int limit = context.Query.Limit; int offset = context.Query.Offset; if (limit >= 0 && offset >= 0) { // If there is a Limit and Offset specified then the required results is the LIMIT+OFFSET _requiredResults = limit + offset; } else if (limit >= 0) { // If there is just a Limit specified then the required results is the LIMIT _requiredResults = limit; } else { // In any other case required results is everything i.e. -1 _requiredResults = -1; } } Debug.WriteLine("Lazy Evaluation - Number of required results is " + _requiredResults); } } switch (_requiredResults) { case -1: // If required results is everything just use normal evaluation as otherwise // lazy evaluation will significantly impact performance and lead to an apparent infinite loop return(base.Evaluate(context)); case 0: // Don't need any results results = new NullMultiset(); break; default: // Do streaming evaluation if (_requiredResults != 0) { results = StreamingEvaluate(context, 0, out halt); if (results is Multiset && results.IsEmpty) { results = new NullMultiset(); } } break; } _requiredResults = origRequired; context.OutputMultiset = results; context.OutputMultiset.Trim(); return(context.OutputMultiset); }
/// <summary> /// Evaluates a Zero Length Path /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public override BaseMultiset Evaluate(SparqlEvaluationContext context) { if (this.AreBothTerms()) { if (this.AreSameTerms()) { return(new IdentityMultiset()); } else { return(new NullMultiset()); } } String subjVar = this.PathStart.VariableName; String objVar = this.PathEnd.VariableName; context.OutputMultiset = new Multiset(); //Determine the Triples to which this applies IEnumerable <Triple> ts = null; if (subjVar != null) { //Subject is a Variable if (context.InputMultiset.ContainsVariable(subjVar)) { //Subject is Bound if (objVar != null) { //Object is a Variable if (context.InputMultiset.ContainsVariable(objVar)) { //Object is Bound ts = (from s in context.InputMultiset.Sets where s[subjVar] != null && s[objVar] != null from t in context.Data.GetTriplesWithSubjectObject(s[subjVar], s[objVar]) select t); } else { //Object is Unbound ts = (from s in context.InputMultiset.Sets where s[subjVar] != null from t in context.Data.GetTriplesWithSubject(s[subjVar]) select t); } } else { //Object is a Term //Preseve sets where the Object Term is equal to the currently bound Subject INode objTerm = ((NodeMatchPattern)this.PathEnd).Node; foreach (ISet s in context.InputMultiset.Sets) { INode temp = s[subjVar]; if (temp != null && temp.Equals(objTerm)) { context.OutputMultiset.Add(s.Copy()); } } } } else { //Subject is Unbound if (objVar != null) { //Object is a Variable if (context.InputMultiset.ContainsVariable(objVar)) { //Object is Bound ts = (from s in context.InputMultiset.Sets where s[objVar] != null from t in context.Data.GetTriplesWithObject(s[objVar]) select t); } else { //Object is Unbound HashSet <INode> nodes = new HashSet <INode>(); foreach (Triple t in context.Data.Triples) { nodes.Add(t.Subject); nodes.Add(t.Object); } foreach (INode n in nodes) { Set s = new Set(); s.Add(subjVar, n); s.Add(objVar, n); context.OutputMultiset.Add(s); } } } else { //Object is a Term //Create a single set with the Variable bound to the Object Term Set s = new Set(); s.Add(subjVar, ((NodeMatchPattern)this.PathEnd).Node); context.OutputMultiset.Add(s); } } } else if (objVar != null) { //Subject is a Term but Object is a Variable if (context.InputMultiset.ContainsVariable(objVar)) { //Object is Bound //Preseve sets where the Subject Term is equal to the currently bound Object INode subjTerm = ((NodeMatchPattern)this.PathStart).Node; foreach (ISet s in context.InputMultiset.Sets) { INode temp = s[objVar]; if (temp != null && temp.Equals(subjTerm)) { context.OutputMultiset.Add(s.Copy()); } } } else { //Object is Unbound //Create a single set with the Variable bound to the Suject Term Set s = new Set(); s.Add(objVar, ((NodeMatchPattern)this.PathStart).Node); context.OutputMultiset.Add(s); } } else { //Should already have dealt with this earlier (the AreBothTerms() and AreSameTerms() branch) throw new RdfQueryException("Reached unexpected point of ZeroLengthPath evaluation"); } //Get the Matches only if we haven't already generated the output if (ts != null) { HashSet <KeyValuePair <INode, INode> > matches = new HashSet <KeyValuePair <INode, INode> >(); foreach (Triple t in ts) { if (this.PathStart.Accepts(context, t.Subject) && this.PathEnd.Accepts(context, t.Object)) { matches.Add(new KeyValuePair <INode, INode>(t.Subject, t.Object)); } } //Generate the Output based on the mathces if (matches.Count == 0) { context.OutputMultiset = new NullMultiset(); } else { if (this.PathStart.VariableName == null && this.PathEnd.VariableName == null) { context.OutputMultiset = new IdentityMultiset(); } else { context.OutputMultiset = new Multiset(); foreach (KeyValuePair <INode, INode> m in matches) { Set s = new Set(); if (subjVar != null) { s.Add(subjVar, m.Key); } if (objVar != null) { s.Add(objVar, m.Value); } context.OutputMultiset.Add(s); } } } } return(context.OutputMultiset); }
/// <summary> /// Gets the Timezone of the Argument Expression as evaluated for the given Binding in the given Context /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override INode Value(SparqlEvaluationContext context, int bindingID) { INode temp = this._expr.Value(context, bindingID); if (temp != null) { if (temp.NodeType == NodeType.Literal) { ILiteralNode lit = (ILiteralNode)temp; if (lit.DataType != null) { if (lit.DataType.ToString().Equals(XmlSpecsHelper.XmlSchemaDataTypeDateTime)) { DateTimeOffset dt; if (DateTimeOffset.TryParse(lit.Value, out dt)) { //Regex based check to see if the value has a Timezone component //If not then the result is a null if (!Regex.IsMatch(lit.Value, "(Z|[+-]\\d{2}:\\d{2})$")) { return(new LiteralNode(null, String.Empty)); } //Now we have a DateTime we can try and return the Timezone if (dt.Offset.Equals(TimeSpan.Zero)) { //If Zero it was specified as Z (which means UTC so zero offset) return(new LiteralNode(null, "Z")); } else { //If the Offset is outside the range -14 to 14 this is considered invalid if (dt.Offset.Hours < -14 || dt.Offset.Hours > 14) { return(null); } //Otherwise it has an offset which is a given number of hours (and minutes) return(new LiteralNode(null, dt.Offset.Hours.ToString("00") + ":" + dt.Offset.Minutes.ToString("00"))); } } else { throw new RdfQueryException("Unable to evaluate a Date Time function as the value of the Date Time typed literal couldn't be parsed as a Date Time"); } } else { throw new RdfQueryException("Unable to evaluate a Date Time function on a typed literal which is not a Date Time"); } } else { throw new RdfQueryException("Unable to evaluate a Date Time function on an untyped literal argument"); } } else { throw new RdfQueryException("Unable to evaluate a Date Time function on a non-literal argument"); } } else { throw new RdfQueryException("Unable to evaluate a Date Time function on a null argument"); } }
/// <summary> /// Calculates the Numeric Value of this Expression as evaluated for a given Binding /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override Object NumericValue(SparqlEvaluationContext context, int bindingID) { if (this._expr is ISparqlNumericExpression) { ISparqlNumericExpression a = (ISparqlNumericExpression)this._expr; switch (a.NumericType(context, bindingID)) { case SparqlNumericType.Integer: return(-1 * a.IntegerValue(context, bindingID)); case SparqlNumericType.Decimal: decimal decvalue = a.DecimalValue(context, bindingID); if (decvalue == 0) { return(0.0m); } else { return(-1 * decvalue); } case SparqlNumericType.Float: float fltvalue = a.FloatValue(context, bindingID); if (Single.IsNaN(fltvalue)) { return(Single.NaN); } else if (Single.IsPositiveInfinity(fltvalue)) { return(Single.NegativeInfinity); } else if (Single.IsNegativeInfinity(fltvalue)) { return(Single.PositiveInfinity); } else { return(-1.0 * fltvalue); } case SparqlNumericType.Double: double dblvalue = a.DoubleValue(context, bindingID); if (Double.IsNaN(dblvalue)) { return(Double.NaN); } else if (Double.IsPositiveInfinity(dblvalue)) { return(Double.NegativeInfinity); } else if (Double.IsNegativeInfinity(dblvalue)) { return(Double.PositiveInfinity); } else { return(-1.0 * dblvalue); } default: throw new RdfQueryException("Cannot evalute an Arithmetic Expression when the Numeric Type of the expression cannot be determined"); } } else { throw new RdfQueryException("Cannot evalute an Arithmetic Expression where the sub-expression is not a Numeric Expressions"); } }
/// <summary> /// Casts the value of the inner Expression to a Boolean /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode n = this._expr.Evaluate(context, bindingID);//.CoerceToBoolean(); //if (n == null) //{ // throw new RdfQueryException("Cannot cast a Null to a xsd:boolean"); //} ////New method should be much faster //if (n is BooleanNode) return n; //return new BooleanNode(null, n.AsBoolean()); switch (n.NodeType) { case NodeType.Blank: case NodeType.GraphLiteral: case NodeType.Uri: throw new RdfQueryException("Cannot cast a Blank/URI/Graph Literal Node to a xsd:boolean"); case NodeType.Literal: //See if the value can be cast if (n is BooleanNode) { return(n); } ILiteralNode lit = (ILiteralNode)n; if (lit.DataType != null) { string dt = lit.DataType.ToString(); if (dt.Equals(XmlSpecsHelper.XmlSchemaDataTypeBoolean)) { //Already a Boolean bool b; if (Boolean.TryParse(lit.Value, out b)) { return(new BooleanNode(lit.Graph, b)); } else { throw new RdfQueryException("Invalid Lexical Form for xsd:boolean"); } } //Cast based on Numeric Type SparqlNumericType type = SparqlSpecsHelper.GetNumericTypeFromDataTypeUri(dt); switch (type) { case SparqlNumericType.Decimal: Decimal dec; if (Decimal.TryParse(lit.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out dec)) { if (dec.Equals(Decimal.Zero)) { return(new BooleanNode(lit.Graph, false)); } else { return(new BooleanNode(lit.Graph, true)); } } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:decimal as an intermediate stage in casting to a xsd:boolean"); } case SparqlNumericType.Double: Double dbl; if (Double.TryParse(lit.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out dbl)) { if (Double.IsNaN(dbl) || dbl == 0.0d) { return(new BooleanNode(lit.Graph, false)); } else { return(new BooleanNode(lit.Graph, true)); } } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:double as an intermediate stage in casting to a xsd:boolean"); } case SparqlNumericType.Integer: Int64 i; if (Int64.TryParse(lit.Value, out i)) { if (i == 0) { return(new BooleanNode(lit.Graph, false)); } else { return(new BooleanNode(lit.Graph, true)); } } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:integer as an intermediate stage in casting to a xsd:boolean"); } case SparqlNumericType.NaN: if (dt.Equals(XmlSpecsHelper.XmlSchemaDataTypeDateTime)) { //DateTime cast forbidden throw new RdfQueryException("Cannot cast a xsd:dateTime to a xsd:boolean"); } else { Boolean b; if (Boolean.TryParse(lit.Value, out b)) { return(new BooleanNode(lit.Graph, b)); } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:boolean"); } } default: throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:boolean"); } } else { Boolean b; if (Boolean.TryParse(lit.Value, out b)) { return(new BooleanNode(lit.Graph, b)); } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:boolean"); } } default: throw new RdfQueryException("Cannot cast an Unknown Node to a xsd:decimal"); } }
/// <summary> /// Applies the Numeric Min Aggregate function to the results /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingIDs">Binding IDs over which the Aggregate applies</param> /// <returns></returns> public override IValuedNode Apply(SparqlEvaluationContext context, IEnumerable <int> bindingIDs) { if (this._varname != null) { // Ensured the MINed variable is in the Variables of the Results if (!context.Binder.Variables.Contains(this._varname)) { throw new RdfQueryException("Cannot use the Variable " + this._expr.ToString() + " in a NMIN Aggregate since the Variable does not occur in a Graph Pattern"); } } // Prep Variables long lngmin = 0; decimal decmin = 0.0m; float fltmin = 0.0f; double dblmin = 0.0d; SparqlNumericType mintype = SparqlNumericType.NaN; SparqlNumericType numtype; foreach (int id in bindingIDs) { IValuedNode temp; try { temp = this._expr.Evaluate(context, id); if (temp == null) { continue; } numtype = temp.NumericType; } catch { continue; } // Skip if Not a Number if (numtype == SparqlNumericType.NaN) { continue; } // Track the Numeric Type if ((int)numtype > (int)mintype) { if (mintype == SparqlNumericType.NaN) { // Initialise Minimums switch (numtype) { case SparqlNumericType.Integer: lngmin = temp.AsInteger(); decmin = temp.AsDecimal(); fltmin = temp.AsFloat(); dblmin = temp.AsDouble(); break; case SparqlNumericType.Decimal: decmin = temp.AsDecimal(); fltmin = temp.AsFloat(); dblmin = temp.AsDouble(); break; case SparqlNumericType.Float: fltmin = temp.AsFloat(); dblmin = temp.AsDouble(); break; case SparqlNumericType.Double: dblmin = temp.AsDouble(); break; } mintype = numtype; continue; } else { mintype = numtype; } } long lngval; decimal decval; float fltval; double dblval; switch (mintype) { case SparqlNumericType.Integer: lngval = temp.AsInteger(); if (lngval < lngmin) { lngmin = lngval; decmin = temp.AsDecimal(); fltmin = temp.AsFloat(); dblmin = temp.AsDouble(); } break; case SparqlNumericType.Decimal: decval = temp.AsDecimal(); if (decval < decmin) { decmin = decval; fltmin = temp.AsFloat(); dblmin = temp.AsDouble(); } break; case SparqlNumericType.Float: fltval = temp.AsFloat(); if (fltval < fltmin) { fltmin = fltval; dblmin = temp.AsDouble(); } break; case SparqlNumericType.Double: dblval = temp.AsDouble(); if (dblval < dblmin) { dblmin = dblval; } break; } } // Return the Min switch (mintype) { case SparqlNumericType.NaN: // No Numeric Values return(null); case SparqlNumericType.Integer: // Integer Values return(new LongNode(null, lngmin)); case SparqlNumericType.Decimal: // Decimal Values return(new DecimalNode(null, decmin)); case SparqlNumericType.Float: // Float Values return(new FloatNode(null, fltmin)); case SparqlNumericType.Double: // Double Values return(new DoubleNode(null, dblmin)); default: throw new RdfQueryException("Failed to calculate a valid Minimum"); } }
/// <summary> /// Trims the Results of evaluating the inner pattern to remove Variables which are not Result Variables. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { try { context.InputMultiset = context.Evaluate(_pattern); } catch (RdfQueryTimeoutException) { // If not partial results throw the error if (context.Query == null || !context.Query.PartialResultsOnTimeout) { throw; } } // Ensure expected variables are present HashSet <SparqlVariable> vars = new HashSet <SparqlVariable>(_variables); if (context.InputMultiset is NullMultiset) { context.InputMultiset = new Multiset(vars.Select(v => v.Name)); } else if (context.InputMultiset is IdentityMultiset) { context.InputMultiset = new Multiset(vars.Select(v => v.Name)); context.InputMultiset.Add(new Set()); } else if (context.InputMultiset.IsEmpty) { foreach (SparqlVariable var in vars) { context.InputMultiset.AddVariable(var.Name); } } // Trim Variables that aren't being SELECTed if (!IsSelectAll) { foreach (String var in context.InputMultiset.Variables.ToList()) { if (!vars.Any(v => v.Name.Equals(var) && v.IsResultVariable)) { // If not a Result variable then trim from results context.InputMultiset.Trim(var); } } } // Ensure all SELECTed variables are present foreach (SparqlVariable var in vars) { if (!context.InputMultiset.ContainsVariable(var.Name)) { context.InputMultiset.AddVariable(var.Name); } } context.OutputMultiset = context.InputMultiset; // Apply variable ordering if applicable if (!IsSelectAll && (context.Query == null || SparqlSpecsHelper.IsSelectQuery(context.Query.QueryType))) { context.OutputMultiset.SetVariableOrder(context.Query.Variables.Where(v => v.IsResultVariable).Select(v => v.Name)); } return(context.OutputMultiset); }
/// <summary> /// Generates the Description for each of the Nodes to be described /// </summary> /// <param name="handler">RDF Handler</param> /// <param name="context">SPARQL Evaluation Context</param> /// <param name="nodes">Nodes to be described</param> protected override void DescribeInternal(IRdfHandler handler, SparqlEvaluationContext context, IEnumerable <INode> nodes) { // Rewrite Blank Node IDs for DESCRIBE Results Dictionary <String, INode> bnodeMapping = new Dictionary <string, INode>(); // Get Triples for this Subject Queue <INode> bnodes = new Queue <INode>(); HashSet <INode> expandedBNodes = new HashSet <INode>(); foreach (INode n in nodes) { // Get Triples where the Node is the Subject foreach (Triple t in context.Data.GetTriplesWithSubject(n).ToList()) { if (t.Object.NodeType == NodeType.Blank) { if (!expandedBNodes.Contains(t.Object)) { bnodes.Enqueue(t.Object); } } if (!handler.HandleTriple(RewriteDescribeBNodes(t, bnodeMapping, handler))) { ParserHelper.Stop(); } } // Get Triples where the Node is the Object foreach (Triple t in context.Data.GetTriplesWithObject(n).ToList()) { if (t.Subject.NodeType == NodeType.Blank) { if (!expandedBNodes.Contains(t.Subject)) { bnodes.Enqueue(t.Subject); } } if (!handler.HandleTriple(RewriteDescribeBNodes(t, bnodeMapping, handler))) { ParserHelper.Stop(); } } // Compute the Blank Node Closure for this Subject while (bnodes.Count > 0) { INode bsubj = bnodes.Dequeue(); if (expandedBNodes.Contains(bsubj)) { continue; } expandedBNodes.Add(bsubj); foreach (Triple t2 in context.Data.GetTriplesWithSubject(bsubj).ToList()) { if (t2.Object.NodeType == NodeType.Blank) { if (!expandedBNodes.Contains(t2.Object)) { bnodes.Enqueue(t2.Object); } } if (!handler.HandleTriple(RewriteDescribeBNodes(t2, bnodeMapping, handler))) { ParserHelper.Stop(); } } foreach (Triple t2 in context.Data.GetTriplesWithObject(bsubj).ToList()) { if (t2.Subject.NodeType == NodeType.Blank) { if (!expandedBNodes.Contains(t2.Subject)) { bnodes.Enqueue(t2.Subject); } } if (!handler.HandleTriple(RewriteDescribeBNodes(t2, bnodeMapping, handler))) { ParserHelper.Stop(); } } } } }
/// <summary> /// Evaluates the expression. /// </summary> /// <param name="context">Evaluation Context.</param> /// <param name="bindingID">Binding ID.</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { return(new BooleanNode(null, _expr.Evaluate(context, bindingID).AsSafeBoolean())); }
/// <summary> /// Evaluates a filter in the given Evaluation Context. /// </summary> /// <param name="context">Evaluation Context.</param> public abstract void Evaluate(SparqlEvaluationContext context);
/// <summary> /// Casts the Value of the inner Expression to a Decimal /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode n = _expr.Evaluate(context, bindingID);//.CoerceToDecimal(); if (n == null) { throw new RdfQueryException("Cannot cast a Null to a xsd:decimal"); } // New method should be much faster // if (n is DecimalNode) return n; // return new DecimalNode(null, n.AsDecimal()); switch (n.NodeType) { case NodeType.Blank: case NodeType.GraphLiteral: case NodeType.Uri: throw new RdfQueryException("Cannot cast a Blank/URI/Graph Literal Node to a xsd:decimal"); case NodeType.Literal: if (n is DecimalNode) { return(n); } // See if the value can be cast ILiteralNode lit = (ILiteralNode)n; if (lit.DataType != null) { string dt = lit.DataType.ToString(); if (SparqlSpecsHelper.IntegerDataTypes.Contains(dt)) { // Already an integer type so valid as a xsd:decimal decimal d; if (Decimal.TryParse(lit.Value, NumberStyles.Any ^ NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out d)) { // Parsed OK return(new DecimalNode(lit.Graph, d)); } else { throw new RdfQueryException("Invalid lexical form for xsd:decimal"); } } else if (dt.Equals(XmlSpecsHelper.XmlSchemaDataTypeDateTime)) { // DateTime cast forbidden throw new RdfQueryException("Cannot cast a xsd:dateTime to a xsd:decimal"); } else { decimal d; if (Decimal.TryParse(lit.Value, NumberStyles.Any ^ NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out d)) { // Parsed OK return(new DecimalNode(lit.Graph, d)); } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:decimal"); } } } else { decimal d; if (Decimal.TryParse(lit.Value, NumberStyles.Any ^ NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out d)) { // Parsed OK return(new DecimalNode(lit.Graph, d)); } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:decimal"); } } default: throw new RdfQueryException("Cannot cast an Unknown Node to a xsd:decimal"); } }
/// <summary> /// Gets the value of the expression as evaluated in a given Context for a given Binding /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { this._funcContext = context[SparqlSpecsHelper.SparqlKeywordBNode] as BNodeFunctionContext; if (this._funcContext == null) { this._funcContext = new BNodeFunctionContext(context.InputMultiset.GetHashCode()); context[SparqlSpecsHelper.SparqlKeywordBNode] = this._funcContext; } else if (this._funcContext.CurrentInput != context.InputMultiset.GetHashCode()) { //Clear the Context this._funcContext.BlankNodes.Clear(); context[SparqlSpecsHelper.SparqlKeywordBNode] = this._funcContext; } if (this._expr == null) { //If no argument then always a fresh BNode return(this._funcContext.Graph.CreateBlankNode().AsValuedNode()); } else { INode temp = this._expr.Evaluate(context, bindingID); if (temp != null) { if (temp.NodeType == NodeType.Literal) { ILiteralNode lit = (ILiteralNode)temp; if (lit.DataType == null) { if (lit.Language.Equals(string.Empty)) { if (!this._funcContext.BlankNodes.ContainsKey(bindingID)) { this._funcContext.BlankNodes.Add(bindingID, new Dictionary <string, INode>()); } if (!this._funcContext.BlankNodes[bindingID].ContainsKey(lit.Value)) { this._funcContext.BlankNodes[bindingID].Add(lit.Value, this._funcContext.Graph.CreateBlankNode()); } return(this._funcContext.BlankNodes[bindingID][lit.Value].AsValuedNode()); } else { throw new RdfQueryException("Cannot create a Blank Node when the argument Expression evaluates to a lanuage specified literal"); } } else { throw new RdfQueryException("Cannot create a Blank Node when the argument Expression evaluates to a typed literal node"); } } else { throw new RdfQueryException("Cannot create a Blank Node when the argument Expression evaluates to a non-literal node"); } } else { throw new RdfQueryException("Cannot create a Blank Node when the argument Expression evaluates to null"); } } }
/// <summary> /// Casts the value of the inner Expression to a Date Time /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode n = this._expr.Evaluate(context, bindingID);//.CoerceToDateTime(); if (n == null) { throw new RdfQueryException("Cannot cast a Null to a xsd:dateTime"); } // New method should be much faster // if (n is DateTimeNode) return n; // if (n is DateNode) return new DateTimeNode(n.Graph, n.AsDateTime()); // return new DateTimeNode(null, n.AsDateTime()); switch (n.NodeType) { case NodeType.Blank: case NodeType.GraphLiteral: case NodeType.Uri: throw new RdfQueryException("Cannot cast a Blank/URI/Graph Literal Node to a xsd:dateTime"); case NodeType.Literal: if (n is DateTimeNode) { return(n); } if (n is DateNode) { return(new DateTimeNode(n.Graph, n.AsDateTime())); } // See if the value can be cast ILiteralNode lit = (ILiteralNode)n; if (lit.DataType != null) { string dt = lit.DataType.ToString(); if (dt.Equals(XmlSpecsHelper.XmlSchemaDataTypeDateTime)) { // Already a xsd:dateTime DateTimeOffset d; if (DateTimeOffset.TryParse(lit.Value, out d)) { // Parsed OK return(new DateTimeNode(lit.Graph, d)); } else { throw new RdfQueryException("Invalid lexical form for xsd:dateTime"); } } else if (dt.Equals(XmlSpecsHelper.XmlSchemaDataTypeString)) { DateTimeOffset d; if (DateTimeOffset.TryParse(lit.Value, out d)) { // Parsed OK return(new DateTimeNode(lit.Graph, d)); } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:double"); } } else { throw new RdfQueryException("Cannot cast a Literal typed <" + dt + "> to a xsd:dateTime"); } } else { DateTimeOffset d; if (DateTimeOffset.TryParse(lit.Value, out d)) { // Parsed OK return(new DateTimeNode(lit.Graph, d)); } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:dateTime"); } } default: throw new RdfQueryException("Cannot cast an Unknown Node to a xsd:string"); } }
/// <summary> /// Returns the value of the Expression as evaluated for a given Binding as a Literal Node /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { //Configure Options if (this._optionExpr != null) { this.ConfigureOptions(this._optionExpr.Evaluate(context, bindingID), true); } //Compile the Regex if necessary if (!this._fixedPattern) { //Regex is not pre-compiled if (this._findExpr != null) { IValuedNode p = this._findExpr.Evaluate(context, bindingID); if (p != null) { if (p.NodeType == NodeType.Literal) { this._find = p.AsString(); } else { throw new RdfQueryException("Cannot parse a Pattern String from a non-Literal Node"); } } else { throw new RdfQueryException("Not a valid Pattern Expression"); } } else { throw new RdfQueryException("Not a valid Pattern Expression or the fixed Pattern String was invalid"); } } //Compute the Replace if necessary if (!this._fixedReplace) { if (this._replaceExpr != null) { IValuedNode r = this._replaceExpr.Evaluate(context, bindingID); if (r != null) { if (r.NodeType == NodeType.Literal) { this._replace = r.AsString(); } else { throw new RdfQueryException("Cannot parse a Replace String from a non-Literal Node"); } } else { throw new RdfQueryException("Not a valid Replace Expression"); } } else { throw new RdfQueryException("Not a valid Replace Expression"); } } //Execute the Regular Expression IValuedNode textNode = this._textExpr.Evaluate(context, bindingID); if (textNode == null) { throw new RdfQueryException("Cannot evaluate a Regular Expression against a NULL"); } if (textNode.NodeType == NodeType.Literal) { //Execute ILiteralNode lit = (ILiteralNode)textNode; if (lit.DataType != null && !lit.DataType.ToString().Equals(XmlSpecsHelper.XmlSchemaDataTypeString)) { throw new RdfQueryException("Text Argument to Replace must be of type xsd:string if a datatype is specified"); } string text = lit.Value; string output = Regex.Replace(text, this._find, this._replace, this._options); if (lit.DataType != null) { return(new StringNode(null, output, lit.DataType)); } else if (!lit.Language.Equals(string.Empty)) { return(new StringNode(null, output, lit.Language)); } else { return(new StringNode(null, output)); } } else { throw new RdfQueryException("Cannot evaluate a Regular Expression against a non-Literal Node"); } }
/// <summary> /// Evaluates the BGP against the Evaluation Context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { if (this._triplePatterns.Count > 0) { for (int i = 0; i < this._triplePatterns.Count; i++) { if (i == 0) { //If the 1st thing in a BGP is a BIND/LET/FILTER the Input becomes the Identity Multiset if (this._triplePatterns[i].PatternType == TriplePatternType.Filter || this._triplePatterns[i].PatternType == TriplePatternType.BindAssignment || this._triplePatterns[i].PatternType == TriplePatternType.LetAssignment) { if (this._triplePatterns[i].PatternType == TriplePatternType.BindAssignment) { if (context.InputMultiset.ContainsVariable(((IAssignmentPattern)this._triplePatterns[i]).VariableName)) { throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been declared"); } } else { context.InputMultiset = new IdentityMultiset(); } } } //Create a new Output Multiset context.OutputMultiset = new Multiset(); this._triplePatterns[i].Evaluate(context); //If at any point we've got an Empty Multiset as our Output then we terminate BGP execution if (context.OutputMultiset.IsEmpty) { break; } //Check for Timeout before attempting the Join context.CheckTimeout(); //If this isn't the first Pattern we do Join/Product the Output to the Input if (i > 0) { if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { //Disjoint so do a Product context.OutputMultiset = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { //Normal Join context.OutputMultiset = context.InputMultiset.Join(context.OutputMultiset); } } //Then the Input for the next Pattern is the Output from the previous Pattern context.InputMultiset = context.OutputMultiset; } if (context.TrimTemporaryVariables) { //Trim the Multiset - this eliminates any temporary variables context.OutputMultiset.Trim(); } } else { //For an Empty BGP we just return the Identity Multiset context.OutputMultiset = new IdentityMultiset(); } //If we've ended with an Empty Multiset then we turn it into the Null Multiset //to indicate that this BGP did not match anything if (context.OutputMultiset is Multiset && context.OutputMultiset.IsEmpty) { context.OutputMultiset = new NullMultiset(); } //Return the Output Multiset return(context.OutputMultiset); }
/// <summary> /// Evaluates the algebra in the given context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { context.InputMultiset = context.Evaluate(this._algebra); return(this._function.Evaluate(context)); }
/// <summary> /// Counts the results /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingIDs">Binding IDs over which the Aggregate applies</param> /// <returns></returns> public override IValuedNode Apply(SparqlEvaluationContext context, IEnumerable <int> bindingIDs) { //Just Count the number of results return(new LongNode(null, bindingIDs.Count())); }
private ILiteralNode CheckArgument(ISparqlExpression expr, SparqlEvaluationContext context, int bindingID) { return(this.CheckArgument(expr, context, bindingID, XPathFunctionFactory.AcceptStringArguments)); }
/// <summary> /// Returns the fixed set of solutions. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { context.OutputMultiset = _table; return(context.OutputMultiset); }
/// <summary> /// Evaluates the property function /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlEvaluationContext context) { context.OutputMultiset = this._function.Evaluate(context); }
/// <summary> /// Evalutes the algebra for the given evaluation context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public abstract BaseMultiset Evaluate(SparqlEvaluationContext context);
/// <summary> /// Gets the Effective Boolean Value of the Expression as evaluated for the given Binding in the given Context /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public override bool EffectiveBooleanValue(SparqlEvaluationContext context, int bindingID) { return(SparqlSpecsHelper.EffectiveBooleanValue(this.Value(context, bindingID))); }
/// <summary> /// Applies the Filter over the results of evaluating the inner pattern /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public sealed override BaseMultiset Evaluate(SparqlEvaluationContext context) { INode term = this._term.Evaluate(null, 0); //First take appropriate pre-filtering actions if (context.InputMultiset is IdentityMultiset) { //If the Input is Identity switch the input to be a Multiset containing a single Set //where the variable is bound to the term context.InputMultiset = new Multiset(); Set s = new Set(); s.Add(this.RestrictionVariable, term); context.InputMultiset.Add(s); } else if (context.InputMultiset is NullMultiset) { //If Input is Null then output is Null context.OutputMultiset = context.InputMultiset; return(context.OutputMultiset); } else { if (context.InputMultiset.ContainsVariable(this.RestrictionVariable)) { //If the Input Multiset contains the variable then pre-filter foreach (int id in context.InputMultiset.SetIDs.ToList()) { ISet x = context.InputMultiset[id]; try { if (x.ContainsVariable(this.RestrictionVariable)) { //If does exist check it has appropriate value and if not remove it if (!term.Equals(x[this.RestrictionVariable])) { context.InputMultiset.Remove(id); } } else { //If doesn't exist for this set then bind it to the term x.Add(this.RestrictionVariable, term); } } catch (RdfQueryException) { context.InputMultiset.Remove(id); } } } else { //If it doesn't contain the variable then bind for each existing set foreach (ISet x in context.InputMultiset.Sets) { x.Add(this.RestrictionVariable, term); } } } //Then evaluate the inner algebra BaseMultiset results = context.Evaluate(this.InnerAlgebra); if (results is NullMultiset || results is IdentityMultiset) { return(results); } //Filter the results to ensure that the variable is indeed bound to the term foreach (int id in results.SetIDs.ToList()) { ISet x = results[id]; try { if (!term.Equals(x[this.RestrictionVariable])) { results.Remove(id); } } catch (RdfQueryException) { results.Remove(id); } } if (results.Count > 0) { context.OutputMultiset = results; } else { context.OutputMultiset = new NullMultiset(); } return(context.OutputMultiset); }
/// <summary> /// Evaluates the expression /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public virtual IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { Guid uuid = Guid.NewGuid(); return(EvaluateInternal(uuid)); }
/// <summary> /// Evaluates the property function. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //The very first thing we must do is check the incoming input if (context.InputMultiset is NullMultiset) { return(context.InputMultiset); //Can abort evaluation if input is null } if (context.InputMultiset.IsEmpty) { return(context.InputMultiset); //Can abort evaluation if input is null } //Then we need to retrieve the full text search provider IFullTextSearchProvider provider = context[FullTextHelper.ContextKey] as IFullTextSearchProvider; if (provider == null) { throw new FullTextQueryException("No Full Text Search Provider is available, please ensure you attach a FullTextQueryOptimiser to your query"); } //First determine whether we can apply the limit when talking to the provider //Essentially as long as the Match Variable (the one we'll bind results to) is not already //bound AND we are actually using a limit bool applyLimitDirect = this._limit.HasValue && this._limit.Value > -1 && this._matchVar.VariableName != null && !context.InputMultiset.ContainsVariable(this._matchVar.VariableName); //Is there a constant for the Match Item? If so extract it now //Otherwise are we needing to check against existing bindings INode matchConstant = null; bool checkExisting = false; HashSet <INode> existing = null; if (this._matchVar.VariableName == null) { matchConstant = ((NodeMatchPattern)this._matchVar).Node; } else if (this._matchVar.VariableName != null && context.InputMultiset.ContainsVariable(this._matchVar.VariableName)) { checkExisting = true; existing = new HashSet <INode>(); foreach (INode n in context.InputMultiset.Sets.Select(s => s[this._matchVar.VariableName]).Where(s => s != null)) { existing.Add(n); } } //Then check that the score variable is not already bound, if so error //If a Score Variable is provided and it is OK then we'll bind scores at a later stage if (this._scoreVar != null) { if (this._scoreVar.VariableName == null) { throw new FullTextQueryException("Queries using full text search that wish to return result scores must provide a variable"); } if (this._scoreVar.VariableName != null && context.InputMultiset.ContainsVariable(this._scoreVar.VariableName)) { throw new FullTextQueryException("Queries using full text search that wish to return result scores must use an unbound variable to do so"); } } //Next ensure that the search text is a node and not a variable if (this._searchVar.VariableName != null) { throw new FullTextQueryException("Queries using full text search must provide a constant value for the search term"); } INode searchNode = ((NodeMatchPattern)this._searchVar).Node; if (searchNode.NodeType != NodeType.Literal) { throw new FullTextQueryException("Queries using full text search must use a literal value for the search term"); } String search = ((ILiteralNode)searchNode).Value; //Determine which graphs we are operating over IEnumerable <Uri> graphUris = context.Data.ActiveGraphUris; //Now we can use the full text search provider to start getting results context.OutputMultiset = new Multiset(); IEnumerable <IFullTextSearchResult> results = applyLimitDirect ? this.GetResults(graphUris, provider, search, this._limit.Value) : this.GetResults(graphUris, provider, search); int r = 0; String matchVar = this._matchVar.VariableName; String scoreVar = this._scoreVar != null ? this._scoreVar.VariableName : null; foreach (IFullTextSearchResult result in results) { if (matchConstant != null) { //Check against constant if present if (result.Node.Equals(matchConstant)) { r++; context.OutputMultiset.Add(result.ToSet(matchVar, scoreVar)); } } else if (checkExisting) { //Check against existing bindings if present if (existing.Contains(result.Node)) { r++; context.OutputMultiset.Add(result.ToSet(matchVar, scoreVar)); } } else { //Otherwise all results are acceptable r++; context.OutputMultiset.Add(result.ToSet(matchVar, scoreVar)); } //Apply the limit locally if necessary if (!applyLimitDirect && this._limit > -1 && r >= this._limit) { break; } } return(context.OutputMultiset); }
private BaseMultiset StreamingEvaluate(SparqlEvaluationContext context, int pattern, out bool halt) { // Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); halt = false; // Handle Empty BGPs if (pattern == 0 && _triplePatterns.Count == 0) { context.OutputMultiset = new IdentityMultiset(); return(context.OutputMultiset); } BaseMultiset initialInput, localOutput, results = null; // Determine whether the Pattern modifies the existing Input rather than joining to it bool modifies = (_triplePatterns[pattern].PatternType == TriplePatternType.Filter); bool extended = (pattern > 0 && _triplePatterns[pattern - 1].PatternType == TriplePatternType.BindAssignment); bool modified = (pattern > 0 && _triplePatterns[pattern - 1].PatternType == TriplePatternType.Filter); // Set up the Input and Output Multiset appropriately switch (pattern) { case 0: // Input is as given and Output is new empty multiset if (!modifies) { initialInput = context.InputMultiset; } else { // If the Pattern will modify the Input and is the first thing in the BGP then it actually modifies a new empty input // This takes care of FILTERs being out of scope initialInput = new Multiset(); } localOutput = new Multiset(); break; case 1: // Input becomes current Output and Output is new empty multiset initialInput = context.OutputMultiset; localOutput = new Multiset(); break; default: if (!extended && !modified) { // Input is join of previous input and output and Output is new empty multiset if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { // Disjoint so do a Product initialInput = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { // Normal Join initialInput = context.InputMultiset.Join(context.OutputMultiset); } } else { initialInput = context.OutputMultiset; } localOutput = new Multiset(); break; } context.InputMultiset = initialInput; context.OutputMultiset = localOutput; // Get the Triple Pattern we're evaluating ITriplePattern temp = _triplePatterns[pattern]; int resultsFound = 0; int prevResults = -1; if (temp.PatternType == TriplePatternType.Match) { // Find the first Triple which matches the Pattern IMatchTriplePattern tp = (IMatchTriplePattern)temp; IEnumerable <Triple> ts = tp.GetTriples(context); // In the case that we're lazily evaluating an optimisable ORDER BY then // we need to apply OrderBy()'s to our enumeration // This only applies to the 1st pattern if (pattern == 0) { if (context.Query != null) { if (context.Query.OrderBy != null && context.Query.IsOptimisableOrderBy) { IComparer <Triple> comparer = context.Query.OrderBy.GetComparer(tp); if (comparer != null) { ts = ts.OrderBy(t => t, comparer); } else { // Can't get a comparer so can't optimise // Thus required results is everything so just use normal evaluation as otherwise // lazy evaluation will significantly impact performance and lead to an apparent infinite loop return(base.Evaluate(context)); } } } } foreach (Triple t in ts) { if (tp.Accepts(context, t)) { resultsFound++; if (tp.IndexType == TripleIndexType.NoVariables) { localOutput = new IdentityMultiset(); context.OutputMultiset = localOutput; } else { context.OutputMultiset.Add(tp.CreateResult(t)); } } } // Recurse unless we're the last pattern if (pattern < _triplePatterns.Count - 1) { results = StreamingEvaluate(context, pattern + 1, out halt); // If recursion leads to a halt then we halt and return immediately if (halt && results.Count >= _requiredResults && _requiredResults != -1) { return(results); } else if (halt) { if (results.Count == 0) { // If recursing leads to no results then eliminate all outputs // Also reset to prevResults to -1 resultsFound = 0; localOutput = new Multiset(); prevResults = -1; } else if (prevResults > -1) { if (results.Count == prevResults) { // If the amount of results found hasn't increased then this match does not // generate any further solutions further down the recursion so we can eliminate // this from the results localOutput.Remove(localOutput.SetIDs.Max()); } } prevResults = results.Count; // If we're supposed to halt but not reached the number of required results then continue context.InputMultiset = initialInput; context.OutputMultiset = localOutput; } else { // Otherwise we need to keep going here // So must reset our input and outputs before continuing context.InputMultiset = initialInput; context.OutputMultiset = new Multiset(); resultsFound--; } } else { // If we're at the last pattern and we've found a match then we can halt halt = true; // Generate the final output and return it if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { // Disjoint so do a Product results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { // Normal Join results = context.InputMultiset.Join(context.OutputMultiset); } // If not reached required number of results continue if (results.Count >= _requiredResults && _requiredResults != -1) { context.OutputMultiset = results; return(context.OutputMultiset); } } context.InputMultiset = results; } else if (temp.PatternType == TriplePatternType.Filter) { IFilterPattern filter = (IFilterPattern)temp; ISparqlExpression filterExpr = filter.Filter.Expression; if (filter.Variables.IsDisjoint(context.InputMultiset.Variables)) { // Filter is Disjoint so determine whether it has any affect or not if (filter.Variables.Any()) { // Has Variables but disjoint from input => not in scope so gets ignored // Do we recurse or not? if (pattern < _triplePatterns.Count - 1) { // Recurse and return results = StreamingEvaluate(context, pattern + 1, out halt); return(results); } else { // We don't affect the input in any way so just return it return(context.InputMultiset); } } else { // No Variables so have to evaluate it to see if it gives true otherwise try { if (filterExpr.Evaluate(context, 0).AsSafeBoolean()) { if (pattern < _triplePatterns.Count - 1) { // Recurse and return results = StreamingEvaluate(context, pattern + 1, out halt); return(results); } else { // Last Pattern and we evaluate to true so can return the input as-is halt = true; return(context.InputMultiset); } } } catch (RdfQueryException) { // Evaluates to false so eliminates all solutions (use an empty Multiset) return(new Multiset()); } } } else { // Test each solution found so far against the Filter and eliminate those that evalute to false/error foreach (int id in context.InputMultiset.SetIDs.ToList()) { try { if (filterExpr.Evaluate(context, id).AsSafeBoolean()) { // If evaluates to true then add to output context.OutputMultiset.Add(context.InputMultiset[id].Copy()); } } catch (RdfQueryException) { // Error means we ignore the solution } } // Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); // Decide whether to recurse or not resultsFound = context.OutputMultiset.Count; if (pattern < _triplePatterns.Count - 1) { // Recurse then return // We can never decide whether to recurse again at this point as we are not capable of deciding // which solutions should be dumped (that is the job of an earlier pattern in the BGP) results = StreamingEvaluate(context, pattern + 1, out halt); return(results); } else { halt = true; // However many results we need we'll halt - previous patterns can call us again if they find more potential solutions // for us to filter return(context.OutputMultiset); } } } else if (temp is BindPattern) { BindPattern bind = (BindPattern)temp; ISparqlExpression bindExpr = bind.AssignExpression; String bindVar = bind.VariableName; if (context.InputMultiset.ContainsVariable(bindVar)) { throw new RdfQueryException( "Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query"); } else { // Compute the Binding for every value context.OutputMultiset.AddVariable(bindVar); foreach (ISet s in context.InputMultiset.Sets) { ISet x = s.Copy(); try { INode val = bindExpr.Evaluate(context, s.ID); x.Add(bindVar, val); } catch (RdfQueryException) { // Equivalent to no assignment but the solution is preserved } context.OutputMultiset.Add(x.Copy()); } // Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); // Decide whether to recurse or not resultsFound = context.OutputMultiset.Count; if (pattern < _triplePatterns.Count - 1) { // Recurse then return results = StreamingEvaluate(context, pattern + 1, out halt); return(results); } else { halt = true; // However many results we need we'll halt - previous patterns can call us again if they find more potential solutions // for us to extend return(context.OutputMultiset); } } } else { throw new RdfQueryException("Encountered a " + temp.GetType().FullName + " which is not a lazily evaluable Pattern"); } // If we found no possibles we return the null multiset if (resultsFound == 0) { return(new NullMultiset()); } else { // Remember to check for Timeouts during Lazy Evaluation context.CheckTimeout(); // Generate the final output and return it if (!modifies) { if (context.InputMultiset.IsDisjointWith(context.OutputMultiset)) { // Disjoint so do a Product results = context.InputMultiset.ProductWithTimeout(context.OutputMultiset, context.RemainingTimeout); } else { // Normal Join results = context.InputMultiset.Join(context.OutputMultiset); } context.OutputMultiset = results; } return(context.OutputMultiset); } }
/// <summary> /// Calculates the Numeric Value of this Expression as evaluated for a given Binding. /// </summary> /// <param name="context">Evaluation Context.</param> /// <param name="bindingID">Binding ID.</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode a = _expr.Evaluate(context, bindingID); if (a == null) { throw new RdfQueryException("Cannot apply unary minus to a null"); } switch (a.NumericType) { case SparqlNumericType.Integer: return(new LongNode(null, -1 * a.AsInteger())); case SparqlNumericType.Decimal: decimal decvalue = a.AsDecimal(); if (decvalue == Decimal.Zero) { return(new DecimalNode(null, Decimal.Zero)); } else { return(new DecimalNode(null, -1 * decvalue)); } case SparqlNumericType.Float: float fltvalue = a.AsFloat(); if (Single.IsNaN(fltvalue)) { return(new FloatNode(null, Single.NaN)); } else if (Single.IsPositiveInfinity(fltvalue)) { return(new FloatNode(null, Single.NegativeInfinity)); } else if (Single.IsNegativeInfinity(fltvalue)) { return(new FloatNode(null, Single.PositiveInfinity)); } else { return(new FloatNode(null, -1.0f * fltvalue)); } case SparqlNumericType.Double: double dblvalue = a.AsDouble(); if (Double.IsNaN(dblvalue)) { return(new DoubleNode(null, Double.NaN)); } else if (Double.IsPositiveInfinity(dblvalue)) { return(new DoubleNode(null, Double.NegativeInfinity)); } else if (Double.IsNegativeInfinity(dblvalue)) { return(new DoubleNode(null, Double.PositiveInfinity)); } else { return(new DoubleNode(null, -1.0 * dblvalue)); } default: throw new RdfQueryException("Cannot evalute an Arithmetic Expression when the Numeric Type of the expression cannot be determined"); } }
/// <summary> /// Gets the value of casting the result of the inner expression /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="bindingID">Binding ID</param> /// <returns></returns> public abstract IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID);
/// <summary> /// Casts the value of the inner Expression to an Integer. /// </summary> /// <param name="context">Evaluation Context.</param> /// <param name="bindingID">Binding ID.</param> /// <returns></returns> public override IValuedNode Evaluate(SparqlEvaluationContext context, int bindingID) { IValuedNode n = _expr.Evaluate(context, bindingID);//.CoerceToInteger(); if (n == null) { throw new RdfQueryException("Cannot cast a Null to a xsd:integer"); } ////New method should be much faster // if (n is LongNode) return n; // return new LongNode(null, n.AsInteger()); switch (n.NodeType) { case NodeType.Blank: case NodeType.GraphLiteral: case NodeType.Uri: throw new RdfQueryException("Cannot cast a Blank/URI/Graph Literal Node to a xsd:integer"); case NodeType.Literal: // See if the value can be cast if (n is LongNode) { return(n); } ILiteralNode lit = (ILiteralNode)n; if (lit.DataType != null) { string dt = lit.DataType.AbsoluteUri; if (SparqlSpecsHelper.IntegerDataTypes.Contains(dt)) { // Already a integer type so valid as a xsd:integer long i; if (Int64.TryParse(lit.Value, out i)) { return(new LongNode(lit.Graph, i)); } else { throw new RdfQueryException("Invalid lexical form for xsd:integer"); } } else if (dt.Equals(XmlSpecsHelper.XmlSchemaDataTypeDateTime)) { // DateTime cast forbidden throw new RdfQueryException("Cannot cast a xsd:dateTime to a xsd:integer"); } else { Int64 i; if (Int64.TryParse(lit.Value, out i)) { // Parsed OK return(new LongNode(lit.Graph, i)); } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:integer"); } } } else { Int64 i; if (Int64.TryParse(lit.Value, out i)) { // Parsed OK return(new LongNode(lit.Graph, i)); } else { throw new RdfQueryException("Cannot cast the value '" + lit.Value + "' to a xsd:integer"); } } default: throw new RdfQueryException("Cannot cast an Unknown Node to a xsd:integer"); } }