Juan José Ramos Cassella created GEODE-6806:
-----------------------------------------------

             Summary: Wrong Results in multi OQL joins + Indexes + LIMIT clause
                 Key: GEODE-6806
                 URL: https://issues.apache.org/jira/browse/GEODE-6806
             Project: Geode
          Issue Type: Bug
          Components: querying
            Reporter: Juan José Ramos Cassella


When joining multiple regions with indexes defined on them, the results of the 
query might be wrong if the {{LIMIT}} keyword is used in the {{OQL}} and the 
intermediate result size of the query is greater than the actual {{LIMIT}} used.
Internally we get the _partial_ results from the {{indexes}} and _cut down_ 
these intermediate results during the actual execution. With the goal of 
speeding things up, we use the {{LIMIT}} value to stop the iteration sooner but 
we do not know if the first X results (governed by the {{LIMIT}} value) might 
or might not fulfil the rest of the operands.

The {{LIMIT}} clause is _disabled_ at the {{index}} level but still enabled in 
this intermediate step, which is causing the final result to not contain 
certain rows that should be included.
The following example reproduces the issue (doesn't matter whether {{PDX}} is 
used or not):


{code:java}
  private void populateTripleJointRegions(int expectedMatches, int 
extraEntitiesPerRegion, Cache cache, Region<String, Object> orderRegion, 
Region<String, Object> validationIssueRegion, Region<String, Object> 
validationIssueXRefRegion) {
    for (int i = 0; i < expectedMatches; i++) {
      PdxInstance orderPdx = cache
          .createPdxInstanceFactory("org.apache.geode.test.Order")
          .writeString("orderId", "orderId_" + i)
          .writeInt("version", i)
          .create();
      PdxInstance validationIssuePdx = cache
          .createPdxInstanceFactory("org.apache.geode.test.ValidationIssue")
          .writeString("issueId", "issueId_" + i)
          .writeDate("createdTime", Calendar.getInstance().getTime())
          .create();
      PdxInstance validationIssueXRefPdx = cache
          
.createPdxInstanceFactory("org.apache.geode.test.OrderValidationIssueXRef")
          .writeString("validationIssueXRefID", "validationIssueXRefID_" + i)
          .writeString("referenceIssueId", "issueId_" + i)
          .writeString("referenceOrderId", "orderId_" + i)
          .writeInt("referenceOrderVersion", i)
          .create();

      orderRegion.put("orderId_" + i, orderPdx);
      validationIssueRegion.put("issueId_" + i , validationIssuePdx);
      validationIssueXRefRegion.put("validationIssueXRefID_" + i, 
validationIssueXRefPdx);
    }

    for (int i = 0; i < extraEntitiesPerRegion; i++) {
      PdxInstance orderPdx = cache
          .createPdxInstanceFactory("org.apache.geode.test.Order")
          .writeString("orderId", "orderId#" + i)
          .writeInt("version", i)
          .create();
      PdxInstance validationIssuePdx = cache
          .createPdxInstanceFactory("org.apache.geode.test.ValidationIssue")
          .writeString("referenceIssueId", "referenceIssueId#" + i)
          .writeDate("createdTime", Calendar.getInstance().getTime())
          .create();
      PdxInstance validationIssueXRefPdx = cache
          
.createPdxInstanceFactory("org.apache.geode.test.OrderValidationIssueXRef")
          .writeString("validationIssueXRefID", "validationIssueXRefID#" + i)
          .writeString("referenceIssueId", "validationIssueID2#" + i)
          .writeString("referenceOrderId", "orderId#2" + i)
          .writeInt("referenceOrderVersion", i)
          .create();

      orderRegion.put("orderId#" + i, orderPdx);
      validationIssueRegion.put("issueId#" + i , validationIssuePdx );
      validationIssueXRefRegion.put("validationIssueXRefID#" + i, 
validationIssueXRefPdx);
    }
  }

  @Test
  public void 
joiningThreeRegionsWhenIntermediateResultSizeIsHigherThanLimitClauseShouldNotTrimResults()
 throws Exception {
    int matches = 10;
    int extraEntitiesPerRegion = 25;
    Cache cache = CacheUtils.getCache();
    QueryService queryService = cache.getQueryService();
    String queryString = "SELECT issue.issueId, issue.createdTime, o.orderId, 
o.version "
        + "FROM /ValidationIssue issue, /OrderValidationIssueXRef xRef, /Order 
o "
        + "WHERE "
        + "issue.issueId = xRef.referenceIssueId "
        + "AND "
        + "xRef.referenceOrderId = o.orderId "
        + "AND "
        + "xRef.referenceOrderVersion = o.version ";

    try {
      Region<String, Object> orderRegion = cache.<String, 
Object>createRegionFactory()
          .setDataPolicy(DataPolicy.REPLICATE).create("Order");
      Region<String, Object> validationIssueRegion = cache.<String, 
Object>createRegionFactory()
          .setDataPolicy(DataPolicy.REPLICATE).create("ValidationIssue");
      Region<String, Object> validationIssueXRefRegion = cache.<String, 
Object>createRegionFactory()
          
.setDataPolicy(DataPolicy.REPLICATE).create("OrderValidationIssueXRef");

        populateTripleJointRegions(matches, extraEntitiesPerRegion, 
orderRegion, validationIssueRegion, validationIssueXRefRegion);

      SelectResults baseResults = (SelectResults) 
queryService.newQuery(queryString).execute();
      SelectResults resultsWithLimitOne = (SelectResults) 
queryService.newQuery(queryString + "LIMIT 2").execute();
      SelectResults resultsWithLimitTwo = (SelectResults) 
queryService.newQuery(queryString  + "LIMIT 5").execute();
      assertThat(baseResults.size()).isEqualTo(matches);
      assertThat(resultsWithLimitOne.size()).isEqualTo(2);
      assertThat(resultsWithLimitTwo.size()).isEqualTo(5);

      // Add Indexes and test again
      cache.getQueryService().createIndex("order_orderID", "orderId", "/Order", 
null);
      cache.getQueryService().createIndex("validationIssue_issueID", "issueId", 
"/ValidationIssue", null);
      
cache.getQueryService().createIndex("orderValidationIssueXRef_referenceOrderId",
 "referenceOrderId", "/OrderValidationIssueXRef", null);
      
cache.getQueryService().createIndex("orderValidationIssueXRef_referenceIssueId",
 "referenceIssueId", "/OrderValidationIssueXRef", null);

      SelectResults baseResultsWithIndexes = (SelectResults) 
queryService.newQuery(queryString).execute();
      SelectResults resultsWithLimitOneWithIndexes = (SelectResults) 
queryService.newQuery(queryString + "LIMIT 2").execute();
      SelectResults resultsWithLimitTwoWithIndexes = (SelectResults) 
queryService.newQuery(queryString  + "LIMIT 5").execute();
      assertThat(baseResultsWithIndexes.size()).isEqualTo(matches);

     // FAIL: the actual size will be 0 in both cases.
      assertThat(resultsWithLimitOneWithIndexes.size()).isEqualTo(2);
      assertThat(resultsWithLimitTwoWithIndexes.size()).isEqualTo(5);
    } finally {
      cache.getRegion("Order").destroyRegion();
      cache.getRegion("ValidationIssue").destroyRegion();
      cache.getRegion("OrderValidationIssueXRef").destroyRegion();
    }
  }
{code}






--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to