Runtime Error with Append From

439 views
Skip to first unread message

Claudia Neumann

unread,
Sep 1, 2012, 2:16:31 PM9/1/12
to harbou...@googlegroups.com
Hi all,

I have a program that updates dbfs. It uses

Append From (<database>)

The xHarbour Language Reference Guide tells:
The import file is attempted to be opened in SHARED and READONLY mode. If
opening the import file fails, APPEND FROM raises a runtime error.

So I assume the import file has not to be opened prior to the command. Is that
right?

Sometimes there are
DBFCDX/1020 Data type error

but I can not retrieve the corrupted file because oError:filename is empty.

Could someone please tell me how I can get the information which file is
corrupted?

Begin sequence - recover - end sequence seems not to prevent a crash. I want to
use a backup file at that point.

Help would be greatly appreciated.

Best regards

Claudia

Zoran Sibinovic

unread,
Sep 1, 2012, 4:05:55 PM9/1/12
to harbou...@googlegroups.com
Hi Claudia,

The DBFCDX/1020 Data type error occurs, always, when you have a field/s in both databases with the same name but of different types
ex. in one base a field called ID is defined as numeric and in the other ID is character. Seems to me that is no corruption in there.
Look at the bases structure.
 
Also a crash can be caused by APPEND FROM <base> FOR <fieldname>... or other condition if the same field and same type is not present in both bases.    

The base where the append have to be done have to be opened in exclusive mode and the base from witch we appended must not be opened.

Hope helpful

Zoran

Claudia Neumann

unread,
Sep 1, 2012, 4:41:35 PM9/1/12
to harbou...@googlegroups.com, Zoran Sibinovic
Hi Zoran,

yes, normally all goes well. Seldom I get this error or even

DBFCDX/1010 Read error

To look what data type error occurs I need the original dbf's name but can not
retrieve it with oError:filename. There are over 1000 databases in an update.

The dbf where the data is appended is opened exclusively.

CU

Claudia

Zoran Sibinovic

unread,
Sep 1, 2012, 5:18:48 PM9/1/12
to harbou...@googlegroups.com, Zoran Sibinovic
Hi Claudia,

well...
If your method don't works and if you made this app you can easily, in an oldfashion way, add some simple code to display the bases name before the append start from that base, when the error occurs, the app will freeze or will display errors that you mentioned, in that moment you will be able to see, in the background the problematic database name as the last displayed in the list. 

If you are not the app creator... then you really have a problem since you have over 1000 base on an update.

The read error DBFCDX/1010 Read error indicates a corrupted or not existing .cdx index, you can try to solve the problem by deleting all the indexes and index the database with fresh indexes, but not with reindex, and the try your append app.

Zoran 

Claudia Neumann

unread,
Sep 1, 2012, 5:38:23 PM9/1/12
to harbou...@googlegroups.com, Zoran Sibinovic
Hi Zoran,

Am Samstag September 1 2012 schrieb Zoran Sibinovic:
> Hi Claudia,
>
> well...
> If your method don't works and if you made this app you can easily, in an
> oldfashion way, add some simple code to display the bases name before the
> append start from that base, when the error occurs, the app will freeze or
> will display errors that you mentioned, in that moment you will be able to
> see, in the background the problematic database name as the last displayed
> in the list.

Okay, that's a possibility. But I would prefer to avoid the crash and use the
backup file instead.

> If you are not the app creator... then you really have a problem since you
> have over 1000 base on an update.
>
> The read error DBFCDX/1010 Read error indicates a corrupted or not existing
> .cdx index, you can try to solve the problem by deleting all the indexes
> and index the database with fresh indexes, but not with reindex, and the
> try your append app.

Thanks, will try this one.

Perhaps other suggestions?

Cu

Claudia

Zoran Sibinovic

unread,
Sep 1, 2012, 5:58:12 PM9/1/12
to harbou...@googlegroups.com, Zoran Sibinovic
Hi Claudia,

not for now,

debugging errors sometimes is a veterinary

goodnight

Zoran

Klas Engwall

unread,
Sep 1, 2012, 6:32:04 PM9/1/12
to harbou...@googlegroups.com
Hi Claudia, Neumann wrote 2012-09-01 23:38:

>> If your method don't works and if you made this app you can easily, in an
>> oldfashion way, add some simple code to display the bases name before the
>> append start from that base, when the error occurs, the app will freeze or
>> will display errors that you mentioned, in that moment you will be able to
>> see, in the background the problematic database name as the last displayed
>> in the list.
>
> Okay, that's a possibility. But I would prefer to avoid the crash and use the
> backup file instead.

Is this a case where a simple ProcName() / ProcLine() trace in the error
handler does not help? A situation where you import dbf files from
different sources where sometimes the structure does not meet the
specifications? If so, how about first opening each of the import files
and comparing the dbstruct() output with the specs, then closing the
file and appending or rejecting depending oh the result?

Regards,
Klas

Claudia Neumann

unread,
Sep 2, 2012, 3:47:41 AM9/2/12
to harbou...@googlegroups.com, Klas Engwall
Hi Klas,

Am Sonntag September 2 2012 schrieb Klas Engwall:
> Hi Claudia, Neumann wrote 2012-09-01 23:38:
> >> If your method don't works and if you made this app you can easily, in
> >> an oldfashion way, add some simple code to display the bases name
> >> before the append start from that base, when the error occurs, the app
> >> will freeze or will display errors that you mentioned, in that moment
> >> you will be able to see, in the background the problematic database
> >> name as the last displayed in the list.
> >
> > Okay, that's a possibility. But I would prefer to avoid the crash and use
> > the backup file instead.
>
> Is this a case where a simple ProcName() / ProcLine() trace in the error
> handler does not help? A situation where you import dbf files from
> different sources where sometimes the structure does not meet the
> specifications?

Yes I import dbf files from multiple sources. Because it is an update the new
structure may differ by 1 or 2 added fields. The problem seems to be that in
rare cases there is wrong data in a record and the update crashes (with
Harbour). Clipper and xbase++ just copy the wrong data and don't complain.

> If so, how about first opening each of the import files
> and comparing the dbstruct() output with the specs, then closing the
> file and appending or rejecting depending oh the result?

I will look into that but I am convinced that dbstruct() shows the same output()
as the specs. Sometimes the program crashes on opening the file. In those cases
I know which file is affected. But in other cases you can work with the file if
you don't use the record with the wrong data. I can not say how the wrong data
get into the database. User manipulation? Error on the disk? In that cases I
have a big problem.

Any help would be greatly appreciated.

Best regards

Claudia


Zoran Sibinovic

unread,
Sep 2, 2012, 4:31:34 AM9/2/12
to harbou...@googlegroups.com, Klas Engwall
Hi Claudia,

another thing,
If am I right, according your informations, cases emerges with different databases and with different errors.

Three questions.

1.Are some of that databases from different sources sometimes in use by other apps during your update?

2.If so, is there some possibility that you cannot access to some particular database/index because is opened as exclusive? If is not, the databases are all free during your update and you use a simple APPEND FROM without conditions, it can be that you have problems with the hdd or the comp.

3.What do you mean with  "record with the wrong data"? The user have, always trough their apps, to enter data of predefined type, except if you allow them to change the database structure on the fly. The database crash can happen only if the user app or his comp hungs/crashes, for some reason of software, hardware, viruses or else, so the bases and indexes can become entirely or a part unreadable. You can investigate, in that case if someone have hungs/crashes on their comp and start from there.  

Is difficult to make some concrete proposal without known the databases use at the time of your update. Things differs if they are used during your update or not.

Zoran 

Claudia Neumann

unread,
Sep 2, 2012, 5:00:18 AM9/2/12
to harbou...@googlegroups.com, Zoran Sibinovic, Klas Engwall
Hi Zoran,

Am Sonntag September 2 2012 schrieb Zoran Sibinovic:
> Hi Claudia,
>
> another thing,
> If am I right, according your informations, cases emerges with different
> databases and with different errors.
>
> Three questions.
>
> 1.Are some of that databases from different sources sometimes in use by
> other apps during your update?

No, that I check before start of update. And user can not log in during update.

> 2.If so, is there some possibility that you cannot access to some
> particular database/index because is opened as exclusive? If is not, the
> databases are all free during your update and you use a simple APPEND FROM
> without conditions, it can be that you have problems with the hdd or the
> comp.

Yes, I use
append from (<database>)
without conditions. That is alright most of the time.

> 3.What do you mean with "record with the wrong data"? The user have,
> always trough their apps, to enter data of predefined type, except if you
> allow them to change the database structure on the fly. The database crash
> can happen only if the user app or his comp hungs/crashes, for some reason
> of software, hardware, viruses or else, so the bases and indexes can become
> entirely or a part unreadable. You can investigate, in that case if someone
> have hungs/crashes on their comp and start from there.

I suspect the wrong data comes from crashes/viruses or else or using some other
software on the database. I know that using some older MS office program can
change data in dbf. Typically the user denies/does not know what happened to the
database or even does not know which database is affected.

> Is difficult to make some concrete proposal without known the databases use
> at the time of your update. Things differs if they are used during your
> update or not.

I know that. My problem is that Clipper or xbase++ don't complain with the same
code. That is not good either because the wrong record is still in the updated
data and may cause crashes in the future. So information which database has the
wrong data or some kind of trick to advoid the crash would help immensely.

Best regards

Claudia

Zoran Sibinovic

unread,
Sep 2, 2012, 5:45:22 AM9/2/12
to harbou...@googlegroups.com, Zoran Sibinovic, Klas Engwall
Hi Claudia,

I have noticed 6-7 years ago that my Clipper apps
cant be affected by virus, why, because are for DOS and my aps are 16-bit.
The virus technology seems was not more interested to make viruses for this kind of things, windows and 32.bit apps become of more interest.

I start to make apps in harbour in the last 2 years and I must admit that I have some fears regarding the virus fields of actions because harbour use also windows api and other OSes stuff to work.   

If I was you and have your suspects, I will start to scan first the users computers for viruses, then make a tools->check of the partitions on users computer, eliminate all third party tweak/hardware/cleaners utility software except the OS basics, This also applies to your comp. Some utilities can make mess especially in the registry. 

Also, the appending of new records in an network environment, talking about the users app, can cause, very rarely but can, the crash if two users press the append button at the same time 

With this I have no problem to add new records even are more of 30 users working in the same database.  

*****************************
PROCEDURE ADDREC

DBAPPEND()
WHILE NETERR() ; INKEY(.5) ; DBAPPEND() ; END
WHILE !RLOCK() ; INKEY(.5) ; END

RETURN

If you can identify the hardware/app crashing computer you have did it, just ask the users if they noticed some problems: suthdowns, freeze, hung, some read errors of doc in office, even insignificant to them. 

Thats for now
Best regards

Zoran 

francesco perillo

unread,
Sep 2, 2012, 6:36:33 AM9/2/12
to harbou...@googlegroups.com
I'd not care about contemporary "virus".

First of all let call them "malware"
Second, 99% of them are here to *steal* informations or money, they scan your drive to get credit card numbers, documents, spy on your web connections, change your dns settings... they try very hard to not modify any data on your pc... the more they are unnoticed on your computer the more information they can steal !!!!

So I don't think they can be a source of problems in this specific case.

Francesco

francesco perillo

unread,
Sep 2, 2012, 6:49:05 AM9/2/12
to harbou...@googlegroups.com

Claudi,
I didn't understand if you have sources for this program or not.

I also don't know the specifics of the situation, for example if you need to process all the updates on the 1000 dbf all together and if you have to rollback if anyone fails.

First of all I'd add a complete log, each step must create a line in the log (file opened, filename to import from),
then I'd check dbf structure (logging positive/negative result)
if you want to keep the APPEND FROM then I'd proceed for a dry-run (import data in empty dbf, just to check import data is ok)
otherwise I'd change to an import using a program: open file, read a record, validate the fields, add a new empty record and REPLACE data. Probably it takes longer but you can have more control on the data.

Anyway, I believe that someone may have opened data in excel (or similar program) so that some changes have happened...

Francesco

Claudia Neumann

unread,
Sep 2, 2012, 7:11:51 AM9/2/12
to harbou...@googlegroups.com, Zoran Sibinovic, Klas Engwall
Hi Zoran, hi all,

maybe it was not a virus. It may be possible, that the errors in the databases
are caused by the Windows oplocks problem in network Klas Engholm cited some
time ago. I will try your code for appending a record. But are you sure this
will eliminate the oplocks problem?

The erroneous databases are often older databases which are not used in daily
practice. Because Clipper and xbase++ have no problem with the append from
command, these older databases are kept as erroneous as they are with Clipper
and xbase++ updates whereas Harbour update crashes. This inhibits badly the
change to Harbour.

Just a notice: in Linux I never experienced erroneous databases which would
suggest either virus or oplocks problem in Windows.

Best regards

Claudia

Am Sonntag September 2 2012 schrieb Zoran Sibinovic:

Claudia Neumann

unread,
Sep 2, 2012, 7:30:40 AM9/2/12
to harbou...@googlegroups.com, francesco perillo
Hi Francesco,

Am Sonntag September 2 2012 schrieb francesco perillo:
> Claudi,
> I didn't understand if you have sources for this program or not.

I have the full source and am programming on it.

> I also don't know the specifics of the situation, for example if you need
> to process all the updates on the 1000 dbf all together and if you have to
> rollback if anyone fails.

I have to process all the 1000 dbfs all together at some special updates.

> First of all I'd add a complete log, each step must create a line in the
> log (file opened, filename to import from),
> then I'd check dbf structure (logging positive/negative result)
> if you want to keep the APPEND FROM then I'd proceed for a dry-run (import
> data in empty dbf, just to check import data is ok)
> otherwise I'd change to an import using a program: open file, read a
> record, validate the fields, add a new empty record and REPLACE data.
> Probably it takes longer but you can have more control on the data.

Naturally I would like to keep the APPEND FROM because it is much quicker.
Normally everything works well. But if the update of 2 users of 800 crashes I
have much trouble to rollback, the search of the offending database and so on.
If I could avoid the crash in APPEND FROM I have a routine which tries in a
second step to eliminate bad records. Better a bad record eliminated with a
notice for the user then a full crash of the update process. But at the moment
the harbour program crashes and leaves the user helpless. Not good.

> Anyway, I believe that someone may have opened data in excel (or similar
> program) so that some changes have happened...

Possible. Even only opening a dbf with excel can change the database. But you
know noone did anything =8-/

CU

Claudia

Klas Engwall

unread,
Sep 2, 2012, 11:58:14 AM9/2/12
to harbou...@googlegroups.com
Hi Claudia,

> Naturally I would like to keep the APPEND FROM because it is much quicker.
> Normally everything works well. But if the update of 2 users of 800 crashes I
> have much trouble to rollback, the search of the offending database and so on.
> If I could avoid the crash in APPEND FROM I have a routine which tries in a
> second step to eliminate bad records. Better a bad record eliminated with a
> notice for the user then a full crash of the update process. But at the moment
> the harbour program crashes and leaves the user helpless. Not good.

I am afraid you have to make a choice between "import it quickly" and
"make sure everything is OK" :-)

If it takes too long to read each record in the update files separately,
analyze the data and save those that meet the criteria, then Francesco's
suggestion to first import into a temporary file is really the only way
to go. It will take twice as long as it does now, of course, but data
integrity must be the #1 priority. A local error handler, a BEGIN
SEQUENCE ... RECOVER ... END SEQUENCE, and manual repair of the
offending files are what you need. When the buggy files have been moved
to the side you can do the real import like you do now.

But unless there is a distinctive relationship between the individual
records that makes the rest of them unreliable or invalid if one is
missing, I would probably go for the slow "manual" approach and log the
one or two offending records while saving all the other ones. That would
call for the least corrective action after the import of all the valid
records is finished - and it will give you the quickest recovery from
the errors.

>> Anyway, I believe that someone may have opened data in excel (or similar
>> program) so that some changes have happened...
>
> Possible. Even only opening a dbf with excel can change the database. But you
> know noone did anything =8-/

But there can also be a much simpler explanation. It is enough that one
single bit is flipped, and something that was supposed to be a digit is
turned into a totally different character. The reason can be an ageing
harddrive (there are even statistical models that will tell you the
probability of that :-) ) or a transmission error, for example. It
doesn't have to he a human fiddling with the data.

When you have identified who gave you the offending file you can send
your hardware guy to check the computer in question :-)

Regards,
Klas

Claudia Neumann

unread,
Sep 2, 2012, 2:32:08 PM9/2/12
to harbou...@googlegroups.com, Klas Engwall
Hi Klas, hi all,

okay, perhaps I will eventually have to "make sure everything is OK" ;-).

How about modifying the /src/rtl/errsys.prg und establishing my own error
handling routine? Has someone done that? How could I do that? If I write my own
errorblock() it seems that first the errorblock in /src/rtl/errsys.prg is
executed and only part of the errorblock() I wrote. If I comment the
errorblock() in /src/rtl/errsys.prg out harbour won't compile. If I exchange the
errorblock() in /src/rtl/errsys.prg with my errorblock() harbour won't compile
because of some variables used in my program that are not known to harbour.

Can/should it be done?

In Clipper I can program my own error handling routine.

Any suggestions/ideas?

Best regards

Claudia

Klas Engwall

unread,
Sep 2, 2012, 9:19:41 PM9/2/12
to harbou...@googlegroups.com
Hi Claudia,

> okay, perhaps I will eventually have to "make sure everything is OK" ;-).
>
> How about modifying the /src/rtl/errsys.prg und establishing my own error
> handling routine? Has someone done that? How could I do that? If I write my own
> errorblock() it seems that first the errorblock in /src/rtl/errsys.prg is
> executed and only part of the errorblock() I wrote. If I comment the
> errorblock() in /src/rtl/errsys.prg out harbour won't compile. If I exchange the
> errorblock() in /src/rtl/errsys.prg with my errorblock() harbour won't compile
> because of some variables used in my program that are not known to harbour.
>
> Can/should it be done?

Yes. Absolutely.

> In Clipper I can program my own error handling routine.
>
> Any suggestions/ideas?

Put
//-----------
static bOldErrBlock
//-----------
at the top of your main prg

Then add an init procedure, also in the main prg
//-----------
init procedure ErrorSys() // Use a modified errorsys.prg
bOldErrBlock := ErrorBlock( { | oError | MyErrorHandler( oError ) } )
return
//-----------

Now the ErrorSys() in the init procedure will be used instead of the one
in rtl. And it will redirect errors to your own errorhandler. The
<bOldErrorBlock> variable can be omitted if you do not need the original
error handler later on in your project. You can have any number of error
handlers and switch between them with the ErrorBlock() function at any
time as long as they are all linked with the application.

Copy errorsys.prg to your project directory, remove the ErrorSys
procedure and rename the DefError() function to MyErrorHandler() (or
whatever you want to call it - but the same as in the ErrorBlock() call).

Then you can add whatever functionality you need in the MyErrorHandler()
function. There used to be a lot more code in errorsys.prg than there is
now, logging for example. I am not sure why it was removed, but it can
easily be added back in your local copy. xHarbour inherited the original
Harbour errorsys.prg and modified it to some extent. I took it with me
(additionally modified) when I migrated to Harbour and have added a lot
of extra bells and whistles over time. You can use the XHB version as a
guide, but there are some variables (just a handful) that differ between
the two Harbours and need to be changed. I have not really checked the
Harbour extras and examples, maybe there is something there that can be
used too ... I just happened to have my modified XHB error handler already.

Write a couple of lines of test code that are guaranteed to raise an
error so you can more easily test your error handling routines.

Regards,
Klas

Klas Engwall

unread,
Sep 2, 2012, 9:23:06 PM9/2/12
to harbou...@googlegroups.com
BTW Claudia,

Please do not CC me. It confuses Thunderbird and makes it difficult to
reply to the list.

Regards,
Klas

Claudia Neumann

unread,
Sep 3, 2012, 7:11:39 AM9/3/12
to harbou...@googlegroups.com
Hi Klas, hi all,

here now, that's a real solution!!

Now I understand why my error handler didn't work as exspected.

Thank you very much. I am pretty sure that now I not only can retrieve the name
of the compromised database but also can program different procedure for various
situations.

To Massimo and Giovanni: I would suggest to integrate Klas's mail into your
documentation.

Best regards

Claudia

Claudia Neumann

unread,
Sep 6, 2012, 8:53:56 AM9/6/12
to harbou...@googlegroups.com
Hi Klas, hi all,

I modified myErrorblock and could correct the datatype error.

Now I can't get back to where the error started. If I set

begin sequence
append from (<database>)
end sequence

and I leave myErrorblock with
return [.t./.f.]
the program still quits.

If I leave myErrorblock with
break
I get a segmentation fault.

Recover has no effect.

What can I do?

Best regards

Claudia

Am Montag September 3 2012 schrieb Klas Engwall:

Klas Engwall

unread,
Sep 6, 2012, 3:11:20 PM9/6/12
to harbou...@googlegroups.com
Hi Claudia,

> I modified myErrorblock and could correct the datatype error.
>
> Now I can't get back to where the error started. If I set
>
> begin sequence
> append from (<database>)
> end sequence
>
> and I leave myErrorblock with
> return [.t./.f.]
> the program still quits.
>
> If I leave myErrorblock with
> break
> I get a segmentation fault.
>
> Recover has no effect.
>
> What can I do?

I suggest that you check out the examples in the Clipper 5.x Norton
Guide or manual regarding the details of BEGIN SEQUENCE. I don't think
you really want a BREAK in this case, but you rather want to RECOVER
after returning from the error block. In the code snippet below an error
occurs in the second case statement. After returning from the errorblock
you will "land" after RECOVER.

//-------------------------
proc main()
local i
errorblock( { || MyError() } )
for i := 1 to 3
begin sequence
do case
case i == 1
? '1 + 2 equals '
?? hb_ntos( 1 + 2 )
case i == 2
? '1 + x equals '
? 1 + 'x'
case i == 3
? '1 + 3 equals '
?? hb_ntos( 1 + 3 )
endcase
recover
end sequence
next
return

proc MyError
? 'An error occured in line ' + hb_ntos( procline( 2 ) )
return 'oops'
//-------------------------

Regards,
Klas

Klas Engwall

unread,
Sep 6, 2012, 8:43:16 PM9/6/12
to harbou...@googlegroups.com
Hi again Claudia,

My previous suggestion actually lands after END SEQUENCE. Here is
another attempt that really lands after RECOVER (and includes a BREAK).

//-------------------------
proc main()
local i
errorblock( { || MyError() } )
for i := 1 to 3
begin sequence
do case
case i == 1
? '1 + 2 equals '
?? hb_ntos( 1 + 2 )
case i == 2
? '1 + x equals '
? 1 + 'x'
case i == 3
? '1 + 3 equals '
?? hb_ntos( 1 + 3 )
endcase
recover
? 'Back in business'
end sequence
next
return

proc MyError()
? 'An error occured in line ' + hb_ntos( procline( 2 ) )
break
return NIL
//-------------------------

And here is one that returns the error to the calling code so you can
analyze it there (with RECOVER USING):

//-------------------------
proc main()
local i, oReturnedErr
errorblock( { |oErr| MyError( oErr ) } )
for i := 1 to 3
begin sequence
do case
case i == 1
? '1 + 2 equals '
?? hb_ntos( 1 + 2 )
case i == 2
? '1 + x equals '
? 1 + 'x'
case i == 3
? '1 + 3 equals '
?? hb_ntos( 1 + 3 )
endcase
recover using oReturnedErr
? 'Back in business'
if oReturnedErr:gencode != 0
? 'The error was: ' + oReturnedErr:Description
endif
end sequence
next
return

proc MyError( oErr )
? 'An error occured in line ' + hb_ntos( procline( 2 ) )
break oErr
return NIL

//-------------------------

And there are probably several additional ways to skin this particular
cat :-)

Regards,
Klas

Claudia Neumann

unread,
Sep 7, 2012, 10:23:55 AM9/7/12
to harbou...@googlegroups.com
Hi again Klas,

okay, I have got it. Many thanks.

Perhaps it should be mentioned, that the prg file has exactly to be called
ERRORSYS.PRG if you want to exchange the harbour error handling procedure with
your own error handler. Otherwise the harbour error handler will be executed as
well.

BTW, I certainely don't want to "skin a cat". ;-)

Best regards

Claudia and Garfield (tuxedo cat)

vszakats

unread,
Sep 7, 2012, 3:12:55 PM9/7/12
to harbou...@googlegroups.com


On Friday, September 7, 2012 4:24:08 PM UTC+2, Claudia wrote:
Hi again Klas,

okay, I have got it. Many thanks.

Perhaps it should be mentioned, that the prg file has exactly to be called  
ERRORSYS.PRG if you want to exchange the harbour error handling procedure with
your own error handler. Otherwise the harbour error handler will be executed as
well.

There is no need to do that. Just write your own 
handler function and change the error handling block 
to call your own local function. Works the same as 
in Clipper 5.

-- Viktor

Klas Engwall

unread,
Sep 7, 2012, 3:50:07 PM9/7/12
to harbou...@googlegroups.com
Hi Claudia,

> Perhaps it should be mentioned, that the prg file has exactly to be called
> ERRORSYS.PRG if you want to exchange the harbour error handling procedure with
> your own error handler. Otherwise the harbour error handler will be executed as
> well.

The default error handler will be linked so you can switch back to it
later, but only the error handler that is installed with ErrorBlock()
will be executed. The default DefError() will be installed at program
startup, before your own code is executed, but if you call ErrorBlock()
with your own error handler, either at the top of main() or in an init
procedure, that is the error handler that will be used until you call
ErrorBlock() again with a different codeblock. The examples I posted
yesterday will not call DefError() even though the new error handler is
not in a source file called ERRORSYS.PRG. If you do not use DefError()
later in the application it will simply cost you a few KB of RAM spent
storing it.

> BTW, I certainely don't want to "skin a cat". ;-)

Let's bring the cat back for a moment and skin it once more :-). The
following code chains two error handlers in the codeblock, so MyError()
will be called first, resulting in an "An error occured..." message.
Then DefError() (stored in bOldBlock) will be called resulting in an
alert complaining about an argument error. And an application crash.

//-------------------------
proc main()
local i, bOldErrBlock
bOldBlock := errorblock( { |oErr| MyError( oErr ) } )
errorblock( { |oErr| MyError( oErr ), eval( bOldBlock, oErr ) } )
for i := 1 to 3
begin sequence
do case
case i == 1
? '1 + 2 equals '
?? hb_ntos( 1 + 2 )
case i == 2
? '1 + x equals '
? 1 + 'x'
case i == 3
? '1 + 3 equals '
?? hb_ntos( 1 + 3 )
endcase
end sequence
next
return
proc MyError( oErr )
? 'An error occured in line ' + hb_ntos( procline( 2 ) )
// No break here or bOldBlock will not be executed!
return NIL
//-------------------------

Regards,
Klas

Claudia Neumann

unread,
Sep 7, 2012, 3:54:27 PM9/7/12
to harbou...@googlegroups.com
Hi Viktor,
"Local function"? Does that mean, the error function has to be in the same file
as the function where the error can occur?

I first had named the file ERRORLIN.PRG with the errorblock and the error
function to differentiate the code from the ERRORSYS.PRG for the Clipper
program. The error function was executed but would not return to the function
where the error occurred and hb_out.log showed the error messages from
ERRORLIN.PRG and from /src/rtl/errsys.prg. After I renamed ERRORLIN.PRG to
ERRORSYS.PRG the error handling did what I intended it to do.

Just my impression.

Best regards

Claudia

Klas Engwall

unread,
Sep 7, 2012, 7:30:38 PM9/7/12
to harbou...@googlegroups.com
Hi Claudia,

>> There is no need to do that. Just write your own
>> handler function and change the error handling block
>> to call your own local function. Works the same as
>> in Clipper 5.
>
> "Local function"? Does that mean, the error function has to be in the same file
> as the function where the error can occur?

I think Viktor meant "local to the project" or "local to the developer".
You can have it anywhere. Try one of my samples and split it into two
separate prg files.

> I first had named the file ERRORLIN.PRG with the errorblock and the error
> function to differentiate the code from the ERRORSYS.PRG for the Clipper
> program. The error function was executed but would not return to the function
> where the error occurred and hb_out.log showed the error messages from
> ERRORLIN.PRG and from /src/rtl/errsys.prg. After I renamed ERRORLIN.PRG to
> ERRORSYS.PRG the error handling did what I intended it to do.

Then maybe we should take a look at what you wrote, including how you
set up ErrorBlock() and the SEQUENCE.

Regards,
Klas

vszakats

unread,
Sep 8, 2012, 2:39:32 AM9/8/12
to harbou...@googlegroups.com
Hi Claudia,
 
> There is no need to do that. Just write your own
> handler function and change the error handling block
> to call your own local function. Works the same as
> in Clipper 5.

"Local function"? Does that mean, the error function has to be in the same file
as the function where the error can occur?

No, the function only has to be visible from the codeblock 
passed to ERRORBLOCK(). It can even be STATIC.

I first had named the file ERRORLIN.PRG with the errorblock and the error
function to differentiate the code from the ERRORSYS.PRG for the Clipper
program. The error function was executed but would not return to the function
where the error occurred and hb_out.log showed the error messages from
ERRORLIN.PRG and from /src/rtl/errsys.prg. After I renamed ERRORLIN.PRG to
ERRORSYS.PRG the error handling did what I intended it to do.

Just my impression.

hb_out.log? It's default output for _internal_ errors, so now 
I don't understand why you'd like to do. But for sure there 
is no need to do any hops and tricks replacing core modules 
to define your own runtime error handler.

-- Viktor

Claudia Neumann

unread,
Sep 8, 2012, 5:45:06 AM9/8/12
to harbou...@googlegroups.com
Hi Viktor, hi Klas, hi all,

okay, my fault. I can't recontruct now, why I had the impression that the
ERRORBLOCK() has to be in ERRORSYS.PRG. It just works also in ERRORLIN.PRG.

I attach my ERRORLIN.PRG. It gives more information about the error than
/src/rtl/errsys.prg and uses some memvars in my program to retrieve the current
database and add some function for correction. Sorry, it is not hbformated.

I solved the "APPEND FROM" error like this:
cfile is the file that should be updated, which could have an error in database
structure.
The function fbasis(cfile) gives the name of an empty database with the right
database structure corresponding to cfile.

-----------------
function fappendfrom(cfile)
memvar cErrFile
cErrFile := cfile
begin sequence
append from (cfile)
recover
fdbfehler(cfile)
cErrFile := ""
end sequence
return .t.

function fdbfehler(cfile)
local nselect,astruct1,astruct2,vdbf2
local nn1,nn2,nn3,nn5,nn6
local cfieldname,vfeldinhalt
*
close all
*
nselect := select()
select 1
use (cfile) alias orig exclusive
pack
nn1 := fcount()
nn5 := lastrec()
astruct1 := DbStruct()
*
select 99
vdbf2 := fbasis(cfile)
ferase("tmp.dbf")
copyfile(vdbf2+".dbf","tmp.dbf")
if !file("tmp.dbf")
? "can not create temporary database tmp.dbf"
return .f.
endif

use ("tmp.dbf") alias new exclusive

for nn2 := 1 to nn5
append
next

astruct2 := DbStruct()

for nn2 := 1 to nn1

for nn3 := 1 to len(astruct2)

if fieldname(nn3) == astruct1[nn2,1] ;
.and. fieldtype(nn3) == astruct1[nn2,2] ;
.and. fieldlen(nn3) == astruct1[nn2,3] ;
.and. fielddec(nn3) == astruct1[nn2,4]

cfieldname := fieldname(nn3)
for nn6 := 1 to nn5
select 1
go nn6
select 99
go nn6
vfeldinhalt := orig->&cfieldname
fReplace("new",cfieldname,vfeldinhalt)
next
endif
next
next
close all
select(nselect)

return .t.

function fReplace(cdbf,cfeld,cinhalt)
replace &cdbf->&cfeld with cinhalt
return nil
----------------

Best regards

Claudia (still learning)
ERRORLIN.PRG

Klas Engwall

unread,
Sep 8, 2012, 5:00:04 PM9/8/12
to harbou...@googlegroups.com
Hi Claudia,

> okay, my fault. I can't recontruct now, why I had the impression that the
> ERRORBLOCK() has to be in ERRORSYS.PRG. It just works also in ERRORLIN.PRG.
>
> I attach my ERRORLIN.PRG. It gives more information about the error than
> /src/rtl/errsys.prg and uses some memvars in my program to retrieve the current
> database and add some function for correction. Sorry, it is not hbformated.
>
> I solved the "APPEND FROM" error like this:
> cfile is the file that should be updated, which could have an error in database
> structure.
> The function fbasis(cfile) gives the name of an empty database with the right
> database structure corresponding to cfile.

We have talked for days now (at least I have :-) ) about error handlers
and how to set them up with ErrorBlock(). But I see none of that in your
code. You have a cleanup routine that you call after RECOVERing. That is
fine, but you will never get there because you still have the original
DefError() as your error handler, and it will not send you back to
fappendfrom() after an error except for a few special cases (see the
original errorsys.prg). This is what prompted your previous "Recover has
no effect" comment.

You have to supply an error handler that will replace DefError() for the
duration of your import routine. It can be in "whatever.prg", and it can
be as short as the Myerror() examples I posted, minus even the error
message I put in there (it was only put there to show you where you
were). But you also have to set up your error handler with the
ErrorBlock() function before BEGIN SEQUENCE, and you should also
reinstate the original error handler, or an extended version of it if
you like, after END SEQUENCE.

Did you study my examples at all?

Regards,
Klas

Qatan

unread,
Sep 8, 2012, 5:10:36 PM9/8/12
to harbou...@googlegroups.com
I can confirm that. That’s the way I usually do too.
 
Qatan
--
You received this message because you are subscribed to the Google
Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com
Web: http://groups.google.com/group/harbour-users

Claudia Neumann

unread,
Sep 9, 2012, 2:43:02 AM9/9/12
to harbou...@googlegroups.com
Hi Klas,

I have looked and tested your examples and I have solved the error:

I get an error subCode 1020 and now I get an alert() (at line 304). The
following break initiates the correction function.

That is what I wanted: the information which file is affected and I try to
correct it. I can not know if the correction succeeds in all cases.

Yes, this file should finally substitute the /src/rtl/errsys.prg. It is a start.

Best regards

Claudia
Reply all
Reply to author
Forward
0 new messages