/// <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> /// Queries the store asynchronously /// </summary> /// <param name="sparqlQuery">SPARQL Query</param> /// <param name="rdfHandler">RDF Handler</param> /// <param name="resultsHandler">Results Handler</param> /// <param name="callback">Callback</param> /// <param name="state">State to pass to the callback</param> public void Query(IRdfHandler rdfHandler, ISparqlResultsHandler resultsHandler, string sparqlQuery, AsyncStorageCallback callback, object state) { try { // First off parse the Query to see what kind of query it is SparqlQuery q; try { q = _parser.ParseFromString(sparqlQuery); } catch (RdfParseException parseEx) { callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, parseEx), state); return; } catch (Exception ex) { callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, new RdfStorageException("An unexpected error occurred while trying to parse the SPARQL Query prior to sending it to the Store, see inner exception for details", ex)), state); return; } // Now select the Accept Header based on the query type String accept = (SparqlSpecsHelper.IsSelectQuery(q.QueryType) || q.QueryType == SparqlQueryType.Ask) ? MimeTypesHelper.HttpSparqlAcceptHeader : MimeTypesHelper.HttpAcceptHeader; // Create the Request, for simplicity async requests are always POST HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_endpoint.Uri); request.Accept = accept; request.Method = "POST"; request.ContentType = MimeTypesHelper.Utf8WWWFormURLEncoded; request = ApplyRequestOptions(request); Tools.HttpDebugRequest(request); request.BeginGetRequestStream(r => { try { Stream stream = request.EndGetRequestStream(r); using (StreamWriter writer = new StreamWriter(stream, new UTF8Encoding(Options.UseBomForUtf8))) { writer.Write("query="); writer.Write(HttpUtility.UrlEncode(sparqlQuery)); writer.Close(); } request.BeginGetResponse(r2 => { // Get the Response and process based on the Content Type try { HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(r2); Tools.HttpDebugResponse(response); StreamReader data = new StreamReader(response.GetResponseStream()); String ctype = response.ContentType; if (SparqlSpecsHelper.IsSelectQuery(q.QueryType) || q.QueryType == SparqlQueryType.Ask) { // ASK/SELECT should return SPARQL Results ISparqlResultsReader resreader = MimeTypesHelper.GetSparqlParser(ctype, q.QueryType == SparqlQueryType.Ask); resreader.Load(resultsHandler, data); response.Close(); } else { // CONSTRUCT/DESCRIBE should return a Graph IRdfReader rdfreader = MimeTypesHelper.GetParser(ctype); rdfreader.Load(rdfHandler, data); response.Close(); } callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, sparqlQuery, rdfHandler, resultsHandler), state); } catch (WebException webEx) { callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, StorageHelper.HandleHttpQueryError(webEx)), state); } catch (Exception ex) { callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, StorageHelper.HandleQueryError(ex)), state); } }, state); } catch (WebException webEx) { callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, StorageHelper.HandleHttpQueryError(webEx)), state); } catch (Exception ex) { callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, StorageHelper.HandleQueryError(ex)), state); } }, state); } catch (WebException webEx) { callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, StorageHelper.HandleHttpQueryError(webEx)), state); } catch (Exception ex) { callback(this, new AsyncStorageCallbackArgs(AsyncStorageOperation.SparqlQueryWithHandler, StorageHelper.HandleQueryError(ex)), state); } }
/// <summary> /// Processes a SPARQL Query sending the results to a RDF/SPARQL Results handler as appropriate /// </summary> /// <param name="rdfHandler">RDF Handler</param> /// <param name="resultsHandler">Results Handler</param> /// <param name="query">SPARQL Query</param> public void ProcessQuery(IRdfHandler rdfHandler, ISparqlResultsHandler resultsHandler, SparqlQuery query) { //Do Handler null checks before evaluating the query if (query == null) { throw new ArgumentNullException("query", "Cannot evaluate a null query"); } if (rdfHandler == null && (query.QueryType == SparqlQueryType.Construct || query.QueryType == SparqlQueryType.Describe || query.QueryType == SparqlQueryType.DescribeAll)) { throw new ArgumentNullException("rdfHandler", "Cannot use a null RDF Handler when the Query is a CONSTRUCT/DESCRIBE"); } if (resultsHandler == null && (query.QueryType == SparqlQueryType.Ask || SparqlSpecsHelper.IsSelectQuery(query.QueryType))) { throw new ArgumentNullException("resultsHandler", "Cannot use a null resultsHandler when the Query is an ASK/SELECT"); } //Handle the Thread Safety of the Query Evaluation #if !NO_RWLOCK ReaderWriterLockSlim currLock = (this._dataset is IThreadSafeDataset) ? ((IThreadSafeDataset)this._dataset).Lock : this._lock; try { currLock.EnterReadLock(); #endif //Reset Query Timers query.QueryExecutionTime = null; bool datasetOk = false, defGraphOk = false; try { //Set up the Default and Active Graphs if (query.DefaultGraphs.Any()) { //Call HasGraph() on each Default Graph but ignore the results, we just do this //in case a dataset has any kind of load on demand behaviour foreach (Uri defGraphUri in query.DefaultGraphs) { this._dataset.HasGraph(defGraphUri); } this._dataset.SetDefaultGraph(query.DefaultGraphs); defGraphOk = true; } else if (query.NamedGraphs.Any()) { //No FROM Clauses but one/more FROM NAMED means the Default Graph is the empty graph this._dataset.SetDefaultGraph(Enumerable.Empty <Uri>()); } this._dataset.SetActiveGraph(this._dataset.DefaultGraphUris); datasetOk = true; //Convert to Algebra and execute the Query SparqlEvaluationContext context = this.GetContext(query); BaseMultiset result; try { context.StartExecution(); ISparqlAlgebra algebra = query.ToAlgebra(); result = context.Evaluate(algebra); context.EndExecution(); query.QueryExecutionTime = new TimeSpan(context.QueryTimeTicks); } catch (RdfQueryException) { context.EndExecution(); query.QueryExecutionTime = new TimeSpan(context.QueryTimeTicks); throw; } catch { context.EndExecution(); query.QueryExecutionTime = new TimeSpan(context.QueryTimeTicks); throw; } //Return the Results switch (query.QueryType) { case SparqlQueryType.Ask: case SparqlQueryType.Select: case SparqlQueryType.SelectAll: case SparqlQueryType.SelectAllDistinct: case SparqlQueryType.SelectAllReduced: case SparqlQueryType.SelectDistinct: case SparqlQueryType.SelectReduced: //For SELECT and ASK can populate a Result Set directly from the Evaluation Context //return new SparqlResultSet(context); resultsHandler.Apply(context); break; case SparqlQueryType.Construct: //Create a new Empty Graph for the Results try { rdfHandler.StartRdf(); foreach (String prefix in query.NamespaceMap.Prefixes) { if (!rdfHandler.HandleNamespace(prefix, query.NamespaceMap.GetNamespaceUri(prefix))) { ParserHelper.Stop(); } } //Construct the Triples for each Solution foreach (ISet s in context.OutputMultiset.Sets) { //List<Triple> constructedTriples = new List<Triple>(); try { ConstructContext constructContext = new ConstructContext(rdfHandler, s, false); foreach (IConstructTriplePattern p in query.ConstructTemplate.TriplePatterns.OfType <IConstructTriplePattern>()) { try { if (!rdfHandler.HandleTriple(p.Construct(constructContext))) { ParserHelper.Stop(); } //constructedTriples.Add(((IConstructTriplePattern)p).Construct(constructContext)); } catch (RdfQueryException) { //If we get an error here then we could not construct a specific triple //so we continue anyway } } } catch (RdfQueryException) { //If we get an error here this means we couldn't construct for this solution so the //entire solution is discarded continue; } //h.Assert(constructedTriples); } rdfHandler.EndRdf(true); } catch (RdfParsingTerminatedException) { rdfHandler.EndRdf(true); } catch { rdfHandler.EndRdf(false); throw; } break; case SparqlQueryType.Describe: case SparqlQueryType.DescribeAll: //For DESCRIBE we retrieve the Describe algorithm and apply it ISparqlDescribe describer = query.Describer; describer.Describe(rdfHandler, context); break; default: throw new RdfQueryException("Unknown query types cannot be processed by Leviathan"); } } finally { if (defGraphOk) { this._dataset.ResetDefaultGraph(); } if (datasetOk) { this._dataset.ResetActiveGraph(); } } #if !NO_RWLOCK } finally { currLock.ExitReadLock(); } #endif }
/// <summary> /// Performs a SPARQL Query against the underlying Store /// </summary> /// <param name="rdfHandler">RDF Handler</param> /// <param name="resultsHandler">SPARQL Results Handler</param> /// <param name="sparqlQuery">SPARQL Query</param> /// <returns></returns> public void Query(IRdfHandler rdfHandler, ISparqlResultsHandler resultsHandler, string sparqlQuery) { try { //First off parse the Query to see what kind of query it is SparqlQuery q; try { q = this._parser.ParseFromString(sparqlQuery); } catch (RdfParseException parseEx) { throw; } catch (Exception ex) { throw new RdfStorageException("An unexpected error occurred while trying to parse the SPARQL Query prior to sending it to the Store, see inner exception for details", ex); } //Now select the Accept Header based on the query type String accept = (SparqlSpecsHelper.IsSelectQuery(q.QueryType) || q.QueryType == SparqlQueryType.Ask) ? MimeTypesHelper.HttpSparqlAcceptHeader : MimeTypesHelper.HttpAcceptHeader; //Create the Request HttpWebRequest request; Dictionary <String, String> queryParams = new Dictionary <string, string>(); if (sparqlQuery.Length < 2048) { queryParams.Add("query", sparqlQuery); request = this.CreateRequest("/sparql", accept, "GET", queryParams); } else { request = this.CreateRequest("/sparql", accept, "POST", queryParams); //Build the Post Data and add to the Request Body request.ContentType = MimeTypesHelper.WWWFormURLEncoded; StringBuilder postData = new StringBuilder(); postData.Append("query="); postData.Append(HttpUtility.UrlEncode(sparqlQuery)); StreamWriter writer = new StreamWriter(request.GetRequestStream()); writer.Write(postData); writer.Close(); } #if DEBUG if (Options.HttpDebugging) { Tools.HttpDebugRequest(request); } #endif //Get the Response and process based on the Content Type using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { #if DEBUG if (Options.HttpDebugging) { Tools.HttpDebugResponse(response); } #endif StreamReader data = new StreamReader(response.GetResponseStream()); String ctype = response.ContentType; if (SparqlSpecsHelper.IsSelectQuery(q.QueryType) || q.QueryType == SparqlQueryType.Ask) { //ASK/SELECT should return SPARQL Results ISparqlResultsReader resreader = MimeTypesHelper.GetSparqlParser(ctype, q.QueryType == SparqlQueryType.Ask); resreader.Load(resultsHandler, data); response.Close(); } else { //CONSTRUCT/DESCRIBE should return a Graph IRdfReader rdfreader = MimeTypesHelper.GetParser(ctype); rdfreader.Load(rdfHandler, data); response.Close(); } } } catch (WebException webEx) { if (webEx.Response != null) { #if DEBUG if (Options.HttpDebugging) { Tools.HttpDebugResponse((HttpWebResponse)webEx.Response); } #endif if (webEx.Response.ContentLength > 0) { try { String responseText = new StreamReader(webEx.Response.GetResponseStream()).ReadToEnd(); throw new RdfQueryException("A HTTP error occured while querying the Store. Store returned the following error message: " + responseText, webEx); } catch { throw new RdfQueryException("A HTTP error occurred while querying the Store", webEx); } } else { throw new RdfQueryException("A HTTP error occurred while querying the Store", webEx); } } else { throw new RdfQueryException("A HTTP error occurred while querying the Store", webEx); } } }
internal static INode ToSpinRdf(this SparqlQuery query, IGraph g) { INode root = g.CreateBlankNode(); SpinVariableTable varTable = new SpinVariableTable(g); //Ensure the Query is optimised so that all the elements are placed in Graph Patterns //so we can serialized them OK query.Optimise(); switch (query.QueryType) { case SparqlQueryType.Ask: g.Assert(root, RDF.PropertyType, SP.ClassAsk); break; case SparqlQueryType.Construct: g.Assert(root, RDF.PropertyType, SP.ClassConstruct); break; case SparqlQueryType.Describe: case SparqlQueryType.DescribeAll: throw new SpinException("DESCRIBE queries cannot be represented in SPIN RDF Syntax"); case SparqlQueryType.Select: case SparqlQueryType.SelectAll: case SparqlQueryType.SelectAllDistinct: case SparqlQueryType.SelectAllReduced: case SparqlQueryType.SelectDistinct: case SparqlQueryType.SelectReduced: g.Assert(root, RDF.PropertyType, SP.ClassSelect); break; case SparqlQueryType.Unknown: throw new SpinException("Unknown query types cannot be represented in SPIN RDF Syntax"); } //Process the WHERE clause g.Assert(root, SP.PropertyWhere, query.RootGraphPattern.ToSpinRdf(g, varTable)); //Add Variables for a SELECT query if (SparqlSpecsHelper.IsSelectQuery(query.QueryType)) { switch (query.QueryType) { case SparqlQueryType.Select: case SparqlQueryType.SelectDistinct: case SparqlQueryType.SelectReduced: //Only Add Variables for SELECTs with explicit variable lists INode vars = g.CreateBlankNode(); g.Assert(root, SP.PropertyResultVariables, vars); //Get the Variables and generate the Nodes we'll use to help represent them List <SparqlVariable> vs = query.Variables.Where(v => v.IsResultVariable).ToList(); for (int i = 0; i < vs.Count; i++) { SparqlVariable v = vs[i]; INode var = varTable[v.Name]; g.Assert(vars, RDF.PropertyFirst, var); if (i < vs.Count - 1) { INode temp = g.CreateBlankNode(); g.Assert(vars, RDF.PropertyRest, temp); vars = temp; } // TODO check that was commented before modifications //g.Assert(var, RDF.type, SP.Variable); if (v.IsAggregate) { g.Assert(var, SP.PropertyAs, g.CreateLiteralNode(v.Name, XSD.string_.Uri)); g.Assert(var, SP.PropertyExpression, v.Aggregate.ToSpinRdf(g, varTable)); } else if (v.IsProjection) { g.Assert(var, SP.PropertyAs, g.CreateLiteralNode(v.Name, XSD.string_.Uri)); //TODO check for this //g.Assert(var, SP.expression, v.Projection.ToSpinRdf(query.RootGraphPattern, g, varTable)); } else { g.Assert(var, SP.PropertyVarName, g.CreateLiteralNode(v.Name, XSD.string_.Uri)); } } g.Assert(vars, RDF.PropertyRest, RDF.Nil); break; } } //Add DISTINCT/REDUCED modifiers if appropriate if (query.HasDistinctModifier) { switch (query.QueryType) { case SparqlQueryType.SelectAllDistinct: case SparqlQueryType.SelectDistinct: g.Assert(root, SP.PropertyDistinct, RDFUtil.TRUE); break; case SparqlQueryType.SelectAllReduced: case SparqlQueryType.SelectReduced: g.Assert(root, SP.PropertyReduced, RDFUtil.TRUE); break; } } //Add LIMIT and/or OFFSET if appropriate if (query.Limit > -1) { g.Assert(root, SP.PropertyLimit, query.Limit.ToLiteral(g)); } if (query.Offset > 0) { g.Assert(root, SP.PropertyOffset, query.Offset.ToLiteral(g)); } //Add ORDER BY if appropriate if (query.OrderBy != null) { g.Assert(root, SP.PropertyOrderBy, query.OrderBy.ToSpinRdf(g, varTable)); } //Add GROUP BY and HAVING if (query.GroupBy != null) { throw new SpinException("GROUP BY clauses are not yet representable in SPIN RDF Syntax"); } if (query.Having != null) { throw new SpinException("HAVING clauses are not yet representable in SPIN RDF Syntax"); } return(root); }
/// <summary> /// Makes a SPARQL Query against the underlying Store processing the results with an appropriate handler from those provided /// </summary> /// <param name="rdfHandler">RDF Handler</param> /// <param name="resultsHandler">Results Handler</param> /// <param name="sparqlQuery">SPARQL Query</param> /// <returns></returns> public virtual void Query(IRdfHandler rdfHandler, ISparqlResultsHandler resultsHandler, String sparqlQuery) { try { //Pre-parse the query to determine what the Query Type is bool isAsk = false; SparqlQuery q = null; try { q = this._parser.ParseFromString(sparqlQuery); isAsk = q.QueryType == SparqlQueryType.Ask; } catch { //If parsing error fallback to naive detection isAsk = Regex.IsMatch(sparqlQuery, "ASK", RegexOptions.IgnoreCase); } //Select Accept Header String accept; if (q != null) { accept = (SparqlSpecsHelper.IsSelectQuery(q.QueryType) || q.QueryType == SparqlQueryType.Ask ? MimeTypesHelper.HttpSparqlAcceptHeader : MimeTypesHelper.HttpAcceptHeader); } else { accept = MimeTypesHelper.HttpRdfOrSparqlAcceptHeader; } HttpWebRequest request; //Create the Request Dictionary <String, String> queryParams = new Dictionary <string, string>(); if (sparqlQuery.Length < 2048 && !this._postAllQueries) { queryParams.Add("query", EscapeQuery(sparqlQuery)); request = this.CreateRequest(this._repositoriesPrefix + this._store + this._queryPath, accept, "GET", queryParams); } else { request = this.CreateRequest(this._repositoriesPrefix + this._store + this._queryPath, accept, "POST", queryParams); //Build the Post Data and add to the Request Body request.ContentType = MimeTypesHelper.WWWFormURLEncoded; StringBuilder postData = new StringBuilder(); postData.Append("query="); postData.Append(Uri.EscapeDataString(EscapeQuery(sparqlQuery))); StreamWriter writer = new StreamWriter(request.GetRequestStream()); writer.Write(postData); writer.Close(); } #if DEBUG if (Options.HttpDebugging) { Tools.HttpDebugRequest(request); } #endif //Get the Response and process based on the Content Type using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { #if DEBUG if (Options.HttpDebugging) { Tools.HttpDebugResponse(response); } #endif StreamReader data = new StreamReader(response.GetResponseStream()); String ctype = response.ContentType; try { //Is the Content Type referring to a Sparql Result Set format? ISparqlResultsReader resreader = MimeTypesHelper.GetSparqlParser(ctype, isAsk); resreader.Load(resultsHandler, data); response.Close(); } catch (RdfParserSelectionException) { //If we get a Parser Selection exception then the Content Type isn't valid for a Sparql Result Set //Is the Content Type referring to a RDF format? IRdfReader rdfreader = MimeTypesHelper.GetParser(ctype); if (q != null && (SparqlSpecsHelper.IsSelectQuery(q.QueryType) || q.QueryType == SparqlQueryType.Ask)) { SparqlRdfParser resreader = new SparqlRdfParser(rdfreader); resreader.Load(resultsHandler, data); } else { rdfreader.Load(rdfHandler, data); } response.Close(); } } } catch (WebException webEx) { if (webEx.Response != null) { #if DEBUG if (Options.HttpDebugging) { Tools.HttpDebugResponse((HttpWebResponse)webEx.Response); } #endif if (webEx.Response.ContentLength > 0) { try { String responseText = new StreamReader(webEx.Response.GetResponseStream()).ReadToEnd(); throw new RdfQueryException("A HTTP error occured while querying the Store. Store returned the following error message: " + responseText, webEx); } catch { throw new RdfQueryException("A HTTP error occurred while querying the Store", webEx); } } else { throw new RdfQueryException("A HTTP error occurred while querying the Store", webEx); } } else { throw new RdfQueryException("A HTTP error occurred while querying the Store", webEx); } } }