Uploaded image for project: 'Calcite'
  1. Calcite
  2. CALCITE-2894

NullPointerException thrown by RelMdPercentageOriginalRows when explaining plan with all attributes

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: 1.18.0
    • Fix Version/s: 1.19.0
    • Component/s: None

      Description

      RelMdPercentageOriginalRows methods use several times double variables to store the result of getPercentageOriginalRows. However, this method returns an object Double, as RelMetadataQuery#getPercentageOriginalRows javadoc says: "return estimated percentage (between 0.0 and 1.0), or null if no reliable estimate can be determined".
      Therefore, null can (and will) be returned in some cases, leading to NullPointerException, for example here:

        public Double getPercentageOriginalRows(Union rel, RelMetadataQuery mq) {
          double numerator = 0.0;
          double denominator = 0.0;
          for (RelNode input : rel.getInputs()) {
            double rowCount = mq.getRowCount(input);
            double percentage = mq.getPercentageOriginalRows(input);  // !!! NullPointerException
            if (percentage != 0.0) {
              denominator += rowCount / percentage;
              numerator += rowCount;
            }
          }
          return quotientForPercentage(numerator, denominator);
        }
      

      In my case, I arrived to this situation by explaining a plan (including all attributes) that contained a SemiJoin, with an Union inside, with a Correlate inside:

        @Test public void testExplainAllAttributesSemiJoinUnionCorrelate() {
          CalciteAssert.that()
                  .with(CalciteConnectionProperty.LEX, Lex.JAVA)
                  .with(CalciteConnectionProperty.FORCE_DECORRELATE, false)
                  .withSchema("s", new ReflectiveSchema(new JdbcTest.HrSchema()))
                  .query(
                          "select deptno, name from depts where deptno in (\n"
                                  + " select e.deptno from emps e where exists (select 1 from depts d where d.deptno=e.deptno)\n"
                                  + " union select e.deptno from emps e where e.salary > 10000) ")
                  .explainMatches("including all attributes ",
                          CalciteAssert.checkResultContains("EnumerableSemiJoin"));
        }
      

        Attachments

        1. exception.txt
          5 kB
          Ruben Q L

          Issue Links

            Activity

              People

              • Assignee:
                rubenql Ruben Q L
                Reporter:
                rubenql Ruben Q L
              • Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 20m
                  20m