Details

    • Type: Bug
    • Status: Closed
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: V4.0_WD01
    • Fix Version/s: V4.0_WD01
    • Component/s: URL Conventions
    • Labels:
      None
    • Environment:

      [Applied]

      Description

      I didn't see any mention of lifted operators in the working drafts. We should define how each operator behaves when one (or both) operands is null.

      With that said, the V3 spec (section 2.2.3.6.1.1.5) is inconsistent with it's treatment of null:

      • For equality operators, null eq null is true and null eq <anything not null> is false (i.e. the result is true or false)
      • Any relational operators when compared with null are false (i.e. the result is true or false)
      • This implies that null ge null and null le null is false which is inconsistent with null eq null is true
      • Logical operators treat null as false (i.e. the result is true or false)
      • Unary operators are null if the operand is null (i.e. in the case of not, the result is true, false, or null)

        Attachments

          Activity

          Hide
          mikep Michael Pizzo (Inactive) added a comment -

          I think we should differentiate between null values and the null literal that we use to evaluate null.

          The null literal isn't really a value, it is ONLY used in an expression to see if a value is null. "eq null" is really an operator, equivalent to "is null" in ansi sql. It's nice to think of it as an operand in that you don't need a separate "is" operator, and you can put it on either side of the eq operator, but it is not a value.
          -The null literal cannot be used in relational operators (gt, ge, lt, le). (i.e., Name ge null is invalid)
          -The null literal cannot be used as a Boolean value (i.e., null and true is invalid)
          -Null values can be compared to the null literal; <nullvalue> eq null is true for all null values, false for all non-null values.
          -Null values compared to any value other than the null literal is false.

          This definition makes it easy to understand null treatment and express null comparisons in a request without having to define rules for handling meaningless cases.

          Show
          mikep Michael Pizzo (Inactive) added a comment - I think we should differentiate between null values and the null literal that we use to evaluate null. The null literal isn't really a value, it is ONLY used in an expression to see if a value is null. "eq null" is really an operator, equivalent to "is null" in ansi sql. It's nice to think of it as an operand in that you don't need a separate "is" operator, and you can put it on either side of the eq operator, but it is not a value. -The null literal cannot be used in relational operators (gt, ge, lt, le). (i.e., Name ge null is invalid) -The null literal cannot be used as a Boolean value (i.e., null and true is invalid) -Null values can be compared to the null literal; <nullvalue> eq null is true for all null values, false for all non-null values. -Null values compared to any value other than the null literal is false. This definition makes it easy to understand null treatment and express null comparisons in a request without having to define rules for handling meaningless cases.
          Hide
          matthew.borges Matthew Borges (Inactive) added a comment -

          If "eq null" is really an operator then I think we need to be explicit about that in the documentation.

          My original description wasn't clear with regard to the null literal and null value. To clarify, I was overloading "null" to mean both a null literal and a null value.

          The issue I was trying to bring up was the inconsistent use of 2-value and 3-value logic (with respect to operators whose outcome is a boolean value). The last comment implies the result of comparison operators is always true or false. To be consistent, the results of boolean operators should also be true or false. Then I still think that "not <nullvalue>" should be true for consistency:

          E.g. Let's say b1 is a boolean property with a null value. If "b1 and b1" is false then "not ( b1 and b1 )" should be true, which implies "not b1" should be true.

          This is different than a database but a database uses 3-value logic. So taking the above example "b1 and b1" is null and "not ( b1 and b1 )" is null so the result is consistent.

          Show
          matthew.borges Matthew Borges (Inactive) added a comment - If "eq null" is really an operator then I think we need to be explicit about that in the documentation. My original description wasn't clear with regard to the null literal and null value. To clarify, I was overloading "null" to mean both a null literal and a null value. The issue I was trying to bring up was the inconsistent use of 2-value and 3-value logic (with respect to operators whose outcome is a boolean value). The last comment implies the result of comparison operators is always true or false. To be consistent, the results of boolean operators should also be true or false. Then I still think that "not <nullvalue>" should be true for consistency: E.g. Let's say b1 is a boolean property with a null value. If "b1 and b1" is false then "not ( b1 and b1 )" should be true, which implies "not b1" should be true. This is different than a database but a database uses 3-value logic. So taking the above example "b1 and b1" is null and "not ( b1 and b1 )" is null so the result is consistent.
          Hide
          matthew.borges Matthew Borges (Inactive) added a comment -

          I thought about this a little bit more and re-read the V2 and V3 spec to see what they say about eq and null and just want to comment on a couple of things:

          1) The V2 and V3 spec both say that two null values are equal (see section 2.2.3.6.1.1.5) so the new proposal is inconsistent with older versions of the spec (I'm not saying that is necessarily a problem I am just mentioning it). Neither the ABNF (in V2 or V3) nor the description of the eq operator place any special meaning on whether a null literal is used or a null value or restrict the null literal from being used with ge, le, lt, gt, etc.

          2) I think overloading the eq operator to mean something special when the right hand operand is the null literal has some unintuitive properties. For example, if b1 is a property with a null value, the last proposed definition of eq, ge, and le means:

          b1 eq null is true
          b1 eq b1 is false
          b1 le b1 is false
          b1 ge b1 is false

          I think it would be more clear if we define the operators to be one of these two things:

          1)

          • <nullvalue> eq null is true and <nullvalue> eq <nullvalue> is true
          • <nullvalue> ge null is true and <nullvalue> ge <nullvalue> is true.
          • <nullvalue> le null is true and <nullvalue> le <nullvalue> is true.
          • All other comparison where either operand is a null literal or <nullvalue> are false.

          OR

          2) Comparing the null literal or <nullvalue> with eq, ge, ne, le, etc. is always false, and introduce an operator, is, like SQL for dealing with nulls.

          Show
          matthew.borges Matthew Borges (Inactive) added a comment - I thought about this a little bit more and re-read the V2 and V3 spec to see what they say about eq and null and just want to comment on a couple of things: 1) The V2 and V3 spec both say that two null values are equal (see section 2.2.3.6.1.1.5) so the new proposal is inconsistent with older versions of the spec (I'm not saying that is necessarily a problem I am just mentioning it). Neither the ABNF (in V2 or V3) nor the description of the eq operator place any special meaning on whether a null literal is used or a null value or restrict the null literal from being used with ge, le, lt, gt, etc. 2) I think overloading the eq operator to mean something special when the right hand operand is the null literal has some unintuitive properties. For example, if b1 is a property with a null value, the last proposed definition of eq, ge, and le means: b1 eq null is true b1 eq b1 is false b1 le b1 is false b1 ge b1 is false I think it would be more clear if we define the operators to be one of these two things: 1) <nullvalue> eq null is true and <nullvalue> eq <nullvalue> is true <nullvalue> ge null is true and <nullvalue> ge <nullvalue> is true. <nullvalue> le null is true and <nullvalue> le <nullvalue> is true. All other comparison where either operand is a null literal or <nullvalue> are false. OR 2) Comparing the null literal or <nullvalue> with eq, ge, ne, le, etc. is always false, and introduce an operator, is, like SQL for dealing with nulls.
          Hide
          ralfhandl Ralf Handl added a comment -

          I'd go for your proposal 1), it's easier to understand.

          Show
          ralfhandl Ralf Handl added a comment - I'd go for your proposal 1), it's easier to understand.
          Hide
          mikep Michael Pizzo (Inactive) added a comment -

          Maybe it's my database bias, but saying that two null values are equal seems wrong to me. I would not expect a query for EyeColor eq HairColor to return records where both EyeColor and HairColor were not specified – by definition, the value of a null valued property is unknown, not known to be equal to another unknown value.

          I am okay adding an is operator, as in SQL, to be used with Null if people think that makes things more clear, although I'm also fine clarifying the use of Null with the eq operator to avoid introducing another operator.

          Show
          mikep Michael Pizzo (Inactive) added a comment - Maybe it's my database bias, but saying that two null values are equal seems wrong to me. I would not expect a query for EyeColor eq HairColor to return records where both EyeColor and HairColor were not specified – by definition, the value of a null valued property is unknown, not known to be equal to another unknown value. I am okay adding an is operator, as in SQL, to be used with Null if people think that makes things more clear, although I'm also fine clarifying the use of Null with the eq operator to avoid introducing another operator.
          Hide
          matthew.borges Matthew Borges (Inactive) added a comment -

          From a database point of view, saying two unknown values are not equal is just as wrong as saying two unknown values are equal. We can avoid this if we use 3-value logic in a $filter, so the outcome of every logical operator (not, and, or, comparison, equality) is true, false, or unknown.

          Show
          matthew.borges Matthew Borges (Inactive) added a comment - From a database point of view, saying two unknown values are not equal is just as wrong as saying two unknown values are equal. We can avoid this if we use 3-value logic in a $filter, so the outcome of every logical operator (not, and, or, comparison, equality) is true, false, or unknown.
          Hide
          mikep Michael Pizzo (Inactive) added a comment -

          The problem with 3-value logic, or with having a different operator for null, is that it makes building predicates that account for null values much harder.

          For example, a query to see if a certain item had changed might build a query with a predicate checking to see if each property is equal to the previously fetched value; for example, the predicate:

          $filter=FirstName eq 'Matthew' and LastName eq 'Borges' and Company eq 'SAP'

          could easily be built by looping through the properties and writing propertyName "eq" value.

          Parameterized, you could write a single predicate that would work for any entity in the entityset:

          String.Format("FirstName eq '

          {0}

          ' and LastName eq '

          {1}

          ' and Company eq '

          {2}

          '", record.FirstName, record.LastName, record.Company)

          This works for null values of FirstName, LastName, and Company IFyou support <nullvalue> eq null. However, if you need a special "is null" operator, or if comparing null values is always unknown, you have to understand, contemplate, and write significantly more logic to deal with potential null values.

          Show
          mikep Michael Pizzo (Inactive) added a comment - The problem with 3-value logic, or with having a different operator for null, is that it makes building predicates that account for null values much harder. For example, a query to see if a certain item had changed might build a query with a predicate checking to see if each property is equal to the previously fetched value; for example, the predicate: $filter=FirstName eq 'Matthew' and LastName eq 'Borges' and Company eq 'SAP' could easily be built by looping through the properties and writing propertyName "eq" value. Parameterized, you could write a single predicate that would work for any entity in the entityset: String.Format("FirstName eq ' {0} ' and LastName eq ' {1} ' and Company eq ' {2} '", record.FirstName, record.LastName, record.Company) This works for null values of FirstName, LastName, and Company IFyou support <nullvalue> eq null. However, if you need a special "is null" operator, or if comparing null values is always unknown, you have to understand, contemplate, and write significantly more logic to deal with potential null values.
          Hide
          matthew.borges Matthew Borges (Inactive) added a comment -

          I 100% agree with that; 3-value logic definitely complicates things. And if one of the goals of OData is to keep things simple, 3-value logic is probably not the correct approach to take.

          I am definitely fine with using 2-value logic as long as we make the results consistent. In which case I still think proposal 1) from the post on "16/Dec/12 04:47 PM" has the most consistent treatment of nulls and simplest to understand.

          Show
          matthew.borges Matthew Borges (Inactive) added a comment - I 100% agree with that; 3-value logic definitely complicates things. And if one of the goals of OData is to keep things simple, 3-value logic is probably not the correct approach to take. I am definitely fine with using 2-value logic as long as we make the results consistent. In which case I still think proposal 1) from the post on "16/Dec/12 04:47 PM" has the most consistent treatment of nulls and simplest to understand.
          Hide
          mikep Michael Pizzo (Inactive) added a comment -

          I've tried over the past 2 weeks to come to terms with the proposal, but I still have a fundamental problem accepting the idea of null = null.

          I think it's easiest, and "least astonishing" to the user to say that:

          <null value> eq null is true (I can test for null)
          <null value> eq <null value> is false (two nulls values are defined to be not equal)

          and that the null literal cannot be used with any other comparison operators (it doesn't make sense to compare something as less than or greater than null).

          Show
          mikep Michael Pizzo (Inactive) added a comment - I've tried over the past 2 weeks to come to terms with the proposal, but I still have a fundamental problem accepting the idea of null = null. I think it's easiest, and "least astonishing" to the user to say that: <null value> eq null is true (I can test for null) <null value> eq <null value> is false (two nulls values are defined to be not equal) and that the null literal cannot be used with any other comparison operators (it doesn't make sense to compare something as less than or greater than null).
          Hide
          ralfhandl Ralf Handl added a comment -

          Matthew and Mike will prepare a proposal for the January F2F in Zürich

          Show
          ralfhandl Ralf Handl added a comment - Matthew and Mike will prepare a proposal for the January F2F in Zürich
          Hide
          ralfhandl Ralf Handl added a comment -

          Accepted in F2F 2013-06-13

          Show
          ralfhandl Ralf Handl added a comment - Accepted in F2F 2013-06-13
          Hide
          ralfhandl Ralf Handl added a comment -

          Accepted on 2013-06-20

          Show
          ralfhandl Ralf Handl added a comment - Accepted on 2013-06-20

            People

            • Assignee:
              handl Ralf Handl
              Reporter:
              matthew.borges Matthew Borges (Inactive)
            • Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: