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

Enumerable gives NullPointerException with NOT on nullable expression

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.0.0-incubating
    • Component/s: None
    • Labels:

      Description

      Foodmart query #6597

      select "store"."store_country" as "c0",
       "store"."store_state" as "c1",
       "store"."store_city" as "c2",
       "store"."store_name" as "c3",
       "Store"."store_type" as "c4",
       "store"."store_manager" as "c5",
       "store"."store_sqft" as "c6",
       "store"."grocery_sqft" as "c7",
       "store"."frozen_sqft" as "c8",
       "store"."meat_sqft" as "c9",
       "store"."coffee_bar" as "c10",
       "store"."store_street_address" as "c11"
      from "store" as "store"
      group by "store"."store_country",
       "store"."store_state",
       "store"."store_city",
       "store"."store_name",
       "store"."store_type",
       "store"."store_manager",
       "store"."store_sqft",
       "store"."grocery_sqft",
       "store"."frozen_sqft",
       "store"."meat_sqft",
       "store"."coffee_bar",
       "store"."store_street_address"
      having NOT((((sum("store"."store_sqft") - sum("store"."grocery_sqft")) < 10000)) )
      order by "store"."store_country" ASC NULLS LAST,
       "store"."store_state" ASC NULLS LAST,
       "store"."store_city" ASC NULLS LAST,
       "store"."store_name" ASC NULLS LAST
      

      gives the following stack:

      java.lang.NullPointerException
      	at Baz$6$1.moveNext(Unknown Source)
      	at net.hydromatic.optiq.runtime.ObjectEnumeratorCursor.next(ObjectEnumeratorCursor.java:43)
      	at net.hydromatic.avatica.AvaticaResultSet.next(AvaticaResultSet.java:186)
      	at net.hydromatic.optiq.test.OptiqAssert.countRows(OptiqAssert.java:493)

      More minimal test case:

      select 1
      from "store"
      group by "store_street_address"
      having NOT (sum("grocery_sqft") < 10000)
      

        Activity

        Hide
        snarayanan Sivaramakrishnan Narayanan added a comment -

        Taking a shot at this.

        Show
        snarayanan Sivaramakrishnan Narayanan added a comment - Taking a shot at this.
        Hide
        snarayanan Sivaramakrishnan Narayanan added a comment -

        My understanding so far is that line 135 has the problem since inputEnumerator.current()[1] could be null.

        /* 133 */             public boolean moveNext() {
        /* 134 */               while (inputEnumerator.moveNext()) {
        /* 135 */                 if ((Integer) ((Object[]) inputEnumerator.current())[1] >= Integer.valueOf(10000)) {
        /* 136 */                   return true;
        /* 137 */                 }
        /* 138 */               }
        /* 139 */               return false;
        /* 140 */             }
        /* 141 */ 
        
        Show
        snarayanan Sivaramakrishnan Narayanan added a comment - My understanding so far is that line 135 has the problem since inputEnumerator.current() [1] could be null. /* 133 */ public boolean moveNext() { /* 134 */ while (inputEnumerator.moveNext()) { /* 135 */ if (( Integer ) (( Object []) inputEnumerator.current())[1] >= Integer .valueOf(10000)) { /* 136 */ return true ; /* 137 */ } /* 138 */ } /* 139 */ return false ; /* 140 */ } /* 141 */
        Hide
        snarayanan Sivaramakrishnan Narayanan added a comment -

        Changing the query by removing the NOT

        select 1
        from "store"
        group by "store_street_address"
        having (sum("grocery_sqft") < 10000)
        

        produces this code block:

        /* 133 */             public boolean moveNext() {
        /* 134 */               while (inputEnumerator.moveNext()) {
        /* 135 */                 final Integer inp1_ = (Integer) ((Object[]) inputEnumerator.current())[1];
        /* 136 */                 if (inp1_ != null && inp1_.intValue() < 10000) {
        /* 137 */                   return true;
        /* 138 */                 }
        /* 139 */               }
        /* 140 */               return false;
        /* 141 */             }
        

        There seems to be a safety check for nullness.

        Show
        snarayanan Sivaramakrishnan Narayanan added a comment - Changing the query by removing the NOT select 1 from "store" group by "store_street_address" having (sum( "grocery_sqft" ) < 10000) produces this code block: /* 133 */ public boolean moveNext() { /* 134 */ while (inputEnumerator.moveNext()) { /* 135 */ final Integer inp1_ = ( Integer ) (( Object []) inputEnumerator.current())[1]; /* 136 */ if (inp1_ != null && inp1_.intValue() < 10000) { /* 137 */ return true ; /* 138 */ } /* 139 */ } /* 140 */ return false ; /* 141 */ } There seems to be a safety check for nullness.
        Hide
        julianhyde Julian Hyde added a comment -

        You're right. It's a problem with NOT's handling of nulls. I managed to reproduce it without HAVING: 'WHERE NOT (store.grocery_sqft < 1000)".

        Show
        julianhyde Julian Hyde added a comment - You're right. It's a problem with NOT's handling of nulls. I managed to reproduce it without HAVING: 'WHERE NOT (store.grocery_sqft < 1000)".
        Show
        julianhyde Julian Hyde added a comment - Fixed in http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/de0bfaad .
        Hide
        snarayanan Sivaramakrishnan Narayanan added a comment -

        Julian - would the fix work for the following cases:

        Select not x from foo (where x is nullable)
        Select * from foo where not x is null (where x is nullable)

        Show
        snarayanan Sivaramakrishnan Narayanan added a comment - Julian - would the fix work for the following cases: Select not x from foo (where x is nullable) Select * from foo where not x is null (where x is nullable)
        Show
        vladimirsitnikov Vladimir Sitnikov added a comment - The fix works. Added those cases in https://git-wip-us.apache.org/repos/asf?p=incubator-calcite.git;a=commitdiff;h=d4b80bf93f28d8aac8b1997d0b8bee2da84fb99c
        Hide
        julianhyde Julian Hyde added a comment -

        Closing now that 1.0.0-incubating has been released.

        Show
        julianhyde Julian Hyde added a comment - Closing now that 1.0.0-incubating has been released.

          People

          • Assignee:
            julianhyde Julian Hyde
            Reporter:
            julianhyde Julian Hyde
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development