Contrary to the other run-able CSIDE objects - i.e. Page, Report and XMLport - we can run a Codeunit and catch the result from this execution: TRUE or FALSE
[Ok :=] Codeunit.RUN(Number[, Record])
So if we call CODEUNIT.RUN and request a return value, as illustrated by the two first examples in this series - CODEUNIT.RUN #1 and CODEUNIT.RUN #2 -, this means that basically any runtime error emerging in the execution of the codeunit (as defined by the Number) will be caught by the system and will result in CODEUNIT.RUN to return FALSE.
Unfortunately there seems to be one exception to the rule - there the basically above - and this is illustrated by my third example, CODEUNIT.RUN #3, even though this example does not really deviate from my second example. The only difference being the table the double insert is operated on. CODEUNIT.RUN #2 operates on the Customer table and CODEUNIT.RUN #3 on the Shipment Method table.
Having in mind to write this short series on CODEUNIT.RUN I stumbled across this post of Bodo addressing this one anomaly - so these credits go to him. In short (as you might not be able to read German):
You will not be able to catch the execution result of a codeunit that makes a duplicate insert of a record as the system will already have thrown the error instead of passing a FALSE to my "catcher" statement.
The deviation that CODEUNIT.RUN #3 illustrates, seems to apply to all tables except for the Customer table. So only in case of the Customer table, it works like intended - did try it on quite some tables, but surely not all. With all other tables your catcher code will NOT get a FALSE passed. And this is clearly a bug as eYe also found out.
This anomaly has been reported to MS and if you feel like voting for it go here.
Amazing the number of times I mess up regarding explicit and implicit :-( Sorry, but I'm sure you know what I mean...
My bad! I meant Explicit :(
I'm not saying it explains the crash - that shouldn't happen. I'm just saying the actual T-SQL Insert and thereby the duplication error from SQL is happening at a later stage. You can see it by adding a MESSAGE after your second INSERT statement.
To force the buffered inserts to be executed, you could add a FIND('=') after your inserts. Then I guess it works like you expect. But this is only needed until MS fixes the actual problem.
I don't understand your last question. The IF Codeunit.RUN statements always differs from ordinary function calls in three ways:
1) It fails instantly if a transaction is started before the call. That is why many insert a COMMIT just before the IF Codeunit.RUN, but you really need to make sure the COMMIT doesn't risk losing data integrity.
2) It performs an EXPLICIT ;) commit at the end.
3) Any error from the scope of the codeunit results in the call to return false and the actual errormsg is stored in the GETLASTERRORTEXT.
Hi Peter, thanx for adding this info. Probably it's due to my level of understanding, but why does this make a difference regarding the "cathcher" statement on CODEUNIT.RUN? Buffered or not the duplicate INSERT will raise an error. Is is that the execution of the implicit (I guess not explicit like you state) COMMIT disables any returning of TRUE and/or FALSE?
The reason is the Bulk Insert buffer. The records are not inserted until the explicit COMMIT is fired when the codeunit it completed. The reason it works for the Customer table, is that the Bulk Insert buffer is disabled for tables with BLOB fields.
Check this link for more info: msdn.microsoft.com/.../dd355341.aspx
PS: The Bulk Insert has been improved a bit from NAV2009 to NAV2013, but I do not know if it changes anything for this example.