/// <summary> /// Constructs a Node based on this Pattern for the given Set /// </summary> /// <param name="context">Construct Context</param> /// <returns></returns> protected internal abstract INode Construct(ConstructContext context);
/// <summary> /// Evaluates the Command in the given Context /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlUpdateEvaluationContext context) { //Split the Pattern into the set of Graph Patterns List<GraphPattern> patterns = new List<GraphPattern>(); if (this._pattern.IsGraph) { patterns.Add(this._pattern); } else if (this._pattern.TriplePatterns.Count > 0 || this._pattern.HasChildGraphPatterns) { if (this._pattern.TriplePatterns.Count > 0) { patterns.Add(new GraphPattern()); this._pattern.TriplePatterns.ForEach(tp => patterns[0].AddTriplePattern(tp)); } this._pattern.ChildGraphPatterns.ForEach(gp => patterns.Add(gp)); } else { //If no Triple Patterns and No Child Graph Patterns nothing to do return; } foreach (GraphPattern pattern in patterns) { if (!this.IsValidDataPattern(pattern, false)) throw new SparqlUpdateException("Cannot evaluate a INSERT DATA command where any of the Triple Patterns are not concrete triples (variables are not permitted) or any of the GRAPH clauses have nested Graph Patterns"); //Get the Target Graph IGraph target; Uri graphUri; if (pattern.IsGraph) { switch (pattern.GraphSpecifier.TokenType) { case Token.QNAME: throw new NotSupportedException("Graph Specifiers as QNames for INSERT DATA Commands are not supported - please specify an absolute URI instead"); case Token.URI: graphUri = UriFactory.Create(pattern.GraphSpecifier.Value); break; default: throw new SparqlUpdateException("Cannot evaluate an INSERT DATA Command as the Graph Specifier is not a QName/URI"); } } else { graphUri = null; } if (context.Data.HasGraph(graphUri)) { target = context.Data.GetModifiableGraph(graphUri); } else { //If the Graph does not exist then it must be created target = new Graph(); target.BaseUri = graphUri; context.Data.AddGraph(target); } //Insert the actual Triples INode subj, pred, obj; ConstructContext constructContext = new ConstructContext(target, null, true); foreach (IConstructTriplePattern p in pattern.TriplePatterns.OfType<IConstructTriplePattern>()) { subj = p.Subject.Construct(constructContext); pred = p.Predicate.Construct(constructContext); obj = p.Object.Construct(constructContext); target.Assert(new Triple(subj, pred, obj)); } } }
/// <summary> /// Constructs a Node based on the given Set /// </summary> /// <param name="context">Construct Context</param> protected internal override INode Construct(ConstructContext context) { return context.GetNode(this._node); }
/// <summary> /// Evaluates the Command in the given Context /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlUpdateEvaluationContext context) { bool defGraphOk = false; bool datasetOk = false; try { //First evaluate the WHERE pattern to get the affected bindings ISparqlAlgebra where = this._wherePattern.ToAlgebra(); if (context.Commands != null) { where = context.Commands.ApplyAlgebraOptimisers(where); } //Set Active Graph for the WHERE based upon the WITH clause //Don't bother if there are USING URIs as these would override any Active Graph we set here //so we can save ourselves the effort of doing this if (!this.UsingUris.Any()) { if (this._graphUri != null) { context.Data.SetActiveGraph(this._graphUri); defGraphOk = true; } else { context.Data.SetActiveGraph((Uri)null); defGraphOk = true; } } //We need to make a dummy SparqlQuery object since if the Command has used any //USING/USING NAMEDs along with GRAPH clauses then the algebra needs to have the //URIs available to it which it gets from the Query property of the Context //object SparqlQuery query = new SparqlQuery(); foreach (Uri u in this.UsingUris) { query.AddDefaultGraph(u); } foreach (Uri u in this.UsingNamedUris) { query.AddNamedGraph(u); } SparqlEvaluationContext queryContext = new SparqlEvaluationContext(query, context.Data, context.QueryProcessor); if (this.UsingUris.Any()) { //If there are USING URIs set the Active Graph to be formed of the Graphs with those URIs context.Data.SetActiveGraph(this._usingUris); datasetOk = true; } BaseMultiset results = queryContext.Evaluate(where); if (this.UsingUris.Any()) { //If there are USING URIs reset the Active Graph afterwards //Also flag the dataset as no longer being OK as this flag is used in the finally //block to determine whether the Active Graph needs resetting which it may do if the //evaluation of the context.Data.ResetActiveGraph(); datasetOk = false; } //Reset Active Graph for the WHERE if (defGraphOk) { context.Data.ResetActiveGraph(); defGraphOk = false; } //Get the Graph from which we are deleting IGraph g = context.Data.GetModifiableGraph(this._graphUri); //Delete the Triples for each Solution foreach (ISet s in queryContext.OutputMultiset.Sets) { List<Triple> deletedTriples = new List<Triple>(); //Triples from raw Triple Patterns try { ConstructContext constructContext = new ConstructContext(g, s, true); foreach (IConstructTriplePattern p in this._deletePattern.TriplePatterns.OfType<IConstructTriplePattern>()) { try { deletedTriples.Add(p.Construct(constructContext)); } catch (RdfQueryException) { //If we get an error here then we couldn't construct a specific Triple //so we continue anyway } } g.Retract(deletedTriples); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct for this solution so the //solution is ignored this graph } //Triples from GRAPH clauses foreach (GraphPattern gp in this._deletePattern.ChildGraphPatterns) { deletedTriples.Clear(); try { String graphUri; switch (gp.GraphSpecifier.TokenType) { case Token.URI: graphUri = gp.GraphSpecifier.Value; break; case Token.VARIABLE: if (s.ContainsVariable(gp.GraphSpecifier.Value)) { INode temp = s[gp.GraphSpecifier.Value.Substring(1)]; if (temp == null) { //If the Variable is not bound then skip continue; } else if (temp.NodeType == NodeType.Uri) { graphUri = temp.ToSafeString(); } else { //If the Variable is not bound to a URI then skip continue; } } else { //If the Variable is not bound for this solution then skip continue; } break; default: //Any other Graph Specifier we have to ignore this solution continue; } //If the Dataset doesn't contain the Graph then no need to do the Deletions if (!context.Data.HasGraph(UriFactory.Create(graphUri))) continue; //Do the actual Deletions IGraph h = context.Data.GetModifiableGraph(UriFactory.Create(graphUri)); ConstructContext constructContext = new ConstructContext(h, s, true); foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType<IConstructTriplePattern>()) { try { deletedTriples.Add(p.Construct(constructContext)); } catch (RdfQueryException) { //If we get an error here then we couldn't construct a specific //triple so we continue anyway } } h.Retract(deletedTriples); } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //solution is ignored for this graph } } } } finally { //If the Dataset was set and an error occurred in doing the WHERE clause then //we'll need to Reset the Active Graph if (datasetOk) context.Data.ResetActiveGraph(); if (defGraphOk) context.Data.ResetActiveGraph(); } }
/// <summary> /// Constructs a Triple from a Set based on this Triple Pattern /// </summary> /// <param name="context">Construct Context</param> /// <returns></returns> public Triple Construct(ConstructContext context) { return new Triple(Tools.CopyNode(this._subj.Construct(context), context.Graph), Tools.CopyNode(this._pred.Construct(context), context.Graph), Tools.CopyNode(this._obj.Construct(context), context.Graph)); }
/// <summary> /// Constructs a Node based on the given Set /// </summary> /// <param name="context">Construct Context</param> /// <returns>The Node which is bound to this Variable in this Solution</returns> protected internal override INode Construct(ConstructContext context) { INode value = context.Set[this._varname]; if (value == null) throw new RdfQueryException("Unable to construct a Value for this Variable for this solution as it is bound to a null"); switch (value.NodeType) { case NodeType.Blank: if (!context.PreserveBlankNodes && value.GraphUri != null) { //Rename Blank Node based on the Graph Uri Hash Code int hash = value.GraphUri.GetEnhancedHashCode(); if (hash >= 0) { return new BlankNode(context.Graph, ((IBlankNode)value).InternalID + "-" + value.GraphUri.GetEnhancedHashCode()); } else { return new BlankNode(context.Graph, ((IBlankNode)value).InternalID + hash); } } else { return new BlankNode(context.Graph, ((IBlankNode)value).InternalID); } default: return context.GetNode(value); } }
/// <summary> /// Processes a DELETE DATA command /// </summary> /// <param name="cmd">DELETE Data Command</param> public void ProcessDeleteDataCommand(DeleteDataCommand cmd) { if (this._manager is IUpdateableGenericIOManager) { ((IUpdateableGenericIOManager)this._manager).Update(cmd.ToString()); } else { //Check IO Behaviour //For a delete we either need the ability to Update Delete Triples or to Overwrite Graphs //Firstly check behaviour persuant to default graph if applicable if (cmd.DataPattern.TriplePatterns.OfType<IConstructTriplePattern>().Any()) { //Must support notion of default graph if ((this._manager.IOBehaviour & IOBehaviour.HasDefaultGraph) == 0) throw new SparqlUpdateException("The underlying store does not support the notion of an explicit unnamed Default Graph required to process this command"); //Must allow either OverwriteDefault or CanUpdateDeleteTriples if ((this._manager.IOBehaviour & IOBehaviour.CanUpdateDeleteTriples) == 0 && (this._manager.IOBehaviour & IOBehaviour.OverwriteDefault) == 0) throw new SparqlUpdateException("The underlying store does not support the required IO Behaviour to implement this command"); } //Then check behaviour persuant to named graphs if applicable if (cmd.DataPattern.HasChildGraphPatterns) { //Must support named graphs if ((this._manager.IOBehaviour & IOBehaviour.HasNamedGraphs) == 0) throw new SparqlUpdateException("The underlying store does not support the notion of named graphs required to process this command"); //Must allow either CanUpdateDeleteTriples or OverwriteNamed if ((this._manager.IOBehaviour & IOBehaviour.CanUpdateDeleteTriples) == 0 && (this._manager.IOBehaviour & IOBehaviour.OverwriteNamed) == 0) throw new SparqlUpdateException("The underlying store does not support the required IO Behaviour to implement this command"); } //Split the Pattern into the set of Graph Patterns List<GraphPattern> patterns = new List<GraphPattern>(); if (cmd.DataPattern.IsGraph) { patterns.Add(cmd.DataPattern); } else if (cmd.DataPattern.TriplePatterns.Count > 0 || cmd.DataPattern.HasChildGraphPatterns) { if (cmd.DataPattern.TriplePatterns.Count > 0) { patterns.Add(new GraphPattern()); cmd.DataPattern.TriplePatterns.ForEach(tp => patterns[0].AddTriplePattern(tp)); } cmd.DataPattern.ChildGraphPatterns.ForEach(gp => patterns.Add(gp)); } else { //If no Triple Patterns and No Child Graph Patterns nothing to do return; } foreach (GraphPattern pattern in patterns) { if (!this.IsValidDataPattern(pattern, false)) throw new SparqlUpdateException("Cannot evaluate a DELETE DATA command where any of the Triple Patterns are not concrete triples - variables are not permitted"); Uri graphUri = null; if (pattern.IsGraph) { switch (pattern.GraphSpecifier.TokenType) { case Token.QNAME: throw new NotSupportedException("Graph Specifiers as QNames for DELETE DATA Commands are not supported - please specify an absolute URI instead"); case Token.URI: graphUri = UriFactory.Create(pattern.GraphSpecifier.Value); break; default: throw new SparqlUpdateException("Cannot evaluate an DELETE DATA Command as the Graph Specifier is not a QName/URI"); } } Graph g = new Graph(); if (!this._manager.UpdateSupported) { //If the Graph to be deleted from is empty then can skip as will have no affect on the Graph this._manager.LoadGraph(g, graphUri); if (g.IsEmpty) continue; } //Note that if the Manager supports Triple Level updates we won't load the Graph //so we can't know whether it is empty or not and so can't skip the delete step //Delete the actual Triples INode subj, pred, obj; ConstructContext context = new ConstructContext(g, null, true); foreach (IConstructTriplePattern p in pattern.TriplePatterns.OfType<IConstructTriplePattern>()) { subj = p.Subject.Construct(context); pred = p.Predicate.Construct(context); obj = p.Object.Construct(context); if (!this._manager.UpdateSupported) { //If we don't support update then we'll have loaded the existing graph //so we'll use this to remove the relevant triples to get to the intended state of //the graph g.Retract(new Triple(subj, pred, obj)); } else { //If we do support update then we'll have an empty graph which we'll use to store //up the set of triples to be removed g.Assert(new Triple(subj, pred, obj)); } } if (this._manager.UpdateSupported) { this._manager.UpdateGraph(graphUri, Enumerable.Empty<Triple>(), g.Triples); } else { this._manager.SaveGraph(g); } } } }
/// <summary> /// Processes an INSERT command /// </summary> /// <param name="cmd">Insert Command</param> /// <remarks> /// <para> /// <strong>Note:</strong> The underlying manager must implement the <see cref="IQueryableGenericIOManager">IQueryableGenericIOManager</see> interface in order for INSERT commands to be processed /// </para> /// </remarks> public void ProcessInsertCommand(InsertCommand cmd) { if (this._manager is IUpdateableGenericIOManager) { ((IUpdateableGenericIOManager)this._manager).Update(cmd.ToString()); } else { if (this._manager is IQueryableGenericIOManager) { //Check IO Behaviour //For a insert we either need the ability to Update Add Triples or to Overwrite Graphs //Firstly check behaviour persuant to default graph if applicable if (cmd.InsertPattern.TriplePatterns.OfType<IConstructTriplePattern>().Any()) { //Must support notion of default graph if ((this._manager.IOBehaviour & IOBehaviour.HasDefaultGraph) == 0) throw new SparqlUpdateException("The underlying store does not support the notion of an explicit unnamed Default Graph required to process this command"); //Must allow either OverwriteDefault or CanUpdateAddTriples if ((this._manager.IOBehaviour & IOBehaviour.CanUpdateAddTriples) == 0 && (this._manager.IOBehaviour & IOBehaviour.OverwriteDefault) == 0) throw new SparqlUpdateException("The underlying store does not support the required IO Behaviour to implement this command"); } //Then check behaviour persuant to named graphs if applicable if (cmd.InsertPattern.HasChildGraphPatterns) { //Must support named graphs if ((this._manager.IOBehaviour & IOBehaviour.HasNamedGraphs) == 0) throw new SparqlUpdateException("The underlying store does not support the notion of named graphs required to process this command"); //Must allow either CanUpdateAddTriples or OverwriteNamed if ((this._manager.IOBehaviour & IOBehaviour.CanUpdateAddTriples) == 0 && (this._manager.IOBehaviour & IOBehaviour.OverwriteNamed) == 0) throw new SparqlUpdateException("The underlying store does not support the required IO Behaviour to implement this command"); } //First build and make the query to get a Result Set String queryText = "SELECT * WHERE " + cmd.WherePattern.ToString(); SparqlQueryParser parser = new SparqlQueryParser(); SparqlQuery query = parser.ParseFromString(queryText); if (cmd.GraphUri != null && !cmd.UsingUris.Any()) query.AddDefaultGraph(cmd.GraphUri); foreach (Uri u in cmd.UsingUris) { query.AddDefaultGraph(u); } foreach (Uri u in cmd.UsingNamedUris) { query.AddNamedGraph(u); } Object results = ((IQueryableGenericIOManager)this._manager).Query(query.ToString()); if (results is SparqlResultSet) { //Now need to transform the Result Set back to a Multiset Multiset mset = new Multiset((SparqlResultSet)results); //Generate the Triples for each Solution List<Triple> insertedTriples = new List<Triple>(); Dictionary<String, List<Triple>> insertedGraphTriples = new Dictionary<string, List<Triple>>(); foreach (ISet s in mset.Sets) { List<Triple> tempInsertedTriples = new List<Triple>(); try { ConstructContext context = new ConstructContext(null, s, true); foreach (IConstructTriplePattern p in cmd.InsertPattern.TriplePatterns.OfType<IConstructTriplePattern>()) { try { tempInsertedTriples.Add(p.Construct(context)); } catch (RdfQueryException) { //If we get an error here then it means we couldn't construct a specific //triple so we continue anyway } } insertedTriples.AddRange(tempInsertedTriples); } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //solution is ignore for this graph } //Triples from GRAPH clauses foreach (GraphPattern gp in cmd.InsertPattern.ChildGraphPatterns) { tempInsertedTriples.Clear(); try { String graphUri; switch (gp.GraphSpecifier.TokenType) { case Token.URI: graphUri = gp.GraphSpecifier.Value; break; case Token.VARIABLE: if (s.ContainsVariable(gp.GraphSpecifier.Value)) { INode temp = s[gp.GraphSpecifier.Value.Substring(1)]; if (temp == null) { //If the Variable is not bound then skip continue; } else if (temp.NodeType == NodeType.Uri) { graphUri = temp.ToSafeString(); } else { //If the Variable is not bound to a URI then skip continue; } } else { //If the Variable is not bound for this solution then skip continue; } break; default: //Any other Graph Specifier we have to ignore this solution continue; } if (!insertedGraphTriples.ContainsKey(graphUri)) insertedGraphTriples.Add(graphUri, new List<Triple>()); ConstructContext context = new ConstructContext(null, s, true); foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType<IConstructTriplePattern>()) { try { tempInsertedTriples.Add(p.Construct(context)); } catch (RdfQueryException) { //If we get an error here then it means we couldn't construct a specific //triple so we continue anyway } } insertedGraphTriples[graphUri].AddRange(tempInsertedTriples); } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //solution is ignore for this graph } } } //Now decide how to apply the update if (this._manager.UpdateSupported) { this._manager.UpdateGraph(cmd.GraphUri, insertedTriples, Enumerable.Empty<Triple>()); foreach (KeyValuePair<String, List<Triple>> graphInsertion in insertedGraphTriples) { this._manager.UpdateGraph(graphInsertion.Key, graphInsertion.Value, Enumerable.Empty<Triple>()); } } else { Graph g = new Graph(); this._manager.LoadGraph(g, cmd.GraphUri); g.Assert(insertedTriples); this._manager.SaveGraph(g); foreach (KeyValuePair<String, List<Triple>> graphInsertion in insertedGraphTriples) { g = new Graph(); this._manager.LoadGraph(g, graphInsertion.Key); g.Assert(graphInsertion.Value); this._manager.SaveGraph(g); } } } else { throw new SparqlUpdateException("Cannot evaluate an INSERT Command as the underlying Store failed to answer the query for the WHERE portion of the command as expected"); } } else { throw new NotSupportedException("INSERT commands are not supported by this Update Processor as the manager for the underlying Store does not provide Query capabilities which are necessary to process this command"); } } }
/// <summary> /// Processes an INSERT DATA command /// </summary> /// <param name="cmd">Insert Data Command</param> public void ProcessInsertDataCommand(InsertDataCommand cmd) { if (this._manager is IUpdateableGenericIOManager) { ((IUpdateableGenericIOManager)this._manager).Update(cmd.ToString()); } else { //Check IO Behaviour //For a insert we either need the ability to Update Delete Triples or to Overwrite Graphs //Firstly check behaviour persuant to default graph if applicable if (cmd.DataPattern.TriplePatterns.OfType<IConstructTriplePattern>().Any()) { //Must support notion of default graph if ((this._manager.IOBehaviour & IOBehaviour.HasDefaultGraph) == 0) throw new SparqlUpdateException("The underlying store does not support the notion of an explicit unnamed Default Graph required to process this command"); //Must allow either OverwriteDefault or CanUpdateAddTriples if ((this._manager.IOBehaviour & IOBehaviour.CanUpdateAddTriples) == 0 && (this._manager.IOBehaviour & IOBehaviour.OverwriteDefault) == 0) throw new SparqlUpdateException("The underlying store does not support the required IO Behaviour to implement this command"); } //Then check behaviour persuant to named graphs if applicable if (cmd.DataPattern.HasChildGraphPatterns) { //Must support named graphs if ((this._manager.IOBehaviour & IOBehaviour.HasNamedGraphs) == 0) throw new SparqlUpdateException("The underlying store does not support the notion of named graphs required to process this command"); //Must allow either CanUpdateAddTriples or OverwriteNamed if ((this._manager.IOBehaviour & IOBehaviour.CanUpdateAddTriples) == 0 && (this._manager.IOBehaviour & IOBehaviour.OverwriteNamed) == 0) throw new SparqlUpdateException("The underlying store does not support the required IO Behaviour to implement this command"); } //Split the Pattern into the set of Graph Patterns List<GraphPattern> patterns = new List<GraphPattern>(); if (cmd.DataPattern.IsGraph) { patterns.Add(cmd.DataPattern); } else if (cmd.DataPattern.TriplePatterns.Count > 0 || cmd.DataPattern.HasChildGraphPatterns) { if (cmd.DataPattern.TriplePatterns.Count > 0) { patterns.Add(new GraphPattern()); cmd.DataPattern.TriplePatterns.ForEach(tp => patterns[0].AddTriplePattern(tp)); } cmd.DataPattern.ChildGraphPatterns.ForEach(gp => patterns.Add(gp)); } else { //If no Triple Patterns and No Child Graph Patterns nothing to do return; } foreach (GraphPattern pattern in patterns) { if (!this.IsValidDataPattern(pattern, false)) throw new SparqlUpdateException("Cannot evaluate an INSERT DATA command where any of the Triple Patterns are not concrete triples - variables are not permitted"); Uri graphUri = null; if (pattern.IsGraph) { switch (pattern.GraphSpecifier.TokenType) { case Token.QNAME: throw new NotSupportedException("Graph Specifiers as QNames for INSERT DATA Commands are not supported - please specify an absolute URI instead"); case Token.URI: graphUri = UriFactory.Create(pattern.GraphSpecifier.Value); break; default: throw new SparqlUpdateException("Cannot evaluate an INSERT DATA Command as the Graph Specifier is not a QName/URI"); } } Graph g = new Graph(); if (!this._manager.UpdateSupported) this._manager.LoadGraph(g, graphUri); //Insert the actual Triples INode subj, pred, obj; ConstructContext context = new ConstructContext(g, null, true); foreach (IConstructTriplePattern p in pattern.TriplePatterns.OfType<IConstructTriplePattern>()) { subj = p.Subject.Construct(context); pred = p.Predicate.Construct(context); obj = p.Object.Construct(context); g.Assert(new Triple(subj, pred, obj)); } if (this._manager.UpdateSupported) { this._manager.UpdateGraph(graphUri, g.Triples, Enumerable.Empty<Triple>()); } else { this._manager.SaveGraph(g); } } } }
/// <summary> /// Processes an INSERT/DELETE command /// </summary> /// <param name="cmd">Insert/Delete Command</param> public void ProcessModifyCommand(ModifyCommand cmd) { if (this._manager is IUpdateableGenericIOManager) { ((IUpdateableGenericIOManager)this._manager).Update(cmd.ToString()); } else { if (this._manager is IQueryableGenericIOManager) { //First build and make the query to get a Result Set String queryText = "SELECT * WHERE " + cmd.WherePattern.ToString(); SparqlQueryParser parser = new SparqlQueryParser(); SparqlQuery query = parser.ParseFromString(queryText); if (cmd.GraphUri != null && !cmd.UsingUris.Any()) query.AddDefaultGraph(cmd.GraphUri); foreach (Uri u in cmd.UsingUris) { query.AddDefaultGraph(u); } foreach (Uri u in cmd.UsingNamedUris) { query.AddNamedGraph(u); } Object results = ((IQueryableGenericIOManager)this._manager).Query(query.ToString()); if (results is SparqlResultSet) { //Now need to transform the Result Set back to a Multiset Multiset mset = new Multiset((SparqlResultSet)results); //Generate the Triples for each Solution List<Triple> deletedTriples = new List<Triple>(); Dictionary<String, List<Triple>> deletedGraphTriples = new Dictionary<string, List<Triple>>(); foreach (Set s in mset.Sets) { List<Triple> tempDeletedTriples = new List<Triple>(); try { ConstructContext context = new ConstructContext(null, s, true); foreach (IConstructTriplePattern p in cmd.DeletePattern.TriplePatterns.OfType<IConstructTriplePattern>()) { try { tempDeletedTriples.Add(p.Construct(context)); } catch (RdfQueryException) { //If we get an error here then it means we could not construct a specific //triple so we continue anyway } } deletedTriples.AddRange(tempDeletedTriples); } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //solution is ignored for this graph } //Triples from GRAPH clauses foreach (GraphPattern gp in cmd.DeletePattern.ChildGraphPatterns) { tempDeletedTriples.Clear(); try { String graphUri; switch (gp.GraphSpecifier.TokenType) { case Token.URI: graphUri = gp.GraphSpecifier.Value; break; case Token.VARIABLE: if (s.ContainsVariable(gp.GraphSpecifier.Value)) { INode temp = s[gp.GraphSpecifier.Value.Substring(1)]; if (temp == null) { //If the Variable is not bound then skip continue; } else if (temp.NodeType == NodeType.Uri) { graphUri = temp.ToSafeString(); } else { //If the Variable is not bound to a URI then skip continue; } } else { //If the Variable is not bound for this solution then skip continue; } break; default: //Any other Graph Specifier we have to ignore this solution continue; } if (!deletedGraphTriples.ContainsKey(graphUri)) deletedGraphTriples.Add(graphUri, new List<Triple>()); ConstructContext context = new ConstructContext(null, s, true); foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType<IConstructTriplePattern>()) { try { tempDeletedTriples.Add(p.Construct(context)); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct a specific //triple so we continue anyway } } deletedGraphTriples[graphUri].AddRange(tempDeletedTriples); } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //solution is ignored for this graph } } } //Generate the Triples for each Solution List<Triple> insertedTriples = new List<Triple>(); Dictionary<String, List<Triple>> insertedGraphTriples = new Dictionary<string, List<Triple>>(); foreach (Set s in mset.Sets) { List<Triple> tempInsertedTriples = new List<Triple>(); try { ConstructContext context = new ConstructContext(null, s, true); foreach (IConstructTriplePattern p in cmd.InsertPattern.TriplePatterns.OfType<IConstructTriplePattern>()) { try { tempInsertedTriples.Add(p.Construct(context)); } catch (RdfQueryException) { //If we get an error here then it means we couldn't construct a specific //triple so we continue anyway } } insertedTriples.AddRange(tempInsertedTriples); } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //solution is ignored for this graph } //Triples from GRAPH clauses foreach (GraphPattern gp in cmd.InsertPattern.ChildGraphPatterns) { tempInsertedTriples.Clear(); try { String graphUri; switch (gp.GraphSpecifier.TokenType) { case Token.URI: graphUri = gp.GraphSpecifier.Value; break; case Token.VARIABLE: if (s.ContainsVariable(gp.GraphSpecifier.Value)) { INode temp = s[gp.GraphSpecifier.Value.Substring(1)]; if (temp == null) { //If the Variable is not bound then skip continue; } else if (temp.NodeType == NodeType.Uri) { graphUri = temp.ToSafeString(); } else { //If the Variable is not bound to a URI then skip continue; } } else { //If the Variable is not bound for this solution then skip continue; } break; default: //Any other Graph Specifier we have to ignore this solution continue; } if (!insertedGraphTriples.ContainsKey(graphUri)) insertedGraphTriples.Add(graphUri, new List<Triple>()); ConstructContext context = new ConstructContext(null, s, true); foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType<IConstructTriplePattern>()) { try { tempInsertedTriples.Add(p.Construct(context)); } catch (RdfQueryException) { //If we get an error here it means we couldn't construct a specific //triple so we continue anyway } } insertedGraphTriples[graphUri].AddRange(tempInsertedTriples); } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //solution is ignored for this graph } } } //Now decide how to apply the update if (this._manager.UpdateSupported) { this._manager.UpdateGraph(cmd.GraphUri, insertedTriples, deletedTriples); //We do these two operations sequentially even if in some cases they could be combined to ensure that the underlying //Manager doesn't do any optimisations which would have the result of our updates not being properly applied //e.g. ignoring Triples which are both asserted and retracted in one update foreach (KeyValuePair<String, List<Triple>> graphDeletion in deletedGraphTriples) { this._manager.UpdateGraph(graphDeletion.Key, Enumerable.Empty<Triple>(), graphDeletion.Value); } foreach (KeyValuePair<String, List<Triple>> graphInsertion in insertedGraphTriples) { this._manager.UpdateGraph(graphInsertion.Key, graphInsertion.Value, Enumerable.Empty<Triple>()); } } else { Graph g = new Graph(); this._manager.LoadGraph(g, cmd.GraphUri); g.Retract(deletedTriples); this._manager.SaveGraph(g); foreach (String graphUri in deletedGraphTriples.Keys.Concat(insertedGraphTriples.Keys).Distinct()) { g = new Graph(); this._manager.LoadGraph(g, graphUri); if (deletedGraphTriples.ContainsKey(graphUri)) g.Retract(deletedGraphTriples[graphUri]); if (insertedGraphTriples.ContainsKey(graphUri)) g.Assert(insertedGraphTriples[graphUri]); this._manager.SaveGraph(g); } } } else { throw new SparqlUpdateException("Cannot evaluate an INSERT/DELETE Command as the underlying Store failed to answer the query for the WHERE portion of the command as expected"); } } else { throw new NotSupportedException("INSERT/DELETE commands are not supported by this Update Processor as the manager for the underlying Store does not provide Query capabilities which are necessary to process this command"); } } }
/// <summary> /// Processes an INSERT DATA command /// </summary> /// <param name="cmd">Insert Data Command</param> public void ProcessInsertDataCommand(InsertDataCommand cmd) { if (this._manager is IUpdateableGenericIOManager) { ((IUpdateableGenericIOManager)this._manager).Update(cmd.ToString()); } else { //Split the Pattern into the set of Graph Patterns List<GraphPattern> patterns = new List<GraphPattern>(); if (cmd.DataPattern.IsGraph) { patterns.Add(cmd.DataPattern); } else if (cmd.DataPattern.TriplePatterns.Count > 0 || cmd.DataPattern.HasChildGraphPatterns) { if (cmd.DataPattern.TriplePatterns.Count > 0) { patterns.Add(new GraphPattern()); cmd.DataPattern.TriplePatterns.ForEach(tp => patterns[0].AddTriplePattern(tp)); } cmd.DataPattern.ChildGraphPatterns.ForEach(gp => patterns.Add(gp)); } else { //If no Triple Patterns and No Child Graph Patterns nothing to do return; } foreach (GraphPattern pattern in patterns) { if (!this.IsValidDataPattern(pattern, false)) throw new SparqlUpdateException("Cannot evaluate an INSERT DATA command where any of the Triple Patterns are not concrete triples - variables are not permitted"); Uri graphUri = null; if (pattern.IsGraph) { switch (pattern.GraphSpecifier.TokenType) { case Token.QNAME: throw new NotImplementedException("Graph Specifiers as QNames for INSERT DATA Commands are not supported - please specify an absolute URI instead"); case Token.URI: graphUri = new Uri(pattern.GraphSpecifier.Value); break; default: throw new SparqlUpdateException("Cannot evaluate an INSERT DATA Command as the Graph Specifier is not a QName/URI"); } } Graph g = new Graph(); if (!this._manager.UpdateSupported) this._manager.LoadGraph(g, graphUri); //Insert the actual Triples INode subj, pred, obj; ConstructContext context = new ConstructContext(g, null, true); foreach (IConstructTriplePattern p in pattern.TriplePatterns.OfType<IConstructTriplePattern>()) { subj = p.Subject.Construct(context); pred = p.Predicate.Construct(context); obj = p.Object.Construct(context); g.Assert(new Triple(subj, pred, obj)); } if (this._manager.UpdateSupported) { this._manager.UpdateGraph(graphUri, g.Triples, Enumerable.Empty<Triple>()); } else { this._manager.SaveGraph(g); } } } }
/// <summary> /// Returns a Blank Node with a fixed ID scoped to whichever graph is provided /// </summary> /// <param name="context">Construct Context</param> protected internal override INode Construct(ConstructContext context) { if (context.Graph != null) { IBlankNode b = context.Graph.GetBlankNode(this._id); if (b != null) { return b; } else { return context.Graph.CreateBlankNode(this._id); } } else { return new BlankNode(context.Graph, this._id); } }
/// <summary> /// Evaluates the Command in the given Context /// </summary> /// <param name="context">Evaluation Context</param> public override void Evaluate(SparqlUpdateEvaluationContext context) { bool datasetOk = false; bool defGraphOk = false; try { //First evaluate the WHERE pattern to get the affected bindings ISparqlAlgebra where = this._wherePattern.ToAlgebra(); //Set Active Graph for the WHERE //Don't bother if there are USING URIs as these would override any Active Graph we set here //so we can save ourselves the effort of doing this if (!this.UsingUris.Any()) { if (this._graphUri != null) { context.Data.SetActiveGraph(this._graphUri); defGraphOk = true; } else { context.Data.SetActiveGraph((Uri)null); defGraphOk = true; } } //We need to make a dummy SparqlQuery object since if the Command has used any //USING NAMEDs along with GRAPH clauses then the algebra needs to have the //URIs available to it which it gets from the Query property of the Context //object SparqlQuery query = new SparqlQuery(); foreach (Uri u in this.UsingNamedUris) { query.AddNamedGraph(u); } SparqlEvaluationContext queryContext = new SparqlEvaluationContext(query, context.Data); if (this.UsingUris.Any()) { //If there are USING URIs set the Active Graph to be formed of the Graphs with those URIs context.Data.SetActiveGraph(this._usingUris); datasetOk = true; } BaseMultiset results = where.Evaluate(queryContext); if (this.UsingUris.Any()) { //If there are USING URIs reset the Active Graph afterwards //Also flag the dataset as no longer being OK as this flag is used in the finally //block to determine whether the Active Graph needs resetting which it may do if the //evaluation of the context.Data.ResetActiveGraph(); datasetOk = false; } //Reset Active Graph for the WHERE if (defGraphOk) { context.Data.ResetActiveGraph(); defGraphOk = false; } //TODO: Need to detect when we create a Graph for Insertion but then fail to insert anything since in this case the Inserted Graph should be removed //Get the Graph to which we are inserting //HashSet<Uri> insertedGraphs = new HashSet<Uri>(); IGraph g; if (context.Data.HasGraph(this._graphUri)) { g = context.Data.GetModifiableGraph(this._graphUri); } else { //insertedGraphs.Add(this._graphUri); g = new Graph(); g.BaseUri = this._graphUri; context.Data.AddGraph(g); g = context.Data.GetModifiableGraph(this._graphUri); } //Insert the Triples for each Solution foreach (Set s in queryContext.OutputMultiset.Sets) { List<Triple> insertedTriples = new List<Triple>(); //Triples from raw Triple Patterns try { ConstructContext constructContext = new ConstructContext(g, s, true); foreach (IConstructTriplePattern p in this._insertPattern.TriplePatterns.OfType<IConstructTriplePattern>()) { try { insertedTriples.Add(p.Construct(constructContext)); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct a specific Triple //so we continue anyway } } g.Assert(insertedTriples); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct for this solution so the //solution is ignored for this graph } //Triples from GRAPH clauses foreach (GraphPattern gp in this._insertPattern.ChildGraphPatterns) { insertedTriples.Clear(); try { String graphUri; switch (gp.GraphSpecifier.TokenType) { case Token.URI: graphUri = gp.GraphSpecifier.Value; break; case Token.VARIABLE: if (s.ContainsVariable(gp.GraphSpecifier.Value)) { INode temp = s[gp.GraphSpecifier.Value.Substring(1)]; if (temp == null) { //If the Variable is not bound then skip continue; } else if (temp.NodeType == NodeType.Uri) { graphUri = temp.ToSafeString(); } else { //If the Variable is not bound to a URI then skip continue; } } else { //If the Variable is not bound for this solution then skip continue; } break; default: //Any other Graph Specifier we have to ignore this solution continue; } //Ensure the Graph we're inserting to exists in the dataset creating it if necessary IGraph h; Uri destUri = new Uri(graphUri); if (context.Data.HasGraph(destUri)) { h = context.Data.GetModifiableGraph(destUri); } else { //insertedGraphs.Add(destUri); h = new Graph(); h.BaseUri = destUri; context.Data.AddGraph(h); h = context.Data.GetModifiableGraph(destUri); } //Do the actual Insertions ConstructContext constructContext = new ConstructContext(h, s, true); foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType<IConstructTriplePattern>()) { try { insertedTriples.Add(p.Construct(constructContext)); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct a specific Triple //so we continue anyway } } h.Assert(insertedTriples); } catch (RdfQueryException) { //If we throw an error this means we couldn't construct for this solution so the //solution is ignored for this Graph } } } } finally { //If the Dataset was set and an error occurred in doing the WHERE clause then //we'll need to Reset the Active Graph if (datasetOk) context.Data.ResetActiveGraph(); if (defGraphOk) context.Data.ResetActiveGraph(); } }