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!

APPEND BLANK fails to move pointer

Status
Not open for further replies.

SimplyES

Programmer
Oct 5, 2012
39
GB
I have a very simple form, with a very simple INIT which (simply) does APPEND BLANK IN cursorName and then displays a half dozen fields - always with the contents of an existing poputlated record. If I set a break point just before the APPEND, and then step through, it does exactly what it should do and presents the displayed form with empty fields. I have tried adding in GO BOTTOM - no difference. Now scratching my head.
 
FWIW, I never, absolutely never, use Append Blank. Instead I always use Insert Into. It's much faster and safer, and it makes it easier if you later want to switch from DBFs to another backend.
 
No idea when APPEND BLANK would fail that way, I guess something else later does some GOTO or SEEK or LOCATE, instead of debugging record a coverage log and see what's executing.
You'll also later be able to APPEND BLANK into a cursor of an updateable view/remoteview/sqlexec cursor/cursoradapter cursor, so no worries about APPEND BLANK itself.

Bye, Olaf.

Olaf Doschke Software Engineering
 
SimplyES, since you are issuing [tt]APPEND BLANK [highlight #FCE94F]IN[/highlight][/tt], aren't you working with different work areas? Are you sure that the controls in your form are explicitly bound to the fields of the cursor to which you are appending a blank record?
 
Keep in mind that the form's Init is executed after all the controls have been initialised. If the controls get their values from their ControlSources, these will have been set before you do the Append Blank. So the solution might be as simple as refreshing the form after you have added the new records.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike has a food point, early binding to data before you're really ready can have bad side effects,

Consider using Form.BindControls=.F. and only set that .T. after you issued the APPEND BLANK.

Bye, Olaf.

Olaf Doschke Software Engineering
 
INSERT INTO 'faster and safer' than APPEND BLANK?

Better for moving back-ends perhaps, but faster or safer? Not sure I see that (never having used the INSERT INTO approach in VFP)

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
I agree, Griff. I don't see why it should be safer. It might or might not be faster, but I can't see that being an issue since we are only appending a single record and doing so while the form is initialising.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I can see the APPEND BLANK followed by a field by field REPLACE WITH being slower if you do each replace on a separate line:

Code:
APPEND BLANK
REPLACE FIELD1 with m.FIELD1
REPLACE FIELD2 with m.FIELD2
REPLACE FIELD3 with m.FIELD3
REPLACE FIELD4 with m.FIELD4
REPLACE FIELD5 with m.FIELD5
REPLACE FIELD6 with m.FIELD6

That would be somewhat slower to do, but for a single record I think it would be hard to measure the effect, and has the advantage of being able to search for all occurrences of
REPLACE FIELD1 WITH later when you are maintaining the system...

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
I did give INSERT INTO a go but the outcome is the same. I have also tried refreshing the fields (rather than the whole form) after APPEND in the INIT.

atlopes: Your point understood. Using IN with APPEND is a habit for me. However, I did pop a SELECT cursorName ahead of it as well - no change.

I did run coverage log and nothing unexpected appears in between any of the steps.

If I put breakpoint late in the process and open the cursor to BROWSE, the pointer is definitely on the populated record rather than the new blank.

The thing that makes me frown is that it all works as any of us would expect if I step through with debug.

 
Can't see an advantage then.
Been using APPEND BLANK since dBaseII, I think there was an INSERT back then, that physically inserted a record after the current one and shuffled the rest down.
I do use INSERT INTO for SQL stuff, where I'm using Classic ASP to update a VFP database via OLEDB, but not in VFP itself.

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
Griff said:
I think there was an INSERT back then, that physically inserted a record after the current one and shuffled the rest down.

That is correct. It was one of those commands that almost nobody ever used. (Another one was SORT.)

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi,

Have you checked there is no filter condition still active? Use SET FILTER TO to make sure you see all records.

Regards, Gerrit
 
INSERT INTO 'faster and safer' than APPEND BLANK?"
My 2 cents, INSERT INTO takes the values and updates the table and index at the same time. Whereas APPEND BLANK with REPLACE or GATHER MEMVAR updates the index twice. Once with the blank record then once more with the values. Granted, it don't make much difference for a single record update like the instance above, but it can slow things down quite a bit if there are a lot of records being updated.


-Dave Summers-
[cheers]
 
SimplyES, please do a coverage log, as I suggested earlier:

In your code right before APPEND BLANK put
Code:
SET COVERAGE TO ADDBS(GETENV("TEMP"))+"append.log"
APPEND BLANK

Then in the Forms control with lowest tab order and tabstop=.t. in the gotfocus put
Code:
SET COVERAGE TO
to turn off the logging. This part is not that important, it just shortens the log to essential code. You might also put a button on the form and put the SET COVERAGE TO into its click event, so you end the log after you're sure the effect already happened.

Now start all this, close VFP afterward and look at that log to see which code runs. The log doesn't contain the text of the source code but control.method names and line numbers, you might find DBC events triggers functions called in index tags, field-, and table rule calls. And many things of that might move the record pointer. I'm sure you'll see why the record pointer is moved, APPEND BLANK will put it on the new blank record unless an insert trigger prevents creating a new record at all and the record pointer stays put where it was, but that trigger code run would also appear in the coverage log.

There are only slight things not recorded with coverage log, eg all expression evaluations in properties, unless they call into PRGs or methods. You can also get "jumps" in the code you don't expect through timers, BINDEVENTS, there might be something run on assigning an alias to the grid or setting any other properties with assign methods.

The debugger causes many focus-change related events and might cause a fix you don't have when not debugging. Timer events might run and "fix" the issue, just because you debug and you don't see that, because by default the debugger doesn't single step through timer events, that would cause a mess when a timer runs tightly, you won't get to single stepping through the code you want to single step through. In contrast, when you don't debug, all code takes so short no timer event happens, it doesn't run at all, even not invisible.

It's safe to assume it's never APPEND BLANK causing any other record pointer move than that to the new blank record. It has to be insert trigger code or table/field rule or index expressions calling code that could move record pointer.

VFP has tools to read in the coverage log and display timing recorded and what code sections were covered/&executed (therefore its name), but that'll not help you see the order of code as it run that shows by simply looking at the log in notepad. There shouldn't be much lines of code between APPEND BLANK and the Gotfocus of the first control. Maybe some other control inits, form init, show and activate.

Bye, Olaf.

Olaf Doschke Software Engineering
 
You may also embed some info into the coverage log (as shown in thread184-1775724), like the record number RECNO() direclty before and after APPEND BLANK:

Code:
SET COVERAGE TO ADDBS(GETENV("TEMP"))+"append.log"
cInfo = strtran("record_"+transform(RECNO(grid.recordsource)),"-","minus_")
=EXECSCRIPT("beforeappend_&cInfo()"+CHR(13)+"Procedure beforeappend_&cInfo()"+CHR(13)+"return"+CHR(13)) 
APPEND BLANK IN (grid.recordsource)
cInfo = strtran("record_"+transform(RECNO(grid.recordsource)),"-","minus_")
=EXECSCRIPT("afterappend_&cInfo()"+CHR(13)+"Procedure afterappend_&cInfo()"+CHR(13)+"return"+CHR(13))

You can repeat these two lines for logging the RECNO at any place you would assume the record number may change or have already changed to narrow that down.
If the number doesn't change after APPEND BLANK you know a new record was rejected, for example. Say your new record has RECNO() -1 then you'll find the procedure name afterappend_record_minus_1 in the final coverage log. And that will be the RECNO of the new record.

By the way, it's normal, that new records have negative RECNO when you buffer. You only get the final RECNO, when the record is committed into the DBF. Therefore and because "-" isn't allowed in a procedure name, the STRTRAN of "-" to the word "minus".

Bye, Olaf.

Olaf Doschke Software Engineering
 
Not at all sure I'm getting the expected output from coverage log!

Here is the INIT script - SET COVERAGE TO is in the gotfocus event of the first textbox on the form. As you can see, there really isn't a lot going on, so not many obvious opportunities for it to go wrong:

LPARAMETERS tnLeft, tnTop, tnMode, tnBackColor
** Set varying screen position of form
WITH thisform
.Left = tnLeft
.OTLRowHeight = 18
.OTLTopRow = 83
.Top = tnTop
ENDWITH
** If not in edit mode, add new blank record
IF tnMode = 1 && Add New
SET COVERAGE TO ADDBS(GETENV("TEMP"))+"append.log"
cInfo = strtran("record_"+transform(RECNO('mqItems')),"-","minus_")
=EXECSCRIPT("beforeappend_&cInfo()"+CHR(13)+"Procedure beforeappend_&cInfo()"+CHR(13))
APPEND BLANK IN mqItems
cInfo = strtran("record_"+transform(RECNO('mqItems')),"-","minus_")
=EXECSCRIPT("beforeappend_&cInfo()"+CHR(13)+"Procedure beforeappend_&cInfo()"+CHR(13))
ENDIF

Here is the output listing from append.log

0.000174,,mqientry.init,13,m:\mcafrodev\forms\mqientry.sct,6
0.003531,,mqientry.init,14,m:\mcafrodev\forms\mqientry.sct,6
0.000052,,0000b56x00rp,1,c:\users\dks\appdata\local\temp\0000b56x00rp.fxp,7
0.000140,,mqientry.init,15,m:\mcafrodev\forms\mqientry.sct,6
0.000091,,mqientry.init,16,m:\mcafrodev\forms\mqientry.sct,6
0.003718,,mqientry.init,17,m:\mcafrodev\forms\mqientry.sct,6
0.000048,,0000b56x00rr,1,c:\users\dks\appdata\local\temp\0000b56x00rr.fxp,7
0.000117,,mqientry.init,18,m:\mcafrodev\forms\mqientry.sct,6
0.000259,,mqientry.txtmqidetailentry.gotfocus,1,m:\mcafrodev\forms\mqientry.sct,6

My understanding is that the output log should have record_x where 0000b56x00rp and 0000b56x00rr is showing.
 
0000b56x00rp and 0000b56x00rr are the names EXECSCRIPT generates for executing the whole scripts. You have to go back to my edited post and add "return", so there is a line in the generated procedures, which executes and becomes part of the log. Optional, but I named the procedures with beforeappend_ and afterappend_, too.

We'll see what shows as the recno, then.

But it seems to me the change of pointer has to be somewhere later. So you better not stop logging in the GotFocus(), but use the coverage log stop button idea. Only after you see the wrong record activated in the grid stop the coverage log and see.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top