Alaska Software Inc. - DbCommit() error
Username: Password:
AuthorTopic: DbCommit() error
Carlos a Beling DbCommit() error
on Thu, 12 Jul 2018 12:39:54 -0300
Hello.
Good afternoon.

I have the code below that rarely gives an unrecoverable error:
   The file where the error occurred was opened normally.
    BEGIN SEQUENCE
          (cAlias)->(DbCommit()) <== here the error occurs
          lCommited := .t.
          nCount    := 4
    RECOVER
          nCount += 1
          Sleep(15)
    ENDSEQUENCE

    The errors are:
       Operation            : DbCommit
       SubSystem            : BASE
       SubCode              : 5381
       Gencode              : 8999

This error triggered an ErrorSys procedure that got the error below in 
another file already opened:
       DESCRIPTION          : Error while reading a file
       Operation            : DbGoTop
       SubSystem            : BASE
       SubCode              : 8999
       Gencode              : 73

Please, why the unrecoverable error occurred in that structure?
Does it have any way to correct it?

Fraternally
Beling
Andreas Gehrs-Pahl
Re: DbCommit() error
on Thu, 12 Jul 2018 15:08:51 -0400
Carlos,

>I have the code below that rarely gives an unrecoverable error:

This error is only unrecoverable because you don't recover from it in your 
code -- at least the part that you have shown us.

>This error triggered an ErrorSys procedure that got the error below in 
>another file already opened:

That's pretty unlikely. That error is probably triggered by the same thing 
that triggered the original error, which is probably a network or file 
access issue or maybe an internal problem with the DBE -- or whatever the 
underlying cause for the original error was.

>Please, why the unrecoverable error occurred in that structure?

The error (apparently) occurred in the DbCommit() function. Why it occurred 
is anyone's guess. If I had to guess, I would say that there is a network or 
file access problem, especially as you apparently also get a read access 
error on another file right afterwards.

As you don't change the ErrorBlock, your default ErrorSys() procedure will 
be called in case of an error, instead of the code between Recover and End. 
And only if a Break() is encountered in your default ErrorSys() procedure, 
is the code after Recover executed.

So, if oError:CanRetry is True and the user selects either Ignore or Retry 
(if you allow those options), then the Recover code isn't executed at all.

If you want to prevent the default error handling to occur, you need to 
override it, using: "ErrorBlock({|e| Break(e)})" to redirect the program 
execution to (after) the Recover statement in case of an error.

Also, even if (the code after) the Recover statement would be executed, 
there is no loop (shown in your code), so your nCount variable doesn't seem 
to have a purpose. Finally, even if there were a loop, you have no code to 
address the issue of what to do if the error continues to occur.

Additionally, whenever you want to (temporarily) change the Error Block, you 
should reset it immediately back to the original setting, so that the normal 
error handling is restored before any other code is executed. So the general 
code pattern is like this:

LOCAL bError
[...]
bError := ErrorBlock({|e| Break(e)})    Don't call Standard Error Handler
BEGIN SEQUENCE
   nVar++                 code that might cause an error
RECOVER     If you care about the error code, use: "RECOVER USING oError"
   ErrorBlock(bError)     Restore the original Error Handling!
 ErrorLog(oError, 2)    You can log the Error if you like
   nVar := 0              "Fix" the issue, if you can
END SEQUENCE
ErrorBlock(bError)        Restore the original Error Handling!
[...]

In case you want to retry the code that created the error, you need to put 
the entire code into a loop:

LOCAL nCount := 0
[...]
while .t.
   BEGIN SEQUENCE
      (cAlias)->(DbCommit())
   RECOVER
      Sleep(15)
      if ++nCount < 5
         loop           Try to commit again
      else
         exit           After five times, give up and don't commit
      endif
   END SEQUENCE
   exit
enddo
[...]

Obviously, the above code will not be of much help, as it is unlikely that 
waiting for a few milliseconds before trying to commit again will do 
anything to fix the issue that actually caused the error. So, the program 
will simply try to commit four times and then continue on.

Chances are that the next database or index operation on this (or possibly 
any other) table will lead to just another error, though.

>Does it have any way to correct it?

Both errors are file access errors, but there is no information given about 
the environment, DBE used, DBE Settings, OS/Network or any environment 
information, etc. So there is no way to determine the actual cause of the 
error(s) -- or prevent the error(s) from (re)occurring. 

The generic (and completely useless and still undocumented) error codes that 
are provided by Xbase++ in this case don't help either with determining the 
cause of the problem or finding a solution to prevent the errors.

Because the underlying reason for such errors is quite often outside of the 
control of your application, you can do only one of three things:

1) Give the user a message about what happened -- and if you know, tell the 
   user what can be done to possibly fix it -- and then retry the offending 
   problem code. If that doesn't work (after several tries), use either 
   option 2) or 3);

2) Ignore the error and continue on with your program, hoping that this 
   won't cause any follow-on errors. But if the situation that lead to the 
   error isn't resolved -- for example if the network is down -- you will 
   just get additional errors;

3) Close the application gracefully -- closing all open files, sessions, 
   handles, dialogs, etc. -- before you either end your application (or the 
   tread in which the error occurred) or restart it.

Hope that helps,

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas@AbsoluteSoftwareLLC.com
web:   http://www.AbsoluteSoftwareLLC.com
[F]:   https://www.facebook.com/AbsoluteSoftwareLLC
Carlos a Beling Re: DbCommit() error
on Fri, 13 Jul 2018 09:38:50 -0300
Hello andreas:
Good morning.
Many thanks.
I did not had not an answer to my question. I got a very nice class, as 
you always do.
In despite to be an annoying thing you showed to us that sometimes to 
stop the procedure is the best thing to be done.

Fraternally
Beling


Em 12/07/2018 16:08, Andreas Gehrs-Pahl escreveu:
> Carlos,
>
>> I have the code below that rarely gives an unrecoverable error:
>
> This error is only unrecoverable because you don't recover from it in your
> code -- at least the part that you have shown us.
>
>> This error triggered an ErrorSys procedure that got the error below in
>> another file already opened:
>
> That's pretty unlikely. That error is probably triggered by the same thing
> that triggered the original error, which is probably a network or file
> access issue or maybe an internal problem with the DBE -- or whatever the
> underlying cause for the original error was.
>
>> Please, why the unrecoverable error occurred in that structure?
>
> The error (apparently) occurred in the DbCommit() function. Why it occurred
> is anyone's guess. If I had to guess, I would say that there is a network or
> file access problem, especially as you apparently also get a read access
> error on another file right afterwards.
>
> As you don't change the ErrorBlock, your default ErrorSys() procedure will
> be called in case of an error, instead of the code between Recover and End.
> And only if a Break() is encountered in your default ErrorSys() procedure,
> is the code after Recover executed.
>
> So, if oError:CanRetry is True and the user selects either Ignore or Retry
> (if you allow those options), then the Recover code isn't executed at all.
>
> If you want to prevent the default error handling to occur, you need to
> override it, using: "ErrorBlock({|e| Break(e)})" to redirect the program
> execution to (after) the Recover statement in case of an error.
>
> Also, even if (the code after) the Recover statement would be executed,
> there is no loop (shown in your code), so your nCount variable doesn't seem
> to have a purpose. Finally, even if there were a loop, you have no code to
> address the issue of what to do if the error continues to occur.
>
> Additionally, whenever you want to (temporarily) change the Error Block, you
> should reset it immediately back to the original setting, so that the normal
> error handling is restored before any other code is executed. So the general
> code pattern is like this:
>
> LOCAL bError
> [...]
> bError := ErrorBlock({|e| Break(e)})    Don't call Standard Error Handler
> BEGIN SEQUENCE
>     nVar++                 code that might cause an error
> RECOVER     If you care about the error code, use: "RECOVER USING oError"
>     ErrorBlock(bError)     Restore the original Error Handling!
>  ErrorLog(oError, 2)    You can log the Error if you like
>     nVar := 0              "Fix" the issue, if you can
> END SEQUENCE
> ErrorBlock(bError)        Restore the original Error Handling!
> [...]
>
> In case you want to retry the code that created the error, you need to put
> the entire code into a loop:
>
> LOCAL nCount := 0
> [...]
> while .t.
>     BEGIN SEQUENCE
>        (cAlias)->(DbCommit())
>     RECOVER
>        Sleep(15)
>        if ++nCount < 5
>           loop           Try to commit again
>        else
>           exit           After five times, give up and don't commit
>        endif
>     END SEQUENCE
>     exit
> enddo
> [...]
>
> Obviously, the above code will not be of much help, as it is unlikely that
> waiting for a few milliseconds before trying to commit again will do
> anything to fix the issue that actually caused the error. So, the program
> will simply try to commit four times and then continue on.
>
> Chances are that the next database or index operation on this (or possibly
> any other) table will lead to just another error, though.
>
>> Does it have any way to correct it?
>
> Both errors are file access errors, but there is no information given about
> the environment, DBE used, DBE Settings, OS/Network or any environment
> information, etc. So there is no way to determine the actual cause of the
> error(s) -- or prevent the error(s) from (re)occurring.
>
> The generic (and completely useless and still undocumented) error codes that
> are provided by Xbase++ in this case don't help either with determining the
> cause of the problem or finding a solution to prevent the errors.
>
> Because the underlying reason for such errors is quite often outside of the
> control of your application, you can do only one of three things:
>
> 1) Give the user a message about what happened -- and if you know, tell the
>     user what can be done to possibly fix it -- and then retry the offending
>     problem code. If that doesn't work (after several tries), use either
>     option 2) or 3);
>
> 2) Ignore the error and continue on with your program, hoping that this
>     won't cause any follow-on errors. But if the situation that lead to the
>     error isn't resolved -- for example if the network is down -- you will
>     just get additional errors;
>
> 3) Close the application gracefully -- closing all open files, sessions,
>     handles, dialogs, etc. -- before you either end your application (or the
>     tread in which the error occurred) or restart it.
>
> Hope that helps,
>
> Andreas
>