Project

General

Profile

Bug #5953

Exceptions raised by UDFs with PRESELECT

Added by Igor Skornyakov over 2 years ago. Updated over 2 years ago.

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.

Also available in: Atom PDF