More NSPredicate brokenness

No matter how i code it a predicate like this gets some or all of its conditions silently ignored:

             (date >= %@) AND (date <= %@) AND (field1 = %@) AND (field2 = %@)

If I put these in this order, the condition0 and condition1 are used and condition2 is ignored:

    NSPredicate *condition2 = [NSPredicate predicateWithFormat:
                              @"(dDate >= %@) "
                               "AND (dDate <= %@) ",
                              startDateStr, endDateStr ];
        
    NSPredicate *condition1= [NSPredicate predicateWithFormat:
                               @"(bBookingIsComplete == %@)",@0 ];
    
    NSPredicate *condition0 = [NSPredicate predicateWithFormat:
                                @"(BookingProgressStatus == %@)",@3];
         
    NSArray *arr = [NSMutableArray arrayWithObjects:condition0,condition1,condition2,nil];

If I reverse the above condition0,1,2 order, then only the DATE field checks are done.

For this NSPredicate:

BookingProgressStatus == 3 AND bBookingIsComplete == 0 AND (dDate >= "2013-02-06" AND dDate <= "2013-04-07")

With this XML:




 
  
   BookingProgressStatus
    3
   
  
   bBookingIsComplete
    0
   
  
 
dDate2013-02-06
dDate
2013-04-07




It’s clearly broken and I suspect the issue is on the server side.

Note that I haven’t installed Spring2013 yet so I guess I should try that first.

Hi,

the first thing I’ve spotted in code above - you cannot directly use date as string to filter on field with Date datatype. Instead you need to use NSDate instance.

So you’ll need to change your code something like this:

NSDateFormatter* df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"yyyy-MM-dd"];

NSPredicate *condition2 = [NSPredicate predicateWithFormat:
                              @"(dDate >= %@) "
                               "AND (dDate <= %@) ",
                              [df dateFromString:startDateStr], [df dateFromString:endDateStr]]; 

So in the XML with <constant type=“String”&gt; the above changes should also result in a change in the output xml…

When you will provide NSDate instances in your predicate, this predicate will be converted into proper DynamicWhere XML, with the same constant node but of DataTime type. Something like

1392160000

The reason you need to provide NSDate instances is that your string date can be written in dozen different formats, and system will not be able to transform it into proper NSDate value. It’s up to you to convert human-readable date strings to exact NSDate.

Now the predicate is (when printed) out, like this:

 NSPredicate BookingProgressStatus == 3 AND bBookingIsComplete == 0 AND (dDate >= CAST(382117080.596557, "NSDate") AND dDate <= CAST(387301080.596572, "NSDate"))

Note that the original behaviour I commented on is still present. The dates are being completely ignored (they should all be within 30 days +/- of todays date, but the entire database row set is being returned for all date values, ignoring the date condition completely.

Note that XML inside PRE html tags is still mangled by your blog engine. The XML can’t be pasted into your blog commenting system. You can see the xml here:

http://pastebin.com/5542NwRy

Also note that when I put parenthesis around predicates, Apple’s code removes them, thus the NSPredicate prints field1 == 3 and field2 == 0 even though I included parenthesis. (field1 == 3) AND (field2 == 0)

I debugged into uDAEngine.pas and I see that the breakage is happening inside uDAEngine at the stage where the XMLWhere stuff is resolved into real SQL. The breakage may be specific to only MS SQL.

You can see my XML where condition which has 4 AND boolean conditions,
and the short circuited SQL result that clearly only has 2 SQL AND conditions
in its where clause here:

http://pastebin.com/6KDHd9FL

The line of code where a LOT OF MAGIC happens is this line:

  SetSQL(fConnection.fMacroProcessor.Eval(GetSQL));

Talk about a lot going on in ONE line.

The difference between XML that works, and XML that doesn’t work is that the RemObjects “XML Where” syntax GENERATOR from XCODE CLIENTS generates more than 2 conditions under a single AND binaryoperation but the Data Abstract Server code on Delphi only processes the first two of them.

See the samples here.

http://pastebin.com/hec5PsYu

If you write the following in Pascal in Delphi and andcond is an array of 5 or 6 elements, the binary-expression-expansion of the TDAWhereExpressions is done in a way that results in the XML conditions NOT including more than 2 AND conditions in a row.

wb.NewBinaryExpressionList(andcond,dboAnd)

The logic in the RemObjects DA code for XCode that expands NSPredicates with more than two sub-conditions does NOT expand it properly.

Instead it passes back a single AND outer XML tag, containing 5 XML sub-elements, and the DA engine (uDAEngine.pas) only evaluates 2 of them, and silently IGNORES the others.

I consider this wrong on several levels. First, to have an engine based on XML that silently ignores data that is sent to it if more than 2 inputs are processed is wrong.

Secondly, to have generated uDAENgine so that “BinaryExpression” MUST contain exactly 2 conditions inside, but then not have the same thing be true on the XCode side is really really bad.

I can probably work around this on the XCOde side by making my own function that will, given a list of boolean predicates, construct a correct list of NSPRedicates, two by two, that will then result in a predicate set that will actually function on the uDAEngine side. But the thought of this makes me sick. Surely this could be more simply and easily fixed if the uDAEngine.pas engine did not silently ignore XML nodes passed to it as XMLWhere clauses, and just did the right thing. Please fix this.

oh right, got it!

I’ve raised an issue 61333 to fix that.
As a temporary solution please use NSCompoundPredicates with not more than 2 sub-predicates inside. Something like:

 NSPredicate *temp = [ NSCompoundPredicate andPredicateWithSubpredicates : @[ condition0, condition1 ] ];
 NSPredicate *final = [ NSCompoundPredicate andPredicateWithSubpredicates : @[ temp, condition2 ] ]; 
 NSString *dynWhereXml = [ DADynamicWhereXmlGenerator generateXmlFromPredicate:final];

Thanks for detailed info!

Thanks for logging that. I’ve found that if I always do the above workaround, it works.