-
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]
-
Proposal:Hide
In the following rules null means either a null literal or a null value
null eq null is true
null ne null is falsenotnull eq null is false
notnull ne null is truenull le null is true --> mathematically consistent with the preceding rules and how JavaScript and Python work, but differs from C# and SQL
null ge null is true --> mathematically consistent with the preceding rules and how JavaScript and Python work, but differs from C# and SQL
notnull le null is false
notnull ge null is false
null le notnull is false
null ge notnull is falsenull lt null is false
null gt null is false
notnull lt null is false
notnull gt null is false
null lt notnull is false
null gt notnull is falsenull in logical operators is treated as unknown, see Kleene logic:
null and null is null
null and false is false
null and true is nullnull or null is null
null or true is true
null or false is nullnot null is null
$filter only returns items where the expression evaluates to true and omits items where it evaluates to false or to null
ShowIn the following rules null means either a null literal or a null value null eq null is true null ne null is false notnull eq null is false notnull ne null is true null le null is true --> mathematically consistent with the preceding rules and how JavaScript and Python work, but differs from C# and SQL null ge null is true --> mathematically consistent with the preceding rules and how JavaScript and Python work, but differs from C# and SQL notnull le null is false notnull ge null is false null le notnull is false null ge notnull is false null lt null is false null gt null is false notnull lt null is false notnull gt null is false null lt notnull is false null gt notnull is false null in logical operators is treated as unknown, see Kleene logic: null and null is null null and false is false null and true is null null or null is null null or true is true null or false is null not null is null $filter only returns items where the expression evaluates to true and omits items where it evaluates to false or to null -
Resolution:Hide
https://www.oasis-open.org/committees/download.php/49613/odata-v4.0-wd02-part1-protocol-2013-06-19.docx
https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/vocabularies/Org.OData.Core.V1.xml?rev=377
https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/vocabularies/Org.OData.Capabilities.V1.xml?rev=379https://www.oasis-open.org/committees/download.php/49614/odata-v4.0-wd02-part2-url-conventions-2013-06-19.docx
https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/ABNF/odata-abnf-construction-rules.txt?rev=380
https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/ABNF/odata-abnf-testcases.xml?rev=380https://www.oasis-open.org/committees/download.php/49615/odata-v4.0-wd02-part3-csdl-2013-06-19.docx
https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/schemas/edmx.xsd?rev=357
https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/schemas/edm.xsd?rev=377
https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/schemas/MetadataService.edmx?rev=374https://www.oasis-open.org/committees/download.php/49611/odata-atom-format-v4.0-wd02-2013-06-19.docx
https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/schemas/metadata.xsd?rev=382https://www.oasis-open.org/committees/download.php/49612/odata-json-format-v4.0-wd02-2013-06-19.docx
Showhttps://www.oasis-open.org/committees/download.php/49613/odata-v4.0-wd02-part1-protocol-2013-06-19.docx https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/vocabularies/Org.OData.Core.V1.xml?rev=377 https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/vocabularies/Org.OData.Capabilities.V1.xml?rev=379 https://www.oasis-open.org/committees/download.php/49614/odata-v4.0-wd02-part2-url-conventions-2013-06-19.docx https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/ABNF/odata-abnf-construction-rules.txt?rev=380 https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/ABNF/odata-abnf-testcases.xml?rev=380 https://www.oasis-open.org/committees/download.php/49615/odata-v4.0-wd02-part3-csdl-2013-06-19.docx https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/schemas/edmx.xsd?rev=357 https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/schemas/edm.xsd?rev=377 https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/schemas/MetadataService.edmx?rev=374 https://www.oasis-open.org/committees/download.php/49611/odata-atom-format-v4.0-wd02-2013-06-19.docx https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/schemas/metadata.xsd?rev=382 https://www.oasis-open.org/committees/download.php/49612/odata-json-format-v4.0-wd02-2013-06-19.docx
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)
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.
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.
I'd go for your proposal 1), it's easier to understand.
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.
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.
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.
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.
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).
Matthew and Mike will prepare a proposal for the January F2F in Zürich
Accepted in F2F 2013-06-13
Accepted on 2013-06-20
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.