Cayenne
  1. Cayenne
  2. CAY-1514

ClassCastException when EJQLQuery parameters is null.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.0.1
    • Fix Version/s: 3.0.3, 3.1M3
    • Component/s: Core Library
    • Labels:
      None
    • Environment:
      Tomcat 6.0.26

      Description

      When a parameter in EJBQLQuery is set to null, an error occurs which results in ClassCastException. When parameter is not null query is executed as expected.
      It is duplicable with following/similar code:

      EJBQLQuery eq = new EJBQLQuery("SELECT COUNT(u) FROM User u WHERE u.username like :usernam AND u.userInfo.name like :userName");
      eq.setParameter("userName", null);
      eq.setParameter("usernam", "msabo");
      return (Long) DataObjectUtils.objectForQuery(getObjectContext(), eq);

      Full stack trace is in attachment.

      1. cayST.txt
        6 kB
        Marek Šabo
      2. ejbql-null-parameters.patch
        2 kB
        Dzmitry Kazimirchyk
      3. test.patch
        1 kB
        Dzmitry Kazimirchyk

        Activity

        Hide
        Marek Šabo added a comment -

        Full stack trace of thrown exception.

        Show
        Marek Šabo added a comment - Full stack trace of thrown exception.
        Hide
        Ksenia Khailenko added a comment -

        That is because when EJBQLConditionsTranslator processes the NamedParameter and sees the null value, it expects to see "equals" condition, not "like": EJBQLConditionsTranslator [838-844]

        Show
        Ksenia Khailenko added a comment - That is because when EJBQLConditionsTranslator processes the NamedParameter and sees the null value, it expects to see "equals" condition, not "like": EJBQLConditionsTranslator [838-844]
        Hide
        Dzmitry Kazimirchyk added a comment -

        LIKE expression's parameters are always parsed into PatternValue objects which I think is the reason of the issue.
        I suppose we can change grammar for parser generator to fix this.
        I've added unit test and patch for trunk, for 3.0 branch it works the same way.

        Show
        Dzmitry Kazimirchyk added a comment - LIKE expression's parameters are always parsed into PatternValue objects which I think is the reason of the issue. I suppose we can change grammar for parser generator to fix this. I've added unit test and patch for trunk, for 3.0 branch it works the same way.
        Hide
        Andrus Adamchik added a comment -

        The test case demonstrates a problem, albeit it seems to be a different one (NPE vs. ClassCastException) :

        Caused by: java.lang.NullPointerException
        at org.apache.cayenne.access.jdbc.EJBQLPathTranslator.processLastPathComponent(EJBQLPathTranslator.java:190)
        at org.apache.cayenne.access.jdbc.EJBQLPathAnaliserTranslator.visitPath(EJBQLConditionTranslator.java:1181)
        at org.apache.cayenne.access.jdbc.EJBQLConditionTranslator.processParameter(EJBQLConditionTranslator.java:852)
        at org.apache.cayenne.access.jdbc.EJBQLConditionTranslator.visitPositionalInputParameter(EJBQLConditionTranslator.java:773)
        at org.apache.cayenne.ejbql.parser.EJBQLPositionalInputParameter.visitNode(EJBQLPositionalInputParameter.java:34)

        I wonder if we have 2 separate problems at hand, and need an extra test case to reproduce the one described by the Jira reporter. One difference with the test case (that may or may not be relevant) is that path matched against NULL is multi-part, traversing the relationship.

        Re: .jjt patch: I am confused about the assymetry between these 2 chunks:

        @@ -693,7 +693,8 @@ void literal_or_param() : { }

        void like_expression() #Like : { }
        {

        • string_expression() [<NOT> { jjtThis.not = true; }] <LIKE> pattern_value()
          + string_expression() [<NOT> { jjtThis.not = true; }

          ] <LIKE>
          + ((input_parameter() [(<ESCAPE> escape_character())]) | pattern_value())
          }

        and

        @ -1208,8 +1209,7 @@ void positional_input_parameter() #PositionalInputParameter :

        void pattern_value() #PatternValue : { }

        { - (input_parameter() | string_literal()) - [(<ESCAPE> escape_character())] + string_literal() [(<ESCAPE> escape_character())] }

        Could you explain the fix?

        Show
        Andrus Adamchik added a comment - The test case demonstrates a problem, albeit it seems to be a different one (NPE vs. ClassCastException) : Caused by: java.lang.NullPointerException at org.apache.cayenne.access.jdbc.EJBQLPathTranslator.processLastPathComponent(EJBQLPathTranslator.java:190) at org.apache.cayenne.access.jdbc.EJBQLPathAnaliserTranslator.visitPath(EJBQLConditionTranslator.java:1181) at org.apache.cayenne.access.jdbc.EJBQLConditionTranslator.processParameter(EJBQLConditionTranslator.java:852) at org.apache.cayenne.access.jdbc.EJBQLConditionTranslator.visitPositionalInputParameter(EJBQLConditionTranslator.java:773) at org.apache.cayenne.ejbql.parser.EJBQLPositionalInputParameter.visitNode(EJBQLPositionalInputParameter.java:34) I wonder if we have 2 separate problems at hand, and need an extra test case to reproduce the one described by the Jira reporter. One difference with the test case (that may or may not be relevant) is that path matched against NULL is multi-part, traversing the relationship. Re: .jjt patch: I am confused about the assymetry between these 2 chunks: @@ -693,7 +693,8 @@ void literal_or_param() : { } void like_expression() #Like : { } { string_expression() [<NOT> { jjtThis.not = true; }] <LIKE> pattern_value() + string_expression() [<NOT> { jjtThis.not = true; } ] <LIKE> + ((input_parameter() [(<ESCAPE> escape_character())] ) | pattern_value()) } and @ -1208,8 +1209,7 @@ void positional_input_parameter() #PositionalInputParameter : void pattern_value() #PatternValue : { } { - (input_parameter() | string_literal()) - [(<ESCAPE> escape_character())] + string_literal() [(<ESCAPE> escape_character())] } Could you explain the fix?
        Hide
        Dzmitry Kazimirchyk added a comment -

        This issue produces ClassCastException for 3.0.x (like in description) and produces NPE for 3.1 version. But the reason of this is the same I suppose.
        Any NamedInputParameter according to the current grammar matches PatternValue. So when we use named input parameters in the query parser produces PatternValue object for them and we are getting ClassCastException trying to cast them into NamedInputParameter.
        So I've changed parser grammar this way to avoid treating NamedInputParameters as PatternValues.

        Show
        Dzmitry Kazimirchyk added a comment - This issue produces ClassCastException for 3.0.x (like in description) and produces NPE for 3.1 version. But the reason of this is the same I suppose. Any NamedInputParameter according to the current grammar matches PatternValue. So when we use named input parameters in the query parser produces PatternValue object for them and we are getting ClassCastException trying to cast them into NamedInputParameter. So I've changed parser grammar this way to avoid treating NamedInputParameters as PatternValues.
        Hide
        Andrus Adamchik added a comment -

        Sorry couldn't think clearly last night. Thanks for the explanation. It makes sense. Now I finally recall why it didn't work in the first place - JPA spec that was used for the original EJBQL grammar does not support input parameters in the LIKE expression, and is vague on null handling ("If the value of the string_expression or pattern_value is NULL or unknown, the value of the LIKE expression is unknown.")... Now we are departing from it in these edge cases.

        Show
        Andrus Adamchik added a comment - Sorry couldn't think clearly last night. Thanks for the explanation. It makes sense. Now I finally recall why it didn't work in the first place - JPA spec that was used for the original EJBQL grammar does not support input parameters in the LIKE expression, and is vague on null handling ("If the value of the string_expression or pattern_value is NULL or unknown, the value of the LIKE expression is unknown.")... Now we are departing from it in these edge cases.

          People

          • Assignee:
            Unassigned
            Reporter:
            Marek Šabo
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development