Hello Martin,
Yes that was my bug in SPARQL-to-SQL front-end.
The fix is attached and now it is on its way to the VOS head and
Virtuoso Universal Server.
Note that there is an issue with the discussed query. When the first
version of the SPARQL support was added to Virtuoso, there was no final
W3C spec and no final decision re. scope of blank nodes in group graph
patterns.
Now this query works solely as a result of intentional violation of the
spec, that says "A [blank node] label can be used in only a single basic
graph pattern (BGP) in any query". Thus the use of "_:b" in three
different BGPs violates the strict SPARQL syntax and will probably cause
syntax error in future versions. Plain variable, say, "?b" would be
safer (and portable).
Best Regards,
Ivan Mikhailov
OpenLink Software
http://virtuoso.openlinksw.com
> > Am 07.03.2011 12:09, schrieb Martin Gerlach:
> > > Hi,
> > >
> > > I observed the following SPARQL behavior with Virtuoso Open Source,
> > > Version 06.01.3127, running on Linux version 2.6.27.56-0.1-xen
> > > (geeko@buildhost) (gcc version 4.3.2 [gcc-4_3-branch revision 141291]
> > > (SUSE Linux) ) #1 SMP 2010-12-01 16:57:58 +0100:
> > >
> > > Given the following test graph:
> > >
> > > create graph <http://alx.neofonie.de/test>
> > >
> > > prefix test:<http://alx.neofonie.de/test/>
> > > insert into <http://alx.neofonie.de/test> {
> > > _:b1 a test:Relation .
> > > _:b1 test:agent test:A1 .
> > > _:b1 test:range test:R1 .
> > > _:b2 a test:Relation .
> > > _:b2 test:agent test:A2 .
> > > _:b2 test:range test:R1 .
> > > _:b3 a test:Relation .
> > > _:b3 test:agent test:A2 .
> > > _:b3 test:range test:R2 .
> > > }
> > >
> > > ... the following query:
> > >
> > > prefix test:<http://alx.neofonie.de/test/>
> > > select ?agent ?range
> > > from <http://alx.neofonie.de/test>
> > > where {
> > > _:b a test:Relation .
> > > filter (?agent = test:A1)
> > > optional{ _:b test:agent ?agent.}
> > > optional{ _:b test:range ?range.}
> > > }
> > >
> > > ... returns (as CSV):
> > >
> > > "agent","range"
> > > "http://alx.neofonie.de/test/A1","http://alx.neofonie.de/test/R1"
> > > "http://alx.neofonie.de/test/A1","http://alx.neofonie.de/test/R1"
> > > "http://alx.neofonie.de/test/A1","http://alx.neofonie.de/test/R2"
> > >
> > > ... which contains the wrong (because non existing) result A1/R2.
> > >
> > > Obviously, the filter expression binds ?agent to test:A1 if it is not
> > > bound by the first optional sub query. This can easily be seen by
> > > omitting the filter.
> > >
> > > The question is: Does this behavior conform to the SPARQL spec or is
> > > this a Virtuoso bug?
> > >
> > > This sentence from http://www.w3.org/TR/rdf-sparql-query/ ,
> > > section 3, makes me think it is probably a bug:
> > >
> > > "Graph pattern matching produces a solution sequence, where each
> > > solution has a set of bindings of variables to RDF terms. SPARQL FILTERs
> > > restrict solutions to those for which the filter expression evaluates to
> > > TRUE."
> > >
> > > The filter expression, ?agent = test:A1, should not evaluate to TRUE if
> > > ?agent is not bound, and it should also not bind ?agent to test:A1.
> > >
> > > Regards,
> > > Martin
> > >
> > > --
> > >
> > > (Of course, one can just make the first optional binding a required
> > > binding (result: A1/R1), or move the filter into the first optional
> > > block (result: _/R1, A1/R1, _/R2) to obtain results that make more
> > > sense. The example is a stripped down version of a more complex use case.)
Index: sparql2sqltext.c
===================================================================
RCS file: /home/staff/us-cvs/virtuoso/libsrc/Wi/sparql2sqltext.c,v
retrieving revision 1.47.2.124
diff -u -U 10 -r1.47.2.124 sparql2sqltext.c
--- sparql2sqltext.c 9 Mar 2011 12:53:09 -0000 1.47.2.124
+++ sparql2sqltext.c 28 Mar 2011 18:20:54 -0000
@@ -5673,20 +5673,22 @@
int sub_ctr;
if (eq->e_replaces_filter & ~(eq->e_rvr.rvrRestrictions) & ~SPART_VARR_EQ_VAR)
spar_internal_error (ssg->ssg_sparp, "lost filters in equivs");
if (UNION_L != eq->e_gp->_.gp.subtype)
{
DO_BOX_FAST (ptrlong, sub_idx, sub_ctr, eq->e_subvalue_idxs)
{
sparp_equiv_t *sub_eq = SPARP_EQUIV (ssg->ssg_sparp, sub_idx);
if (OPTIONAL_L == sub_eq->e_gp->_.gp.subtype)
continue;
+ if (!(SPART_VARR_NOT_NULL & sub_eq->e_rvr.rvrRestrictions) && (0 == sub_eq->e_gspo_uses))
+ continue;
restrs_not_filtered_in_subqs &= (~(sub_eq->e_rvr.rvrRestrictions) |
~(SPART_VARR_IS_BLANK | SPART_VARR_IS_IRI | SPART_VARR_IS_LIT | SPART_VARR_IS_REF | SPART_VARR_NOT_NULL ) );
if ((SPART_VARR_FIXED & restrs_not_filtered_in_subqs) &&
(SPART_VARR_FIXED & sub_eq->e_rvr.rvrRestrictions) &&
(DVC_MATCH == cmp_boxes_safe ((caddr_t) eq->e_rvr.rvrFixedValue, (caddr_t) sub_eq->e_rvr.rvrFixedValue, NULL, NULL)) )
restrs_not_filtered_in_subqs &= ~SPART_VARR_FIXED;
if ((SPART_VARR_TYPED & restrs_not_filtered_in_subqs) &&
(SPART_VARR_TYPED & sub_eq->e_rvr.rvrRestrictions) &&
(DVC_MATCH == cmp_boxes_safe ((caddr_t) eq->e_rvr.rvrDatatype, (caddr_t) sub_eq->e_rvr.rvrDatatype, NULL, NULL)) )
restrs_not_filtered_in_subqs &= ~SPART_VARR_TYPED;