/// <summary>
 /// Processes an INSERT/DELETE command
 /// </summary>
 /// <param name="cmd">Insert/Delete Command</param>
 public void ProcessModifyCommand(ModifyCommand cmd)
 {
     this.ProcessCommand(cmd);
 }
Example #2
0
        /// <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)
                {
                    //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.DeletePattern.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.DeletePattern.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");
                    }
                    //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> deletedTriples = new List<Triple>();
                        Dictionary<String, List<Triple>> deletedGraphTriples = new Dictionary<string, List<Triple>>();
                        foreach (ISet 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 (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 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/DELETE command
 /// </summary>
 /// <param name="cmd">Insert/Delete Command</param>
 public void ProcessModifyCommand(ModifyCommand cmd)
 {
     this.ProcessModifyCommandInternal(cmd, this.GetContext());
 }
 /// <summary>
 /// Processes an INSERT/DELETE command
 /// </summary>
 /// <param name="cmd">Insert/Delete Command</param>
 /// <param name="context">SPARQL Update Evaluation Context</param>
 protected virtual void ProcessModifyCommandInternal(ModifyCommand cmd, SparqlUpdateEvaluationContext context)
 {
     cmd.Evaluate(context);
 }
        private SparqlUpdateCommand TryParseDeleteCommand(SparqlUpdateParserContext context, bool allowData)
        {
            IToken next = context.Tokens.Dequeue();
            List<Uri> usings = new List<Uri>();
            List<Uri> usingNamed = new List<Uri>();
            if (allowData)
            {
                //We are allowed to have an DELETE DATA command here so check for it
                if (next.TokenType == Token.DATA) return this.TryParseDeleteDataCommand(context);
            }
            else
            {
                if (next.TokenType == Token.DATA) throw ParserHelper.Error("The DATA keyword is not permitted here as this INSERT command forms part of a modification command", next);
            }

            if (next.TokenType == Token.WHERE)
            {
                //Parse the WHERE pattern which serves as both the selection and deletion pattern in this case
                context.Tokens.Dequeue();
                GraphPattern where = this.TryParseModifyTemplate(context);

                //Then return the command
                return new DeleteCommand(where, where);
            }
            else
            {
                //Get the Modification Template
                GraphPattern deletions = this.TryParseModifyTemplate(context);

                //Then we expect a WHERE keyword
                next = context.Tokens.Dequeue();
                if (next.TokenType == Token.USING)
                {
                    foreach (KeyValuePair<Uri, bool> kvp in this.TryParseUsingStatements(context))
                    {
                        if (kvp.Value)
                        {
                            usingNamed.Add(kvp.Key);
                        }
                        else
                        {
                            usings.Add(kvp.Key);
                        }
                    }
                    next = context.Tokens.Dequeue();
                }
                if (next.TokenType == Token.WHERE)
                {
                    //Now parse the WHERE pattern
                    SparqlQueryParserContext subContext = new SparqlQueryParserContext(context.Tokens);
                    subContext.Query.BaseUri = context.BaseUri;
                    subContext.Query.NamespaceMap = context.NamespaceMap;
                    subContext.ExpressionParser.NamespaceMap = context.NamespaceMap;
                    subContext.ExpressionParser.ExpressionFactories = context.ExpressionFactories;
                    subContext.ExpressionFactories = context.ExpressionFactories;
                    GraphPattern where = context.QueryParser.TryParseGraphPattern(subContext, context.Tokens.LastTokenType != Token.LEFTCURLYBRACKET);

                    //And finally return the command
                    DeleteCommand cmd = new DeleteCommand(deletions, where);
                    usings.ForEach(u => cmd.AddUsingUri(u));
                    usingNamed.ForEach(u => cmd.AddUsingNamedUri(u));
                    return cmd;
                }
                else if (next.TokenType == Token.INSERT)
                {
                    InsertCommand insertCmd = (InsertCommand)this.TryParseInsertCommand(context, false);
                    ModifyCommand cmd = new ModifyCommand(deletions, insertCmd.InsertPattern, insertCmd.WherePattern);
                    insertCmd.UsingUris.ToList().ForEach(u => cmd.AddUsingUri(u));
                    insertCmd.UsingNamedUris.ToList().ForEach(u => cmd.AddUsingNamedUri(u));
                    return cmd;
                }
                else
                {
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a WHERE keyword as part of a DELETE command", next);
                }
            }
        }