Bug #5953
Exceptions raised by UDFs with PRESELECT
Status:
New
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
01/06/2022
Due date:
% Done:
0%
billable:
No
vendor_id:
GCD
case_num:
History
#2 Updated by Igor Skornyakov over 2 years ago
It seems that we have a serious problem with PRESELECT
if UDF raises an error. Consider the following code:
outer2: do on stop undo, leave outer2: REPEAT PRESELECT EACH udftests NO-LOCK WHERE string(fdate, fmt) = udftests.fstr-result AND udftests.test-name = 'dtostring': err-flag3 = false. message 'in preselect loop:'. err-flag = true. inner: do on stop undo, leave inner: FIND NEXT udftests NO-ERROR. err-flag = no. if not AVAILABLE udftests then do: message "no more records". leave outer2. end. message "After find next:" udftests.id ERROR-STATUS:ERROR ERROR-STATUS:NUM-MESSAGES AVAILABLE udftests. if not AVAILABLE udftests then leave outer2. end. message "After find: error =" ERROR-STATUS:ERROR "num-messages =" ERROR-STATUS:NUM-MESSAGES "type =" ERROR-STATUS:TYPE "available =" AVAILABLE udftests "err-flag = " err-flag. if ERROR-STATUS:ERROR then leave outer2. END. end. message 'done' err-flag3.
It is converted to
OnPhrase[] onPhrase4 = new OnPhrase[] { new OnPhrase(Condition.STOP, Action.LEAVE, "outer2") }; doBlock(TransactionType.SUB, "outer2", onPhrase4, new Block((Body) () -> { PreselectQuery query2 = new PreselectQuery(); repeat("loopLabel2", new Block((Init) () -> { RecordBuffer.openScope(udftests); query2.initialize(udftests, "toString(udftests.fdate, upper(udftests.fmt)) = upper(udftests.fstrResult) and upper(udftests.testName) = 'DTOSTRING'", null, "udftests.id asc", LockType.NONE); }, (Body) () -> { errFlag3.assign(false); message("in preselect loop:"); errFlag.assign(true); OnPhrase[] onPhrase5 = new OnPhrase[] { new OnPhrase(Condition.STOP, Action.LEAVE, "inner") }; doBlock(TransactionType.SUB, "inner", onPhrase5, new Block((Body) () -> { silent(() -> query2.next()); errFlag.assign(false); if (_not(udftests.available())) { message("no more records"); leave("outer2"); } message(new Object[] { "After find next:", (integer) new FieldReference(udftests, "id").getValue(), ErrorManager.isError(), ErrorManager.numErrors(), udftests.available() }); if (_not(udftests.available())) { leave("outer2"); } })); message(new Object[] { "After find: error =", ErrorManager.isError(), "num-messages =", ErrorManager.numErrors(), "type =", ErrorManager.getResourceType(), "available =", udftests.available(), "err-flag = ", errFlag }); if ((ErrorManager.isError()).booleanValue()) { leave("outer2"); } })); })); message(new Object[] { "done", errFlag3 });
With 4GL the STOP
is raised on
REPEAT PRESELECT EACH udftests NO-LOCK WHERE string(fdate, fmt) = udftests.fstr-result AND udftests.test-name = 'dtostring':
In particular, we do not see
in preselect loop:
message.
With FWD we get the SQLException
only on the first query2.next()
execution. after the in preselect loop:
message is shown.
What is much worse, is that the StopConditionException
which is thrown after the SQLException
is caught and converted to the UdfException
does not cause the exit from the outer2
block, we just leave only the inner
block instead.