OData TC meeting #180 Thursday July 06, 2017

Acting chair: Ralf

Chat transcript from room: odatatc
2017-0706 800-1000 PDT

1. Roll call

1.1 Members present

    George Ericson (Dell)
    Hubert Heijkers (IBM)
    Mark Biamonte (Progress Software)
    Martin Zurmuehl (SAP SE)
    Matthew Borges (SAP SE) a.k.a. Matt
    Michael Pizzo (IBM) a.k.a. Mike
    Ralf Handl (SAP SE)
    Ramesh Reddy (Red Hat)
    Stefan Hagen (Individual)

Quorum achieved. Details cf. normative attendance sheet for this meeting (event_id=43985).

Notes taken by all and subsequently edited for readability by Stefan.

2. Approve agenda

Ralf: 5.Version 4.01 Public Review - 05 July 2017 to 03 August 2017
a.Issues
i.ODATA-1090 Clarify text about referential constraint for navigation properties on complex types
ii.ODATA-1091 Special values of numeric types (public comment c201707e0002)

Agenda is approved as published with above additions.

3. Approve minutes from previous meeting(s)

3.1 Minutes from June 29, 2017 TC meeting #179

https://www.oasis-open.org/committees/download.php/61109/odata-meeting-179_on-20170629-minutes.html

Minutes approved unchanged as published.

4. Review action items [Link to Action item list]

4.1 Action items due

None

5. Version 4.01 Public Review - 05 July 2017 to 03 August 2017 - Issues

5.1 ODATA-1090 - Clarify text about referential constraint for navigation properties on complex types

Ralf: TC-Comments mailing list archive: https://lists.oasis-open.org/archives/odata-comment/

Ralf: Use "dependent instance" and point out that referential constraints can only be defined for properties "next" to the navigation property, i.e. paths in the Property attribute are resolved starting at the structured type declaring the navigation property.

Ralf: ODATA-1090 is OPEN

Mike: I move we resolve ODATA-1090 as proposed. Martin seconds.

Ralf: ODATA-1090 is RESOLVED as proposed

5.2 ODATA-1091 - Special values of numeric types (public comment c201707e0002)

Ralf: Comment on: 4.01 Committee Specification Draft 02 / Public Review Draft 02

One of the new provisions in 4.01 is:

All numeric types allow the special numeric values INF, INF, and NaN

This feels onerous given typical technologies for storing integer numeric types. The ABNF for values of Int16, for example, now reads:

int16Value = [ SIGN ] 1*5DIGIT / nanInfinity ; numbers in the range from -32768 to 32767

Clearly this now requires MORE than 16 bits to store.

Given that the numeric integer types are typically used as keys for entities there are some odd implications too. Clearly the definitions of INF and -INF can still work as they compare equal to themselves and top/tail the value range when ordering. I'm more concerned about NaN which doesn't compare equal to itself, this is likely to cause issues if it is used as the value of an entity key. (I believe PostgreSQL allows these values as keys but treats Nan == Nan as true and Nan > x as true for all x != Nan, this goes against IEEE but seems necessary if they are to be used in context where ordering is required.)

To use XML schema vocab, it feels like the abstract values and lexical representations have become muddled. The desire to use special values in JSON representations of integers has serious implications for the abstract value space.

The 'special' values INF, -INF and NaN are actually values in the abstract value spaces of Single and Double types (as per IEEE, extendable to Decimal). They are not universal special (numeric) values with a status similar to 'null'. It feels like the language of the specification is sliding toward treating all of these in a similar way. Witness the definition of equals in Part 2 5.1.1.1.1

Each of the special values null -INF, and INF is equal to itself, and only to itself.
The special value NaN is not equal to anything, even to itself.

You might find this SO answer in relation to C++ interesting: https://stackoverflow.com/questions/38795544/is-casting-of-infinity-to-integer-undefined I particularly like the parenthetical comment...

truncation of infinity is still infinity, and infinity cannot be represented in int (I hope there's no question about this part)

There's a serious point to this quote though. W.r.t. https://issues.oasis-open.org/browse/ODATA-785 I reject point (2) in the working proposal (add +inf/-inf/nan to int) for this reason.

My proposal is to clarify that the 'special' numeric values are values of type Single, Double or Decimal only. You already have sufficient type promotion to resolve any ambiguity when parsing the literals. For example, the less contentious promotion of the constant parsed from the string "42" to any of the numeric types is already accepted without the special modifiers used in OData 2/3.

The second part of my proposal is that if the abstract result of an operation cannot be represented in the return type defined for that operation then the result should be the special value null. This would include the special case of integer division by zero (where 4.0 says the request fails) but also covers overflow of integers in other operations. I sense the panel dislikes failing requests so my proposal fixes that by silently carrying on - the alternative is to continue to raise an exception or put in some more general provision that says that an _expression_ that fails with a division by zero is treat as null (WITHOUT continuing the computation). The latter version has less of an impact on existing behaviour in 4.0 I guess so might be worth considering.

The NULLIF pattern for treat division by 0 as null is fairly widespread though and it is more consistent with the definition of cast:

5.1.1.10.1

Numeric primitive types are cast to each other with appropriate rounding. The cast fails if the integer
part doesn't fit into target type.
...
If the cast fails, the cast function returns null.

As a follow-up point on your open issue: https://issues.oasis-open.org/browse/ODATA-919

The idea of doing general type promotion to the largest integer type makes sense to me, if the result overflows Int64 then you'd get null (according to my proposal) which is freely castable to any of the integer types.

But I propose that Single operations that overflow Single results should be promoted to Double in a similar way. The definition of cast will need to be modified to allow for the cast of a Double to Single with overflow resulting in INF (not a failed cast). The proposed difference between the way integers and floating point numbers behave in this respect is precisely because the latter can represent INF.

Hope this helps.

Steve Lay
https://www.pyslet.org/

Ralf: ODATA-1091 is OPEN

Ralf: Proposal (extracted from comment):

1) Clarify that the 'special' numeric values are values of type Single, Double or Decimal only. You already have sufficient type promotion to resolve any ambiguity when parsing the literals. For example, the less contentious promotion of the constant parsed from the string "42" to any of the numeric types is already accepted without the special modifiers used in OData 2/3.

2) If the abstract result of an operation cannot be represented in the return type defined for that operation then the result should be the special value null. This would include the special case of integer division by zero (where 4.0 says the request fails) but also covers overflow of integers in other operations.

Mike: maybe distinguish between $filter and $compute

Ralf: $compute should not fail e.g. due to division by zero

Mike: what does SQL do?

Ralf: SQL Anywhere doesn't raise an error but returns no results

Matt: select * from Customers where ( ID / 0 ) is null

Matt: select * from Customers where ( ID / 0 ) is not null

Ramesh: Postgres says ERROR: "division by zero"

Ramesh: same when the expression is in the select clause

Mike: From stack overflow: Select dividend / nullif(divisor, 0)

Ramesh: most of the database vendors

Ramesh: SQLServer yes

Matt: HANA, SQLAnywhere, and UltraLite all support NULLIF

Mark: Oracle and DB2 support NULLIF

Mike: Question: Should we add a nullif operator to the current expression, or mandate it as part of the behavior of the existing div operator?

Mike: I would be concerned about changing behavior of an operation based on protocol version. We are adding a new division operator in 4.01. We could define the nullif behavior for the new operator without breaking compatibility.

Ralf: Proposal:
- no -INF, INF, NaN for integer types
- no -INF, INF for Date and DateTimeOffset
- keep -INF, INF, NaN for Decimal, Float, and Double
- divby returns null for division by zero
- div returns an error for division by zero

Mike: Since divby returns a decimal, should divby zero return NaN?

Ralf: Yes, should

Mike: Wording from 4.01 spec:
If the left operand is numeric, then positive div zero returns INF, negative div zero returns -INF, and zero div zero returns NaN. For 4.0 services this behavior is only required if the left operand is of type Edm.Single or Edm.Double, for all other types the request MAY fail.

Mike: In 4.0, we said that int div zero was an error.

Ralf: Wording from 4.0 spec:
The div operator divides the left numeric operand by the right numeric operand. If the right operand is zero and the left operand is neither of type Edm.Single nor Edm.Double, the request fails. If the left operand is of type Edm.Single or Edm.Double, then positive div zero returns INF, negative div zero returns -INF, and zero div zero returns NaN.

Ralf: We could treat Edm.Decimal(Scale=floating) similar to Double and Single

Ralf: It's new in V4.01 and is a DECFLOAT

Ralf: Only add -INF, INF, and NaN for Edm.Decimal(Scale=floating)

Mike: So proposal is to go back to 4.0 behavior for div 0 (integer fails, decimal, single, and double return INF, -INF, NaN as appropriate), but since divby promotes to decimal it makes sense for it not to fail for divby 0 even if left operand is integer.

Ralf: Postpone issue to next meeting, research whether to treat Edm.Decimal(Scale=floating) similar to Double and Single

6. Issues

6.1 Vocabularies: NEW or OPEN

6.1.1 ODATA-958 - Capabilities: FilterRestrictions and SortRestrictions for navigation properties

Ralf: New proposal:
Add three new properties, FilterFunctions, FilterRestrictions, and SortRestrictions, to Capabilities.NavigationPropertyRestriction, such that the full definition becomes:

<ComplexType Name="NavigationPropertyRestriction"> 
  <Property Type="Edm.NavigationPropertyPath" Name="NavigationProperty"> 
  <Annotation Term="Core.Description" String="Navigation properties can be navigated"/> 
  </Property> 
  <Property Type="Capabilities.NavigationType" Name="Navigability"> 
  <Annotation Term="Core.Description" String="Navigation properties can be navigated to this level"/> 
  </Property> 
  <Property Type="Collection(Edm.String)" Name="FilterFunctions"> 
  <Annotation Term="Core.Description" String="List of functions and operators supported in $filter. If null, all functions and operators may be attempted."/> 
  </Property> 
  <Property Type="Capabilities.FilterRestrictionsType" Name="FilterRestrictions"> 
  <Annotation Term="Core.Description" String="Restrictions on $filter expressions"/> 
  </Property> 
  <Property Type="Capabilities.SortRestrictionsType" Name="SortRestrictions"> 
  <Annotation Term="Core.Description" String="Restrictions on $orderby expressions"/> 
  </Property> 
</ComplexType>

Mike: Here are existing definitions of FilterRestrictionsType and SortRestrictionsType:

<Term AppliesTo="EntityContainer EntitySet" Type="Collection(Edm.String)" Name="FilterFunctions" Nullable="false">
<Annotation Term="Core.Description" String="List of functions and operators supported in $filter"/>
</Term>
<Term AppliesTo="EntitySet Collection" Type="Capabilities.FilterRestrictionsType" Name="FilterRestrictions">
<Annotation Term="Core.Description" String="Restrictions on $filter expressions"/>
</Term>
<ComplexType Name="FilterRestrictionsType">
<Property Type="Edm.Boolean" Name="Filterable" DefaultValue="true">
<Annotation Term="Core.Description" String="$filter is supported"/>
</Property>
<Property Type="Edm.Boolean" Name="RequiresFilter" DefaultValue="false">
<Annotation Term="Core.Description" String="$filter is required"/>
</Property>
<Property Type="Collection(Edm.PropertyPath)" Name="RequiredProperties" Nullable="false">
<Annotation Term="Core.Description" String="These properties must be specified in the $filter clause (properties of derived types are not allowed here)"/>
</Property>
<Property Type="Collection(Edm.AnyPropertyPath)" Name="NonFilterableProperties" Nullable="false">
<Annotation Term="Core.Description" String="These structural or navigation properties cannot be used in $filter expressions"/>
</Property>
<Property Type="Collection(Capabilities.FilterExpressionRestrictionType)" Name="FilterExpressionRestrictions" Nullable="false">
<Annotation Term="Core.Description" String="These properties only allow a subset of expressions"/>
</Property>
<Property Type="Edm.Int32" Name="MaxLevels" DefaultValue="-1">
<Annotation Term="Core.Description" String="The maximum number of levels (including recursion) that can be traversed in a $filter expression. A value of -1 indicates there is no restriction."/>
</Property>
</ComplexType>
<ComplexType Name="FilterExpressionRestrictionType">
<Property Type="Edm.PropertyPath" Name="Property">
<Annotation Term="Core.Description" String="Path to the restricted property"/>
</Property>
<Property Type="Capabilities.FilterExpressionType" Name="AllowedExpressions">
<Annotation Term="Core.Description" String="Allowed subset of expressions"/>
</Property>
</ComplexType>
<TypeDefinition Name="FilterExpressionType" UnderlyingType="Edm.String">
<Annotation Term="Validation.AllowedValues">
<Collection>
<Record>
<PropertyValue String="SingleValue" Property="Value"/>
<Annotation Term="Core.Description" String="Property can be used in a single eq clause"/>
</Record>
<Record>
<PropertyValue String="MultiValue" Property="Value"/>
<Annotation Term="Core.Description" String="Property can be used in a single in clause"/>
</Record>
<Record>
<PropertyValue String="SingleRange" Property="Value"/>
<Annotation Term="Core.Description" String="Property can be used in at most one ge and/or one le clause, separated by and"/>
</Record>
<Record>
<PropertyValue String="SearchExpression" Property="Value"/>
<Annotation Term="Core.Description" String="String property can be used as first operand in startswith, endswith, and contains clauses"/>
</Record>
</Collection>
</Annotation>
</TypeDefinition>
<Term AppliesTo="EntitySet Collection" Type="Capabilities.SortRestrictionsType" Name="SortRestrictions">
<Annotation Term="Core.Description" String="Restrictions on $orderby expressions"/>
</Term>
<ComplexType Name="SortRestrictionsType">
<Property Type="Edm.Boolean" Name="Sortable" DefaultValue="true">
<Annotation Term="Core.Description" String="$orderby is supported"/>
</Property>
<Property Type="Collection(Edm.PropertyPath)" Name="AscendingOnlyProperties" Nullable="false">
<Annotation Term="Core.Description" String="These properties can only be used for sorting in Ascending order"/>
</Property>
<Property Type="Collection(Edm.PropertyPath)" Name="DescendingOnlyProperties" Nullable="false">
<Annotation Term="Core.Description" String="These properties can only be used for sorting in Descending order"/>
</Property>
<Property Type="Collection(Edm.AnyPropertyPath)" Name="NonSortableProperties" Nullable="false">
<Annotation Term="Core.Description" String="These structural or navigation properties cannot be used in $orderby expressions"/>
</Property>
</ComplexType>

George: I move to resolve ODATA-958 as proposed. Hubert seconds.

Ralf: ODATA-958 is RESOLVED as proposed

6.1.2 ODATA-1085 - Decide how to use V4.01 features in OASIS vocabularies

Mike: I move we defer ODATA-1085 and deal with compatibility issues on a case-by-case basis, as they come up. Martin seconds.

Ralf: ODATA-1085 is DEFERRED for now

6.1.3 ODATA-1089 - Org.OData.Aggregation.V1 missing Nullable="false" for Function ReturnType

Ralf: ODATA-1089 is OPEN

George: I move we resolve ODATA-1089 as proposed. Stefan seconds.

Ralf: ODATA-1089 is RESOLVED as proposed

6.1.4 ODATA-1086 - AppliesTo semantics are not normative

Ralf: Description:
The term attribute AppliesTo is documented in section "14.1.2 Applicability" in a way that has been interpreted to mean that the AppliesTo values are merely recommendations. From a specification point of view, this renders the AppliesTo attribute having no semantic value.

I expected that the intent is that AppliesTo values are normative restrictions, but that the set of values may be changed in future versions of the vocabulary.

Ralf: Proposal:

Modify 14.1.2 Applicability as follows:
The AppliesTo attribute MAY be used to restrict a term to a list of model elements that the term may be applied to. If no list is supplied, the term is not intended to be restricted in its application. The list of elements may be extended in future versions of the vocabulary. As the intended usage may evolve over time, clients SHOULD be prepared for any term to be applied to any model element and SHOULD be prepared to handle unknown values within the AppliesTo attribute.

Ralf: ODATA-1086 is OPEN

Mike: I move to resolve ODATA-1086 as proposed. Martin seconds.

Ralf: ODATA-1086 is RESOLVED as proposed

6.1.5 ODATA-1082 - Add term Constraint to Validation vocabulary

Ralf: Proposal:
Add new term

<Term Name="Constraint" 
       Type="Validation.ConstraintType" 
       AppliesTo="Property EntityType ComplexType"> 
  <Annotation Term="Core.Description" String="Condition that the annotation target has to fulfill" /> 
</Term> 
<ComplexType Name="ConstraintType"> 
  <Property Name="FailureMessage" Type="Edm.String" Nullable="true"> 
    <Annotation Term="Core.IsLanguageDependent" /> 
  </Property> 
  <Property Name="Condition" Type="Edm.Boolean"> 
    <Annotation Term="Core.Description" 
        String="Value MUST be a dynamic expression that evaluates to true if and only if the constraint is fulfilled" /> 
  </Property> 
</ComplexType> 

Example:

<Annotation Term="Validation.Constraint" Qualifier="Comparison"> 
 <Record> 
   <PropertyValue Property="FailureMessage" String="Start date cannot be after end date" /> 
   <PropertyValue Property="Condition"> 
     <Le> 
      <Path>StartDate</Path> 
      <Path>EndDate</Path> 
     </Le> 
   </PropertyValue> 
 </Record> 
</Annotation>

Mike: Condition should be Nullable="false"

Ralf: Definition of Qualifier: http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/csprd02/odata-csdl-xml-v4.01-csprd02.html#sec_Qualifier

Ralf: ODATA-1082 is OPEN

George: I move as amended to include Nullable="False" on Constraint. Mark seconds.

Ralf: ODATA-1082 is RESOLVED with the amended proposal

6.1.6 ODATA-1079 - Several issues with latest standard vocabularies

Ralf: Proposal:
Org.OData.Core.V1.xml

<ComplexType Name="AlternateKey"> 
<Property Type="Collection(Core.PropertyRef)" Name="Key"> 
  <Annotation Term="Core.Description" String="The set of properties that make up this key" /> 
</Property> 
</ComplexType> 

should have Nullable="false" in the Property

Org.OData.Temporal.V1.xml

<Term Name="TemporalSupported" Type="Aggregation.TemporalSupportedType" AppliesTo="EntityContainer EntitySet NavigationProperty"> --> 

should be:

   
<Term Name="TemporalSupported" Type="Temporal.TemporalSupportedType" AppliesTo="EntityContainer EntitySet NavigationProperty"> 

8 references to Term="Core.Documentation" should be to Term="Core.Description"
Activity

Ralf: ODATA-1079 is OPEN

Mike: I move we resolve ODATA-1079 as proposed. George seconds.

Ralf: ODATA-1079 is RESOLVED as proposed

6.1.7 ODATA-1069 - New term Capabiliies.OperationAvailable

Ralf: Proposal

<Term Name="OperationAvailable" Type="Edm.Boolean" DefaultValue="true" AppliesTo="Action Function"> 
<Annotation Term="Core.Description" String="Action or function is available" /> 
</Term>

Ralf: Example:

<Annotation Term="Capabilties.OperationAvailable">
  <Ne>
  <Path>bindingParam/OrderStatus</Path>
  <String>SHIPPED</String>
  </Ne>
</Annotation>

Ralf: ODATA-1069 is OPEN

6. Next meetings only bi-weekly during Summer vacation period?

Mike: meet next week, decide then which meetings to have during July and August

6.1 Next Meeting on Thursday July 13, 2017 during 8-10 am PDT (17:00-19:00 CEST)

Confirmed as next meeting

6.2 Meetings following the next one (to be decided next week)

Ralf: Please all participate in Doodle: https://beta.doodle.com/poll/nivcwiuanz3yf98m

8. AOB and wrap up

None

Meeting adjourned by chair.