Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Error No 5 Record is out of range 1

Status
Not open for further replies.

mstrcmtr

Programmer
Nov 14, 2007
103
PK
What are the reasons of the following error and how to avoid this error

Record is out of range

Working in multi user environment

 
Pretty well what the message says.

Typically, it happens if you try to go to a record number that is beyond the end of the table. So, if the table has 100 records, and you [tt]GOTO 101[/tt], you will get that error. Also if you try to go to a negative record number (there is an exception to that, but it's probably not relevant so I won't confuse the issue).

You might also see it if the index is corrupted. If you think that might be the case, try to REINDEX the table.

The fact that you are in a multi-user environment is probably not relevant.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I recently rambled about RECNO as bad way to remember a record position to go back to in thread184-1786102

Take any table, no special settings required. Do this:
Code:
USE your.dbf
GO Bottom
SKIP 1
? RECNO(), RECCONT()
GOTO RECNO()

This just shows one of several situations, in which RECNO() can be a record number you can read and "have" but not GOTO.

Bye, Olaf.
 
The lesson rather is, when remembering the position to go back to, you can't always go back to what RECNO() gave you previously.
And it's answering why you can get this error 5. In my sample code that doesn't happen at the line SKIP 1, but at GOTO RECNO(), which you would naively expect to always work.

Besides notice the output of this:
Code:
ON ERROR ?? ERROR(), MESSAGE()
USE foxcode.dbf
GO Bottom
? EOF(), RECNO(), RECCOUNT() && output .F., 1008, 1008
SKIP 1
? EOF(), RECNO(), RECCOUNT() && output .F., 1009, 1008
? "GOTO RECNO():"
GOTO RECNO() 
? "SKIP 1:"
SKIP 1

Your exact record count may vary as you can extend foxcode, but it's a system table for intellisense you should have with VFP7 and above.
SKIP 1 at EOF() errors with error 4, not error 5, so it's very likely you encounter error 5 = record out of range from a GOTO RECNO of a record number you previously encountered.

There is an obvious truth in not skipping 1 at EOF, that errors with error 4, but is not directly related. You can already be quite sure you won't be able to GOTO the same record, if you save the current RECNO(), while you're at EOF(), that's more to the point. The ideal way to get back to a record you started with is remembering its primary key value, not its record number. If you stick for RecNo, as it's generally available, say you store [tt]lnRecno=RECNO()[/tt] then you need to deal with errors you encounter at [tt]GOTO lnRecno[/tt], there are more cases than the one higher than RecCount Recno at EOF() this code shows, in buffering modes RECNO() of new records is negative and only becomes positive when it's saved. And in record buffering that will happen if you leave the record. If you also store RecCount() at the time you could get to the record previously having the negative record number by navigating to the previous RECCOUNT and then SKIP forward -lnRecno records, which is skipping forward, as lnRecno<0.

But instead of getting all that complicated about the GOTO handling, rather remember IDs of the record you want to go back to and use that for record navigation via SEEK. you still always should cover cases of not finding a record, which could be deleted in the meantime, so any such mechanism of remembering a position to go back to us bound to fail under special conditions and likely works in first tests, if you never test special cases.

Bye, Olaf.
 
Just recently I was suffering the same issues, I found:-

This didn't work:-
Code:
IF NOT EOF()
	SKIP 1
	ELSE
	SKIP -1
ENDIF
But this did:-
Code:
IF NOT EOF()
	SKIP 1
ENDIF
*
IF EOF()
	SKIP -1
ENDIF

Regards,

David.

Recreational user of VFP.
 
Mike Y. said:
Code:
IF NOT EOF()
SKIP
ENDIF

I disagree. If you are on the last record, you are not yet at EOF, so the above code will skip to eof, which is not where you want to be. I would prefer:

Code:
SKIP
IF EOF()
  SKIP -1
ENDIF

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Replacing my double IF/ENDIF Statements with Mike's code worked ok in my application. Although they are doing the same job Mike's Code was more elegant than mine! Thanks Mike.

Regards,

David.

Recreational user of VFP.
 
David, it's OK to check EOF() before SKIP 1, too, because you always can be at EOF through a LOCATE not finding something, for example.

It's off topic in regard of the error 5, though, as you don't get it through skipping forward or backward alone. Notive SKIP at EOF causes error 4.

Well, when we're at navigation, then the full way to do it: You already can öook it up, it's in foxpro sample code multiple times! In FFC base classes you can take _navbtns from _datanav.vcx for navigation. Here's the essential code:
Code:
* first botton:
Locate
this.RefreshForm()

Code:
* previous button:
IF NOT BOF()
	SKIP -1
ENDIF
this.RefreshForm()

Code:
* next button
IF NOT EOF()
	SKIP
ENDIF
IF EOF()
	SKIP -1
ENDIF
this.RefreshForm()

Code:
* last botton:
Go Bottom
this.RefreshForm()


The idea of a refreshform() method could in the simplest case just call THISFORM.REFRESH(), it cascades and even the navbar you are working from could, for example, enable/disable buttons depending on record pointer. When you already SKIP -1 after detecting EOF(), that means you can't detect being at the bottom via checking EOF() in Refresh() code, so that would need another SKIP 1 and EOF() check because checking RECNO()=RECCOUNT() won't give you the correct answer in the general case data is sorted by any index. So notice how quirky that all gets. It's no wonder many navbars fail to work properly all of the time, but they never cause error 5, unless you offer a goto button using a wrong recno.

Nevertheless, exactly what you had in terms of next button is good and better by not simply doing SKIP without first checking EOF(), to avoid error 4. To avoid being at EOF AFTER clicking the next button you test EOF() again after SKIP and then SKIP -1, as here. But this doesn't prevent any other reason to get to EOF(). And not any other reason to get to error 5. You can't make this airtight by a perfect navigation, but it contributes to less EOF() problems if you incorporate that.

Anyway, you need to watch out before any REPLACE, silently doing nothing at EOF(). Notice, FOUND() is just a synonym for NOT EOF(), that means when FOUND() is false, Locate has really put the record pointer to EOF. Go Bottom only puts it to the last record before EOF, so that is perfect for the "last" button and GO TOP is the usual way to go to the first record, but LOCATE without any FOR condition is better optimized, especially in case of data sorted by an index, again, so your "first/top" button would do [tt]LOCATE[/tt] and your "last/bottom" button would do [tt]GO BOTTOM[/tt], another asymmetry.

Final words still are: Even with the perfect navbar button behaviour you're not failsafe against any other code working in thw wrong workarea are explicitly the right but not repositioning after getting to EOF(). Even with button disabling to avoid impossible navigation, this only happens when you actively call the refreshform, there is no event, if a LOCATE repositions a record pointer, etc. So navbar button can reflect a wrong situation.

It's a very general rule that you can't rely on the outset being in your full control and you don't need to check before doing something. So also in case of the error 5, you can do so in TRY..CATCH

Bye, Olaf.
 
Olaf,
Many thanks for your reply, very interesting. I will follow your Code and advice posted on this thread.


Regards,

David.

Recreational user of VFP.
 
OK, I tidied up a bit and split code for the various buttons, there's still more to it, if you want to enable/disable buttons. Also this doesn't yet address activating the correct workarea, that's a prerequisite.

What never makes things airtight is, that you typically have code doing LOCATEs. Setting a FILTER or requiring data changes the current situation, too. I don't think much of navbars, as the natural way to navigate a list is the scrollbar a grid provides. It might be nice to have top/bottom as extra buttons, but otherwise, you have a window listing a few rows and you pick one by a click. It's also possible to navigate that with keyboard only.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top