Uploaded image for project: 'Apache Jena'
  1. Apache Jena
  2. JENA-1275

TransformScopeRename does the wrong thing with FILTER NOT EXISTS

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • Jena 3.1.1
    • Jena 3.2.0
    • ARQ
    • None

    Description

      I have produced the following minimal query from an originally much larger query. When the optimise is applied to this it incorrectly double renames the variables inside of the FILTER NOT EXISTS clause leading to incorrect algebra.

      Query:

      SELECT ?triangles ?openTriplets
        {
          {
            #subQ2: calculate #open-triplets
            SELECT (COUNT(?x) as ?openTriplets)
            WHERE {
              ?x ?a ?y .
              ?y ?b ?z .
              FILTER NOT EXISTS {?z ?c ?x}
            }
          }
        }
      

      Output:

      (project (?triangles ?openTriplets)
        (project (?openTriplets)
          (extend ((?openTriplets ?/.0))
            (group () ((?/.0 (count ?/x)))
              (filter (notexists
                         (quadpattern (quad <urn:x-arq:DefaultGraphNode> ?//z ?//c ?//x)))
                (quadpattern
                  (quad <urn:x-arq:DefaultGraphNode> ?/x ?/a ?/y)
                  (quad <urn:x-arq:DefaultGraphNode> ?/y ?/b ?/z)
                ))))))
      

      Note that we apply the quad transformation prior to applying the optimiser.

      Strangely enough I cannot reproduce the problem using pure Jena command line tools i.e. qparse although I note from the code that it applies quad transformation after applying optimisation. This suggests that it is a bug in how TransformScopeRename applies to quad form algebra.

      I can reproduce it with a unit test like so:

          @Test
          public void filter_not_exists_scoping_03() {
              //@formatter:off
              Op orig = SSE.parseOp(StrUtils.strjoinNL("(project (?triangles ?openTriplets)",
                                             "  (project (?openTriplets)",
                                             "    (extend ((?openTriplets ?.0))",
                                             "      (group () ((?.0 (count ?x)))",
                                             "        (filter (notexists",
                                             "                   (quadpattern (quad <urn:x-arq:DefaultGraphNode> ?z ?c ?x)))",
                                             "          (quadpattern",
                                             "            (quad <urn:x-arq:DefaultGraphNode> ?x ?a ?y)",
                                             "            (quad <urn:x-arq:DefaultGraphNode> ?y ?b ?z)",
                                             "          ))))))"));
              Op expected = SSE.parseOp(StrUtils.strjoinNL("(project (?triangles ?openTriplets)",
                      "  (project (?openTriplets)",
                      "    (extend ((?openTriplets ?/.0))",
                      "      (group () ((?/.0 (count ?/x)))",
                      "        (filter (notexists",
                      "                   (quadpattern (quad <urn:x-arq:DefaultGraphNode> ?/z ?/c ?/x)))",
                      "          (quadpattern",
                      "            (quad <urn:x-arq:DefaultGraphNode> ?/x ?/a ?/y)",
                      "            (quad <urn:x-arq:DefaultGraphNode> ?/y ?/b ?/z)",
                      "          ))))))"));
              //@formatter:on
              
              Op transformed = TransformScopeRename.transform(orig);
              
              Assert.assertEquals(transformed, expected);
          }
          
          @Test
          public void filter_not_exists_scoping_04() {
              //@formatter:off
              Op orig = SSE.parseOp(StrUtils.strjoinNL(
                                             "  (project (?openTriplets)",
                                             "    (extend ((?openTriplets ?.0))",
                                             "      (group () ((?.0 (count ?x)))",
                                             "        (filter (notexists",
                                             "                   (quadpattern (quad <urn:x-arq:DefaultGraphNode> ?z ?c ?x)))",
                                             "          (quadpattern",
                                             "            (quad <urn:x-arq:DefaultGraphNode> ?x ?a ?y)",
                                             "            (quad <urn:x-arq:DefaultGraphNode> ?y ?b ?z)",
                                             "          )))))"));
              Op expected = SSE.parseOp(StrUtils.strjoinNL(
                      "  (project (?openTriplets)",
                      "    (extend ((?openTriplets ?.0))",
                      "      (group () ((?.0 (count ?x)))",
                      "        (filter (notexists",
                      "                   (quadpattern (quad <urn:x-arq:DefaultGraphNode> ?z ?c ?x)))",
                      "          (quadpattern",
                      "            (quad <urn:x-arq:DefaultGraphNode> ?x ?a ?y)",
                      "            (quad <urn:x-arq:DefaultGraphNode> ?y ?b ?z)",
                      "          )))))"));
              //@formatter:on
              
              Op transformed = TransformScopeRename.transform(orig);
              
              Assert.assertEquals(transformed, expected);
          }
      

      The first test fails while the second passes. This implies that you need 2 levels of projection to hit the bug.

      Attachments

        Issue Links

          Activity

            People

              andy Andy Seaborne
              rvesse Rob Vesse
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: