/// <summary> /// Evaluates the Graph Clause by setting up the dataset, applying the pattern and then generating additional bindings if necessary. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { // Q: Can we optimise GRAPH when the input is the Null Multiset to just return the Null Multiset? bool datasetOk = false; try { List <String> activeGraphs = new List <string>(); // Get the URIs of Graphs that should be evaluated over if (_graphSpecifier.TokenType != Token.VARIABLE) { switch (_graphSpecifier.TokenType) { case Token.URI: case Token.QNAME: Uri activeGraphUri = UriFactory.Create(Tools.ResolveUriOrQName(_graphSpecifier, context.Query.NamespaceMap, context.Query.BaseUri)); if (context.Data.HasGraph(activeGraphUri)) { // If the Graph is explicitly specified and there are FROM/FROM NAMED present then the Graph // URI must be in the graphs specified by a FROM/FROM NAMED or the result is null if (context.Query == null || ((!context.Query.DefaultGraphs.Any() && !context.Query.NamedGraphs.Any()) || context.Query.NamedGraphs.Any(u => EqualityHelper.AreUrisEqual(activeGraphUri, u))) ) { // Either there was no Query // OR there were no Default/Named Graphs (hence any Graph URI is permitted) // OR the specified URI was a Named Graph URI // In any case we can go ahead and set the active Graph activeGraphs.Add(activeGraphUri.AbsoluteUri); } else { // The specified URI was not present in the Named Graphs so return null context.OutputMultiset = new NullMultiset(); return(context.OutputMultiset); } } else { // If specifies a specific Graph and not in the Dataset result is a null multiset context.OutputMultiset = new NullMultiset(); return(context.OutputMultiset); } break; default: throw new RdfQueryException("Cannot use a '" + _graphSpecifier.GetType().ToString() + "' Token to specify the Graph for a GRAPH clause"); } } else { String gvar = _graphSpecifier.Value.Substring(1); // Watch out for the case in which the Graph Variable is not bound for all Sets in which case // we still need to operate over all Graphs if (context.InputMultiset.ContainsVariable(gvar) && context.InputMultiset.Sets.All(s => s[gvar] != null)) { // If there are already values bound to the Graph variable for all Input Solutions then we limit the Query to those Graphs List <Uri> graphUris = new List <Uri>(); foreach (ISet s in context.InputMultiset.Sets) { INode temp = s[gvar]; if (temp == null) { continue; } if (temp.NodeType != NodeType.Uri) { continue; } activeGraphs.Add(temp.ToString()); graphUris.Add(((IUriNode)temp).Uri); } } else { // Nothing yet bound to the Graph Variable so the Query is over all the named Graphs if (context.Query != null && context.Query.NamedGraphs.Any()) { // Query specifies one/more named Graphs activeGraphs.AddRange(context.Query.NamedGraphs.Select(u => u.AbsoluteUri)); } else if (context.Query != null && context.Query.DefaultGraphs.Any() && !context.Query.NamedGraphs.Any()) { // Gives null since the query dataset does not include any named graphs context.OutputMultiset = new NullMultiset(); return(context.OutputMultiset); } else { // Query is over entire dataset/default Graph since no named Graphs are explicitly specified activeGraphs.AddRange(context.Data.GraphUris.Select(u => u.ToSafeString())); } } } // Remove all duplicates from Active Graphs to avoid duplicate results activeGraphs = activeGraphs.Distinct().ToList(); // Evaluate the inner pattern BaseMultiset initialInput = context.InputMultiset; BaseMultiset finalResult = new Multiset(); // Evalute for each Graph URI and union the results foreach (String uri in activeGraphs) { // Always use the same Input for each Graph URI and set that Graph to be the Active Graph // Be sure to translate String.Empty back to the null URI to select the default graph // correctly context.InputMultiset = initialInput; Uri currGraphUri = (uri.Equals(String.Empty)) ? null : UriFactory.Create(uri); // Set Active Graph if (currGraphUri == null) { // GRAPH operates over named graphs only so default graph gets skipped continue; } // The result of the HasGraph() call is ignored we just make it so datasets with any kind of // load on demand behaviour work properly context.Data.HasGraph(currGraphUri); // All we actually care about is setting the active graph context.Data.SetActiveGraph(currGraphUri); datasetOk = true; // Evaluate for the current Active Graph BaseMultiset result = context.Evaluate(_pattern); // Merge the Results into our overall Results if (result is NullMultiset) { // Don't do anything, adds nothing to the results } else if (result is IdentityMultiset) { // Adds a single row to the results if (_graphSpecifier.TokenType == Token.VARIABLE) { // Include graph variable if not yet bound INode currGraph = new UriNode(null, currGraphUri); Set s = new Set(); s.Add(_graphSpecifier.Value.Substring(1), currGraph); finalResult.Add(s); } else { finalResult.Add(new Set()); } } else { // If the Graph Specifier is a Variable then we must either bind the // variable or eliminate solutions which have an incorrect value for it if (_graphSpecifier.TokenType == Token.VARIABLE) { String gvar = _graphSpecifier.Value.Substring(1); INode currGraph = new UriNode(null, currGraphUri); foreach (int id in result.SetIDs.ToList()) { ISet s = result[id]; if (s[gvar] == null) { // If Graph Variable is not yet bound for solution bind it s.Add(gvar, currGraph); } else if (!s[gvar].Equals(currGraph)) { // If Graph Variable is bound for solution and doesn't match // current Graph then we have to remove the solution result.Remove(id); } } } // Union solutions into the Results finalResult.Union(result); } // Reset the Active Graph after each pass context.Data.ResetActiveGraph(); datasetOk = false; } // Return the final result if (finalResult.IsEmpty) { finalResult = new NullMultiset(); } context.OutputMultiset = finalResult; } finally { if (datasetOk) { context.Data.ResetActiveGraph(); } } return(context.OutputMultiset); }
/// <summary> /// Gets whether the given URI represents the default graph of the dataset /// </summary> /// <param name="graphUri">Graph URI</param> /// <returns></returns> protected bool IsDefaultGraph(Uri graphUri) { return(EqualityHelper.AreUrisEqual(graphUri, this._defaultGraphUri)); }
/// <summary> /// Evaluates the Graph Clause by setting up the dataset, applying the pattern and then generating additional bindings if necessary /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset result; //Q: Can we optimise GRAPH when the input is the Null Multiset to just return the Null Multiset? if (this._pattern is Bgp && ((Bgp)this._pattern).IsEmpty) { //Optimise the case where we have GRAPH ?g {} by not setting the Graph and just returning //a Null Multiset result = new NullMultiset(); } else { bool datasetOk = false; try { List <String> activeGraphs = new List <string>(); //Get the URIs of Graphs that should be evaluated over if (this._graphSpecifier.TokenType != Token.VARIABLE) { switch (this._graphSpecifier.TokenType) { case Token.URI: case Token.QNAME: Uri activeGraphUri = new Uri(Tools.ResolveUriOrQName(this._graphSpecifier, context.Query.NamespaceMap, context.Query.BaseUri)); if (context.Data.HasGraph(activeGraphUri)) { //If the Graph is explicitly specified and there are FROM NAMED present then the Graph //URI must be in the graphs specified by a FROM NAMED or the result is null if (context.Query != null && ((!context.Query.DefaultGraphs.Any() && !context.Query.NamedGraphs.Any()) || context.Query.DefaultGraphs.Any(u => EqualityHelper.AreUrisEqual(activeGraphUri, u)) || context.Query.NamedGraphs.Any(u => EqualityHelper.AreUrisEqual(activeGraphUri, u))) ) { //Either there was no Query OR there were no Default/Named Graphs OR //the specified URI was either a Default/Named Graph URI //In any case we can go ahead and set the active Graph activeGraphs.Add(activeGraphUri.ToString()); } else { //The specified URI was not present in the Default/Named Graphs so return null context.OutputMultiset = new NullMultiset(); return(context.OutputMultiset); } } else { //If specifies a specific Graph and not in the Dataset result is a null multiset context.OutputMultiset = new NullMultiset(); return(context.OutputMultiset); } break; default: throw new RdfQueryException("Cannot use a '" + this._graphSpecifier.GetType().ToString() + "' Token to specify the Graph for a GRAPH clause"); } } else { String gvar = this._graphSpecifier.Value.Substring(1); //Watch out for the case in which the Graph Variable is not bound for all Sets in which case //we still need to operate over all Graphs if (context.InputMultiset.ContainsVariable(gvar) && context.InputMultiset.Sets.All(s => s[gvar] != null)) { //If there are already values bound to the Graph variable for all Input Solutions then we limit the Query to those Graphs List <Uri> graphUris = new List <Uri>(); foreach (ISet s in context.InputMultiset.Sets) { INode temp = s[gvar]; if (temp != null) { if (temp.NodeType == NodeType.Uri) { activeGraphs.Add(temp.ToString()); graphUris.Add(((IUriNode)temp).Uri); } } } } else { //Nothing yet bound to the Graph Variable so the Query is over all the named Graphs if (context.Query != null && context.Query.NamedGraphs.Any()) { //Query specifies one/more named Graphs activeGraphs.AddRange(context.Query.NamedGraphs.Select(u => u.ToString())); } else { //Query is over entire dataset/default Graph since no named Graphs are explicitly specified activeGraphs.AddRange(context.Data.GraphUris.Select(u => u.ToSafeString())); } } } //Remove all duplicates from Active Graphs to avoid duplicate results activeGraphs = activeGraphs.Distinct().ToList(); //Evaluate the inner pattern BaseMultiset initialInput = context.InputMultiset; BaseMultiset finalResult = new Multiset(); //Evalute for each Graph URI and union the results foreach (String uri in activeGraphs) { //Always use the same Input for each Graph URI and set that Graph to be the Active Graph //Be sure to translate String.Empty back to the null URI to select the default graph //correctly context.InputMultiset = initialInput; Uri currGraphUri = (uri.Equals(String.Empty)) ? null : new Uri(uri); //This bit of logic takes care of the fact that calling SetActiveGraph((Uri)null) resets the //Active Graph to be the default graph which if the default graph is null is usually the Union of //all Graphs in the Store if (currGraphUri == null && context.Data.DefaultGraph == null && context.Data.UsesUnionDefaultGraph) { if (context.Data.HasGraph(null)) { context.Data.SetActiveGraph(context.Data[null]); } else { continue; } } else { context.Data.SetActiveGraph(currGraphUri); } datasetOk = true; //Evaluate for the current Active Graph result = context.Evaluate(this._pattern); //Merge the Results into our overall Results if (result is NullMultiset || result is IdentityMultiset) { //Don't do anything } else { //If the Graph Specifier is a Variable then we must either bind the //variable or eliminate solutions which have an incorrect value for it if (this._graphSpecifier.TokenType == Token.VARIABLE) { String gvar = this._graphSpecifier.Value.Substring(1); INode currGraph = (currGraphUri == null) ? null : new UriNode(null, currGraphUri); foreach (int id in result.SetIDs.ToList()) { ISet s = result[id]; if (s[gvar] == null) { //If Graph Variable is not yet bound for solution bind it s.Add(gvar, currGraph); } else if (!s[gvar].Equals(currGraph)) { //If Graph Variable is bound for solution and doesn't match //current Graph then we have to remove the solution result.Remove(id); } } } //Union solutions into the Results finalResult.Union(result); } //Reset the Active Graph after each pass context.Data.ResetActiveGraph(); datasetOk = false; } //Return the final result if (finalResult.IsEmpty) { finalResult = new NullMultiset(); } context.OutputMultiset = finalResult; } finally { if (datasetOk) { context.Data.ResetActiveGraph(); } } } return(context.OutputMultiset); }
/// <summary> /// Evaluates the Command in the given Context /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlUpdateEvaluationContext context) { try { //If Source and Destination are same this is a no-op if (EqualityHelper.AreUrisEqual(this._sourceUri, this._destUri)) { return; } if (context.Data.HasGraph(this._sourceUri)) { //Get the Source Graph IGraph source = context.Data.GetModifiableGraph(this._sourceUri); //Create/Delete/Clear the Destination Graph IGraph dest; if (context.Data.HasGraph(this._destUri)) { if (this._destUri == null) { dest = context.Data.GetModifiableGraph(this._destUri); dest.Clear(); } else { context.Data.RemoveGraph(this._destUri); dest = new Graph(); dest.BaseUri = this._destUri; context.Data.AddGraph(dest); dest = context.Data.GetModifiableGraph(this._destUri); } } else { dest = new Graph(); dest.BaseUri = this._destUri; context.Data.AddGraph(dest); } //Move data from the Source into the Destination dest.Merge(source); //Delete/Clear the Source Graph if (this._sourceUri == null) { source.Clear(); } else { context.Data.RemoveGraph(this._sourceUri); } } else { //Only show error if not Silent if (!this._silent) { if (this._sourceUri != null) { throw new SparqlUpdateException("Cannot MOVE from Graph <" + this._sourceUri.AbsoluteUri + "> as it does not exist"); } else { //This would imply a more fundamental issue with the Dataset not understanding that null means default graph throw new SparqlUpdateException("Cannot MOVE from the Default Graph as it does not exist"); } } } } catch { //If not silent throw the exception upwards if (!this._silent) { throw; } } }
/// <summary> /// Constructs a Full Text Match property function. /// </summary> /// <param name="info">Property Function information.</param> public FullTextMatchPropertyFunction(PropertyFunctionInfo info) { if (info == null) { throw new ArgumentNullException("info"); } if (!EqualityHelper.AreUrisEqual(info.FunctionUri, this.FunctionUri)) { throw new ArgumentException("Property Function information is not valid for this function"); } //Get basic arguments this._matchVar = info.SubjectArgs[0]; if (this._matchVar.VariableName != null) { this._vars.Add(this._matchVar.VariableName); } if (info.SubjectArgs.Count == 2) { this._scoreVar = info.SubjectArgs[1]; if (this._scoreVar.VariableName != null) { this._vars.Add(this._scoreVar.VariableName); } } //Check extended arguments this._searchVar = info.ObjectArgs[0]; if (this._searchVar.VariableName != null) { this._vars.Add(this._searchVar.VariableName); } switch (info.ObjectArgs.Count) { case 1: break; case 2: PatternItem arg = info.ObjectArgs[1]; if (arg.VariableName != null) { throw new RdfQueryException("Cannot use a variable as the limit/score threshold for full text queries, must use a numeric constant"); } IValuedNode n = ((NodeMatchPattern)arg).Node.AsValuedNode(); switch (n.NumericType) { case SparqlNumericType.Integer: this._limit = (int)n.AsInteger(); break; case SparqlNumericType.Decimal: case SparqlNumericType.Double: case SparqlNumericType.Float: this._threshold = n.AsDouble(); break; default: throw new RdfQueryException("Cannot use a non-numeric constant as the limit/score threshold for full text queries, must use a numeric constant"); } break; case 3: default: PatternItem arg1 = info.ObjectArgs[1]; PatternItem arg2 = info.ObjectArgs[2]; if (arg1.VariableName != null || arg2.VariableName != null) { throw new RdfQueryException("Cannot use a variable as the limit/score threshold for full text queries, must use a numeric constant"); } IValuedNode n1 = ((NodeMatchPattern)arg1).Node.AsValuedNode(); switch (n1.NumericType) { case SparqlNumericType.NaN: throw new RdfQueryException("Cannot use a non-numeric constant as the score threshold for full text queries, must use a numeric constant"); default: this._threshold = n1.AsDouble(); break; } IValuedNode n2 = ((NodeMatchPattern)arg2).Node.AsValuedNode(); switch (n2.NumericType) { case SparqlNumericType.NaN: throw new RdfQueryException("Cannot use a non-numeric constant as the limit for full text queries, must use a numeric constant"); default: this._limit = (int)n2.AsInteger(); break; } break; } }