In the C# test program I have
interface IParallelogram { ... }
class Parallelogram : IParallelogram
{
private int height1;
private int height2;
...
}
class Rectangle : IParallelogram
{
private int height1;
private int height2;
...
}
I store two instances of Parallelogram with (height1, height2) = (10, 10) and (20, 20), two instances of Rectangle with (10, 10) and (30, 30). Then the following queries return wrong results:
IQuery q2 = objectContainer.Query();
q2.Constrain(typeof(IParallelogram));
IConstraint icon1 = q2.Descend("height1").Constrain(10);
IConstraint icon2 = q2.Descend("height2").Constrain(10);
IConstraint icon = icon1.And(icon2);
IObjectSet os3 = q2.Execute();
returns an empty IObjectSet.
IQuery q4 = objectContainer.Query();
q4.Constrain(typeof(IParallelogram));
IConstraint icon6 = q4.Descend("height1").Constrain(10).Not();
IObjectSet os5 = q4.Execute();
returns all the four instances of IParallelogram.
The C# test program can be downloaded from
https://svn.origo.ethz.ch/defcon/test_suites/SODA_Test.zip
In Eiffel for .NET applications, the developer only uses queries for interfaces because of multiple inheritance, so it is important to have SODA queries for interfaces work correctly.
The actual issue, at least for the NOT scenario, is not about interfaces as such, but seems to be a bug in the query processor. In a query like this...
QConClass GenericClass com.db4o.db4ounit.common.soda.InterfaceQueryTestCase$DataA 1
QConJoin 1|2 3
QConObject 10 6
QConClass GenericClass com.db4o.db4ounit.common.soda.InterfaceQueryTestCase$DataB 2
QConJoin 1|2 3
QConObject 10 7
...we can assume "implicit" AND joins between the OR join branches (QConClass) and their children (QConObject). However, we don't see both ends of the joins processed correctly, so no "do not include" is triggered. The cause seems to be some kind of "in-band signaling" that uses null as a candidate value when a field value could not be determined, see NullFieldMetadata. We need special handling for this case in QENot, however, currently there is no way to distinguish between an "unavailable field" and an actual null field value. Suggested solution: Use some designated value (like Null.INSTANCE) in the unavailable field case, fix all client code that expects null there.