Sign up on the Revelation Software website to have access to the most current content, and to be able to ask questions and get answers from the Revelation community

At 30 DEC 1997 11:47:41PM Don Bakke wrote:

I know that keeping indexes on a symbolic field runs the danger of having those indexes out of synch, especially when the data that affects these symbolics is altered in a way where the system has no way of knowing that an index needs to be updated.

However, if I know in advance that this dependent data is going to be modified, is there a way that I can manually (i.e. programmatically) get the index to become updated without having to rebuild it?

Thanks,

[email protected]

SRP Computer Solutions


At 01 JAN 1998 02:00PM Cameron Revelation wrote:

Don,

The simplest way is to lock, read, write, and unlock the record that must be re-indexed. This will put it into the list of keys that will get processed when the index gets flushed. I am sure there is a function that does this directly for you but I don't know what it is. (Maybe Aaron would know.)

Cameron Purdy

Revelation Software


At 01 JAN 1998 04:26PM Aaron Kaplan wrote:

Well, you could write %ALL.IDS% to the 0 record of the !file then call index.flush…

No, there's no real program that will do that. However, there is that dependant index thing I was talking about in another thread. I can't remember how to do it though. It involved hacking dictionaries to create dependancies based on the relational index hooks which allowed for the symbolic updates. There might be something on CI$, but this computer doesn't have access (well, it does, it has a modem, but I'm dialed into a different ISP, and I can't remember how to telnet across and it's been a long time since I did the CIS ASCII interface stuff anyway). Andrew also had something in one of the older Revmedia vols (vol2 maybe) so when he gets home, maybe he'll be kind enough to post. If you have the on-line look-up, you should be able to find it in there.

I was showing this to someone not that long ago and it worked in 2.6, so it still should work. One word of caution, make a backup before you do this, since this does all sorts of fun things with your index control records.

Your only other option is to do some of this handling yourself and write a few well placed MFS's used in conjunction with a couple of relationals and you should be able to handle this seamlessly.

[email protected]

Sprezzatura, Inc.

www.sprezzatura.com_zz.jpg


At 02 JAN 1998 06:30AM Andrew P McAuley wrote:

First - rebuilding…

Gordon French of Fort Lauderdale recently asked, with reference to the INDEX.SUB program included on Utility Diskette Number 1, "How is it possible to force a rebuild of an index for a file?". The INDEX.SUB routine does not actually force a rebuild as it assumes that you will be rebuilding after adding a new index, in which case it will work perfectly. If however, it is suspected that the indexes have become corrupted it can be long-winded calling INDEX.SUB to remove, readd then rebuild the indexes.

It is possible to instruct the system to rebuild the index for a field by

mimicking the action taken by the system when it adds an index to a field.

The system simply writes a record to the !INDEXING file, containing

information about the file to update and the keyword ALL.IDS. The listing below shows a generic routine designed to allow the rebuilding of indexes from within an RBASIC program. To use, call with the file name and the field name/index name (EG USER, COMPANY_NAME.XREF, CUST*INV*AR). Note,

network users should ensure they incorporate locking logic into this

subroutine.

   SUBROUTINE REBUILD_INDEX(FILE,FIELD)
  • Author AMcA
  • Date Jan 91
  • Purpose To rebuild an index for a field
  • COPYRIGHT Sprezzatura Ltd 1991. Permission given to
  • REVMEDIA subscribers to use in any form.
    DECLARE SUBROUTINE FSMSG
    OPEN "!INDEXING" TO IFILE THEN
     GOSUB GET_VOL_INFO
     GOSUB UPDATE_INDEX_FILE
    END ELSE
     FSMSG()
    END
   RETURN
   GET_VOL_INFO:
    FILE_REC=XLATE("FILES",FILE,"","X")
    VOL_REC =XLATE("VOLUMES",FILE_REC,"","X")
    VOL_INFO=FILE_REC:"*":FILE_REC:"*":VOL_REC
   RETURN
   UPDATE_INDEX_FILE:
    UPDATE_REC   =VOL_INFO      ; * Volume Information
    UPDATE_REC=1             ; * Number of transactions
    UPDATE_REC=FIELD         ; * Index to update
    UPDATE_REC=%%ALL.IDS%%" ; * Rebuild Flag
    UPDATE_REC   := @FM : @FM : @FM
    READ ZERO_REC FROM IFILE, "0" ELSE ZERO_REC=@FM
  • Ensure there is a trailing field mark
    IF INDEX(ZERO_REC,@FM,1) ELSE ZERO_REC := @FM
    ZERO_REC := UPDATE_REC
    WRITE ZERO_REC TO IFILE, "0"
    CALL INDEX.FLUSH(VOL_INFO,'')
   RETURN

(Volume 2, Issue 8, Page 7)

[email protected]

Sprezzatura Ltd

World Leaders in all things RevSoft


At 02 JAN 1998 06:36AM Andrew P McAuley wrote:

and the rest…

Indexing on Symbolics is one of the most powerful features of AREV indexing

- creating a symbolic which concatenates three fields together and BTREEing

this can dramatically improve the performance of three level sorts when the

required three levels are known in advance.

In an effort to implement databases in a relational manner it is customary

to store foreign keys in data records pointing to data records in an

external table where repeating data can be kept. A classic example of this

would be an employee record containing a departmental ID. Rather than store

all details about the department in the employee record, the department id

is stored and all additional information about the department is XLATEd as

required.

This works in a wholly satisfactory manner until fast reporting is required

on a derived field (for example, sorting the Employees by Department Name).

If a Btree is established on the Department Name symbolic in the Employee

file, the report will run correctly until a department name is changed in

the Department file. When the department name is changed, the Employee

record Department name symbolic is not updated (the only write is that of

the department record so the employee department symbolic is not

reevaluated), and the Employee index becomes out of sync. Thus if there were

three employees in departments as follows, and the list was sorted by a

btreed dept. name

        BROWN A   100  BOUGHT LEDGER
        SMITH J   200  PERSONNEL
        JONES A   300  STAFF ACCOUNTING

and the STAFF ACCOUNTING department was changed to PAYROLL the employee list

would now display in an incorrectly sorted order.

        BROWN A   100  BOUGHT LEDGER
        SMITH J   200  PERSONNEL
        JONES A   300  PAYROLL

What is required is a method whereby whenever a department name is changed,

all symbolics referring to that field in other files are reevaluated and the

corresponding indexes updated. To do this several conditions, must be met

        System must know which records reference the changed record
        System must know of existence of indexes on external records
        System must detect change and reevaluate external symbolics

An undocumented feature permits the system to keep track of these details

for the user, subject to the usual restrictions on relational indexes.

(Sticking to the example given above, one department could not have more

than 64K of employees keys related to it).

The steps involved in setting up this feature are straightforward. Using

the example given above

        Add BTREE to Department Name symbolic in Employee file and build
        the index
        As a relational index is to be set up between the Employee file
        and the Departments file, add a multivalued field definition (EG
        EMP.KEYS) to the Department file to store the relationally indexed
        keys from the Employee file.
        Define a relational index from the Department Number in the
        Employees files to the EMP.KEYS field in the Department file.
        (This is most easily accomplished from Shift-F1 in the DICT window
        rather than the indexing menu).
        At TCL, edit the symbolic which XLATES the description (in this
        case the Department Name Symbolic in the Employees file).  Ensure
        that no extra lines are inserted or deleted by turning Ins Line
        off.  Move the cursor to line 21 (the "depends on" field) and
        define this item as related to the department file by inserting
        information in the format FILE*FIELD, in this case
        DEPARTMENTS*EMP.KEYS.  Save this symbolic.  (Try a LISTINDEX on
        Employees to see "Depens").

The link is now established and the symbolic on the btree will now be

automatically updated.

Note that if more than one independent link is required, Field 21 can be

multivalued.

Caveats

This method can occasionally "hang" in a networked environment. To consider

the scenario - when you write a record to disk and an index update is

required, SI.MFS locks record 0 in the !INDEXING file, then evaluates the

necessary index updates and writes the transactions to !INDEXING. After the

transactions are written, the lock on !INDEXING is released. Whilst one

station has the lock, other stations cannot save transactions but must wait

for the transaction lock. This is evidenced by the "Waiting for Index

Transaction Lock" message.

If you change a master record which has, for example, 2,000 associated

records, the system must evaluate the results of the change for all 2,000

associated records. The !INDEXING lock will be kept for some time, and other

stations trying to save their records will be delayed. Normally the message

will disappear if left, and is a small price to pay for the convenience.

This problem seems to be worse in releases prior to 2.0.

(Volume 2, Issue 4, Pages 5,6)

[email protected]

Sprezzatura Ltd

World Leaders in all things RevSoft


At 02 JAN 1998 01:07PM Don Bakke wrote:

Cameron, Aaron, and Andrew,

First, thank you very much for your consideration and help with this matter. The information provided, especially the tech bulletin, is very interesting and possibly helpful in many scenarios. Howevever, here is a direct example of what I need:

I have an INVOICE table. It has a data field INVOICE_DATE and a mv-field PAYMENT_DATE. It also has a symbolic field called INVOICE_MONYR (which is based on INVOICE_DATE) and a mv-symbolic field called PAYMENT_MONYR (which is based on PAYMENT_DATE). There are Btree indexes on all four fields.

INVOICE_MONYR index is always correct since INVOICE_DATE is entered via the Invoice window and the system knows to update the INVOICE_DATE and INVOICE_MONYR indexes.

PAYMENT_MONYR index is not always correct since PAYMENT_DATE can either be entered directly into the Invoice window (which updates the index) or in batch mode through a dialog box which then programmatically updates the necessary records. It's in this latter case that the PAYMENT_MONYR index begins to get out of sync.

So I'm not sure how Andrew's article will help me here as I'm not dealing with multiple tables. This was why I was wondering what is the method that OI/AREV uses when it knows it's supposed to update a symbolic index. In the event of the batch processing described above I would simply duplicate that work myself.

Any more thoughts would be appreciated,

[email protected]

SRP Computer Solutions


At 02 JAN 1998 03:02PM Cameron Revelation wrote:

Don,

I have an INVOICE table. It has a data field INVOICE_DATE and a mv-field PAYMENT_DATE. It also has a symbolic field called INVOICE_MONYR (which is based on INVOICE_DATE) and a mv-symbolic field called PAYMENT_MONYR (which is based on PAYMENT_DATE). There are Btree indexes on all four fields. INVOICE_MONYR index is always correct since INVOICE_DATE is entered via the Invoice window and the system knows to update the INVOICE_DATE and INVOICE_MONYR indexes. PAYMENT_MONYR index is not always correct since PAYMENT_DATE can either be entered directly into the Invoice window (which updates the index) or in batch mode through a dialog box which then programmatically updates the necessary records. It's in this latter case that the PAYMENT_MONYR index begins to get out of sync.

When I responded originally, I thought you were indexing the result of an XLATE. That is a more complicated scenario (as you can see from Andrew's tech bulletin).

Since the fields are all coming from the same record, there should be no problem with the symbolic updating automatically if the system can determine the dependencies. When you run the following command, it should return a comma delimited list of field numbers that are depended on by the fields. I reproduced your table structure as described, and the following returns "1,2" which is correct for my dictionary.

run dict_depend 'INVOICE*INVOICE_MONYR', 'PAYMENT_MONYR'

Does it show the correct field number dependencies for your dictionary?

Cameron Purdy

Revelation Software


At 02 JAN 1998 06:31PM Don Bakke wrote:

Cameron,

Does it show the correct field number dependencies for your dictionary?

Yes it does. However, something you said made me think that my conception of how indexes on symbolics (i.e. those with dependent data fields) get updated is all wrong.

My assumption had been that these indexes only get updated if the dependent data is modified within the window.

Now I get the impression that they will still get updated even if the data is modified programmatically or even from the Editor. Is this correct? If so, then are the dependencies stored outside of the window, like in the dictionary? And is SI.MFS calling the shots on everything?

If this is the case I need to revisit a lot of my work and see where my indexes are really out of sync and make sure we're not talking about Xlated stuff. Thanks,

[email protected]

SRP Computer Solutions


At 03 JAN 1998 04:46AM Andrew P McAuley wrote:

Don

It should do it regardless of where the change is made as ALL index logic is at the MFS level.

[email protected]

Sprezzatura Ltd

World Leaders in all things RevSoft


At 03 JAN 1998 08:55AM Don Bakke wrote:

Andrew,

It should do it regardless of where the change is made as ALL index logic is at the MFS level.

It had totally slipped my mind that MFS will operate no matter how the table gets accessed. Well at least the topic generated that article you reprinted for me so it was worth it!

BTW, is that article in the REVMEDIA-FKB? I don't think I ever saw it (but then I haven't looked for articles on this specific topic either).

Thanks again,

[email protected]

SRP Computer Solutions


At 03 JAN 1998 09:43AM Aaron Kaplan wrote:

SI.MFS is a pretty simple program, at least for the purposes of a write. All it does is pass control to the ! record of the !FILE. The ! record is simply a psuedo dictionary record, or at least it's code compilation is the same as a dictionary, instead of regular source code. SI.MFS executes this with a calculate or calculatex (probably the latter).

Now, the beauty of all this (and I think this is true system design elegance) is you have total control over this program, if you want it. All you need to do is compile a program as a dictionay (pretty simple with RTP5) and stick it back as the ! record.

It's also possible to see what it is the system is doing. Source code at it's finest. What you need to do is pretty simple as well.

  • Create a !! record in the !FILE
  • Delete the ! record (using delete_row in OI or deleterow/deleterec in ARev)
  • Detach and re-attach the table
  • Open the data table

(Incidentally, this was documented in the ARev 1 manuals, if no where else. No hidden tricks, or inside secret knowledge.)

In ARev, you'll see the generating index transaction code message. In OI you'll see nothing, but it happens anyway. What's going on is that SI.MFS, on an open call, checks to see that the ! record is there. If not, it generates it. After this, if there is a !! record, it writes the source code it generated for the ! record out to the !! record.

I've placed the output of this at the end of this message so the viewers at home can follow along.

As you can see by the calculatex calls, it tries to use the old, cached record to determine what the previous index value to delete was.

If you're doing something like

Read Rec from Handle, Key else do Errorstuff

Rec<x]=NewData

Rec<y]=MoreNewData

Write Rec on Handle, Key else do ErrorStuff

then the record should be cached, it should find the older code and everything should be fine.

If you read in a bunch of indexed records, the cache will be changed, so there's a greater change of having to re-read in a record. With that, there's a small chance the record currently in the file is not the same as the record you read originally.

With this, you can also see how some calcuated symbolics can cause problems. It will only remove the index reference based on the calulation of OREC at the time of the write. If I'm doing an XLATE, then assuming the information in the other file hasn't changed, it should work.

Take social security numbers, something pretty constant.

If we change a customer ID from 243 to 2043, and have a symbolic that XLATES out social security number from another file, it should always give back 123-45-6789 for IS 243 and 987-65-4321 for 2043. In this case, as long as OREC contains 243, the index will be updated.

Now, if 243 did happen to change social security numbers in between the initial write and the subsequent write (from 123-45-6789 to 321-54-9876), when the system calucates the social security number of OREC, it will get the new value, not the old value. The old value will never be removed from the index until it is rebuilt.

If you use this code as a guide, follow through the debugger or debug it by hand, you'll see how it pans out.

[email protected]

Sprezzatura Ltd

www.sprezzatura.com_zz.jpg

* DON Secondary index transaction builder for version 2.1 and above

* Invoked like a dictionary calculate
* Input: @MV = 0 for write, 1 for delete, 2 for clearfile
* @ID = Record key for write and delete
* @RECORD = Record for write
* @ANS = data file file variable
* RETURNS: nothing

COMMON /%%SI%%/MAX.UPDATE.SIZE,INDEXES,INDEXES.FILEVAR,NO.PROTECT,

  ---]OLD.REC,OLD.FLAG,OLD.FV,OLD.ID,DICT.FVS%,BATCH.MODE%,UPDATE.ITEM%

EQU MARKS TO \FCFBFEFF\
EQU VMARKS TO \FDFD\
EQU DELETED.VALUE$ TO \FC\
EQU TRUE$ TO 1
EQU FALSE$ TO 0
EQU READ.RECORD TO 1
EQU WRITE.RECORD TO 3
EQU DELETE.RECORD TO 4
EQU SI.WRITE$ TO 0
EQU SI.DELETE$ TO 1
EQU SI.CLEARFILE$ TO 2

DECLARE SUBROUTINE MSG, BATCH.INDEXING, DELAY
DECLARE FUNCTION CALCULATE, CALCULATEX, RELATER, INDEX.OPEN, ESC.TO.EXIT

* @ANS contains SI.MFS file handle, parse into local variables. 
POS = 6 + @ANS 1, 5  
TEMP = @ANS POS, 5  
POS += 5 
@DICT = @ANS POS, TEMP  ;* used to be an index.open 
DICT.FILEVAR = @DICT 
POS += TEMP 
TEMP = @ANS POS, 5  
POS += 5 
IDX.FV = @ANS POS, TEMP  
POS += TEMP 
TEMP = @ANS POS, 5  
POS += 5 
FILEVAR = @ANS POS, TEMP  

FS = FILEVAR<1,1]
NEXTFS = FS<1,1,1]
FVAR = DELETE(FILEVAR, 1, 1, 0)
STATUS = 0
FNAME =!DON*SYSPROG*13:47:47  23 APR 1993"1,"F*"
IF BATCH.MODE% THEN
 IDX.FV = INDEXES.FILEVAR
END

* CHECK FOR CLEAR-FILE OPERATION

IF @MV EQ SI.CLEARFILE$ THEN
 UPDATE.LIST = ''
 @ID = '%%ALL.IDS%%'
 UPDATE.LIST := "INVOICE_DATE":@FM:@ID:@FM:@FM:@FM
 UPDATE.LIST := "INVOICE_MONYR":@FM:@ID:@FM:@FM:@FM
 UPDATE.LIST := "PAYMENT_DATE":@FM:@ID:@FM:@FM:@FM
 UPDATE.LIST := "PAYMENT_MONYR":@FM:@ID:@FM:@FM:@FM
END ELSE

* Make sure the record is locked and lock it now if not.
* At lease the indexes will stay correct this way even if the
* caller does not lock records on a network
* Skip locking if not on a network
ITEM.LOCKED = FALSE$
IF LEN(@STATION) THEN
* IF INDEX.OPEN('DON*SYSPROG*13:47:47  23 APR 1993',LOCK.FILEVAR) THEN
* LOCK_FV = LOCK.FILEVAR
* LOCK_ID = @ID
* LOCK_MSG = 'B440'
* PARA = @ID:@FM:"DON"
* GOSUB LOCK_ITEM
* IF ABORT THEN
* RETURN FALSE$
* END
* IF LOCKED AND NOT(SELF_LOCKED) THEN
* ITEM.LOCKED = TRUE$
* END
* END
END

* Check for old record cached by read logic

OPTIMIZED = FALSE$ ;* remember if old record cached
IF OLD.FLAG THEN

 * If something cached, then ID and FILEVAR must match

 IF OLD.ID EQ @ID THEN
 IF OLD.FV EQ FILEVAR THEN

 * If something cached, then the record had better have been locked.
 * If not we will force another read later. This will
 * keep the indexes in line with the data file but some user may not
 * find the data he expects if he is sharing the file without locking.

* IF ITEM.LOCKED ELSE
 OPTIMIZED = TRUE$ ;* did not have to lock it
 IF OLD.FLAG EQ 2 THEN
 NO.OREC = TRUE$ ;* Record does not exist
 OREC = ''
 END ELSE
 TRANSFER OLD.REC TO OREC
 NO.OREC = FALSE$
 END
* END
 OLD.FLAG = FALSE$ ;* Empty the cache on a match
 END
 END
END

* If old record wasn't cached then get it now

IF OPTIMIZED ELSE
 CALL @NEXTFS(READ.RECORD, FS, FVAR:'', @ID, '', OREC, FLAG)
 IF FLAG THEN
 NO.OREC = FALSE$
 END ELSE
 IF @FILE.ERROR<1] # 100 THEN
* IF @STATION NE '' AND ITEM.LOCKED THEN 
* ERR.SAVE = @FILE.ERROR
* UNLOCK LOCK.FILEVAR, @ID ELSE NULL
* @FILE.ERROR = ERR.SAVE
* FLAG = FALSE$
* END
 RETURN FLAG ;* Error other than record does not exist
 END
 OREC = ''
 NO.OREC = TRUE$
 END
END
IF NO.OREC THEN
 OLD.1 = DELETED.VALUE$
 OLD.2 = DELETED.VALUE$
 OLD.3 = DELETED.VALUE$
 OLD.4 = DELETED.VALUE$
END ELSE
 OLD.1 = OREC<1]
 CONVERT MARKS TO VMARKS IN OLD.1
 CONVERT @LOWER.CASE TO @UPPER.CASE IN OLD.1
 OLD.2 = CALCULATEX('INVOICE_MONYR',DICT.FILEVAR,@ID,OREC,'')
 CONVERT MARKS TO VMARKS IN OLD.2
 CONVERT @LOWER.CASE TO @UPPER.CASE IN OLD.2
 OLD.3 = OREC<2]
 CONVERT MARKS TO VMARKS IN OLD.3
 CONVERT @LOWER.CASE TO @UPPER.CASE IN OLD.3
 OLD.4 = CALCULATEX('PAYMENT_MONYR',DICT.FILEVAR,@ID,OREC,'')
 CONVERT MARKS TO VMARKS IN OLD.4
 CONVERT @LOWER.CASE TO @UPPER.CASE IN OLD.4
END

* Time to actually do the record write or delete

INDEXES = TRUE$ ;* Set SC.XLATE.RESET
IF @MV EQ SI.DELETE$ THEN
 CALL @NEXTFS(DELETE.RECORD,FS,FVAR,@ID,'','', FLAG)
END ELSE
 CALL @NEXTFS(WRITE.RECORD,FS,FVAR,@ID,'',@RECORD, FLAG)
END
IF FLAG ELSE 
* IF @STATION NE '' AND ITEM.LOCKED THEN 
* ERR.SAVE = @FILE.ERROR
* UNLOCK LOCK.FILEVAR, @ID ELSE NULL
* @FILE.ERROR = ERR.SAVE
* FLAG = FALSE$
* END
 RETURN FLAG
END

* Loop through all files, compute new field values

DON.UPD = ''
DON.CNT = 0
IF @MV EQ SI.DELETE$ THEN
 NEW.1 = DELETED.VALUE$
 NEW.2 = DELETED.VALUE$
 NEW.3 = DELETED.VALUE$
 NEW.4 = DELETED.VALUE$
END ELSE
 NEW.1 = @RECORD<1]
 CONVERT MARKS TO VMARKS IN NEW.1
 CONVERT @LOWER.CASE TO @UPPER.CASE IN NEW.1
 NEW.2 = CALCULATE('INVOICE_MONYR')
 CONVERT MARKS TO VMARKS IN NEW.2
 CONVERT @LOWER.CASE TO @UPPER.CASE IN NEW.2
 NEW.3 = @RECORD<2]
 CONVERT MARKS TO VMARKS IN NEW.3
 CONVERT @LOWER.CASE TO @UPPER.CASE IN NEW.3
 NEW.4 = CALCULATE('PAYMENT_MONYR')
 CONVERT MARKS TO VMARKS IN NEW.4
 CONVERT @LOWER.CASE TO @UPPER.CASE IN NEW.4
END
IF NEW.1 NE OLD.1 THEN
 DON.UPD := 'INVOICE_DATE':@FM:@ID:@FM:OLD.1:@FM:NEW.1:@FM
 DON.CNT += 1
END
IF NEW.2 NE OLD.2 THEN
 DON.UPD := 'INVOICE_MONYR':@FM:@ID:@FM:OLD.2:@FM:NEW.2:@FM
 DON.CNT += 1
END
IF NEW.3 NE OLD.3 THEN
 DON.UPD := 'PAYMENT_DATE':@FM:@ID:@FM:OLD.3:@FM:NEW.3:@FM
 DON.CNT += 1
END
IF NEW.4 NE OLD.4 THEN
 DON.UPD := 'PAYMENT_MONYR':@FM:@ID:@FM:OLD.4:@FM:NEW.4:@FM
 DON.CNT += 1
END
UPDATE.LIST = ''
IF DON.UPD NE '' THEN
 UPDATE.LIST := DON.UPD
END
* End of clearfile else
END
* If updates to perform, check for trans rec and write out transaction
* If record is too big, write to the end of the linked list and clear record 0.
* Need to update record 0 no matter if split is needed or not.
IF UPDATE.LIST THEN
 IF BATCH.MODE% AND (UPDATE.ITEM% NE "") ELSE
 IF LEN(@STATION) THEN
 LOCK_FV = IDX.FV
 LOCK_ID = "0"
 LOCK_MSG = 'B521'
 PARA = 0:@FM:FNAME
 GOSUB LOCK_ITEM
 IF ABORT THEN
* IF @STATION NE '' AND ITEM.LOCKED THEN UNLOCK LOCK.FILEVAR, @ID ELSE NULL
 RETURN FALSE$
 END
 END
*
 READ TRANS.REC FROM IDX.FV, "XTRANS" THEN
 GOSUB PATCH
 IF FLAG ELSE RETURN FALSE$
 END
*
 READ UPDATE.ITEM% FROM IDX.FV, "0" ELSE
 UPDATE.ITEM% = @FM
 END
*
 IF BATCH.MODE% THEN
 BATCH.MODE%<2] = TIME()+5
 END
 END
 UPDATE.ITEM% := UPDATE.LIST
 * Record over 1k bytes, will split and write to the end of list.
 IF LEN(UPDATE.ITEM%) GT MAX.UPDATE.SIZE THEN
 RELINK = TRUE$
 NUM = UPDATE.ITEM%1, @FM
 UPDATE.ITEM%1,COL2() = ""
 NUM += 1
*
 TRANS.REC = "W":@FM:NUM:@FM:NUM + 1:@FM:UPDATE.ITEM%
 CONVERT @FM:@VM:@SVM TO @VM:@SVM:@TM IN TRANS.REC
 TRANS.REC := @FM:"W":@VM:0:@VM:NUM:@VM
 WRITE TRANS.REC TO IDX.FV, "XTRANS" ELSE RETURN FALSE$
*
 WRITE NUM + 1:@FM:UPDATE.ITEM% TO IDX.FV, NUM ELSE RETURN FALSE$
 UPDATE.ITEM% = NUM:@FM
 WRITE.UPDATES = TRUE$
 END ELSE
 RELINK = FALSE$
 IF BATCH.MODE% THEN
 WRITE.UPDATES = (TIME() GT BATCH.MODE%<2])
 END ELSE
 WRITE.UPDATES = TRUE$
 END
 END
 IF WRITE.UPDATES THEN
 WRITE UPDATE.ITEM% TO IDX.FV, "0" ELSE RETURN FALSE$
 IF RELINK THEN
 DELETE IDX.FV, "XTRANS" ELSE RETURN FALSE$
 END
 IF LEN(@STATION) THEN
 UNLOCK IDX.FV,"0" ELSE NULL
 END
 UPDATE.ITEM% = ""
 END
END
* Skip final processing if clearfile
IF @MV EQ SI.CLEARFILE$ ELSE

 * Unlock all the indexes that were "logically" locked before getting the
 * OLD VALUES

 IF @STATION NE '' THEN
* IF ITEM.LOCKED THEN
* UNLOCK LOCK.FILEVAR,@ID ELSE NULL
* END
 END
END
RETURN TRUE$

*-----------------
LOCK_ITEM:
 LOCKED = FALSE$
 SELF_LOCKED = FALSE$
 ABORT = FALSE$
 LOCKCNT = 1
 LOCK_IMAGE = ""
 LOOP
 IF LOCKCNT = 200 THEN
 MSG(LOCK_MSG, 'UB', LOCK_IMAGE, PARA)
 END
 LOCK LOCK_FV, LOCK_ID THEN
 LOCKED = TRUE$
 END ELSE
 IF STATUS() EQ 1 THEN
 LOCKED = TRUE$ ;* OKAY if already locked by our station
 SELF_LOCKED = TRUE$
 END ELSE
 DELAY(0.5) ;* Delay 1/2 sec to reduce network traffic 
 END
 END
 UNTIL LOCKED
 BATCH.INDEXING(0,'')
 LOCKCNT += 1
 IF ESC.TO.EXIT() THEN
 RESP = 1
 MSG('B296','', RESP, '')
 IF RESP THEN
 ABORT = TRUE$
 @FILE.ERROR = 421 ;* FS_SYS_USER_ABORT$
 STATUS() = 1 ;* FSPHYSICAL$
 END
 END
 UNTIL ABORT
 REPEAT
 IF LEN(LOCK_IMAGE) THEN
 MSG('','DB',LOCK_IMAGE,'')
 END
 RETURN

*-----------------
PATCH:
 PIX = 1
 FLAG = TRUE$
 LOOP
 WHILE LEN(TRANS.REC<PIX])
 PREC = TRANS.REC<PIX]
 CONVERT @VM:@SVM:@TM TO @FM:@VM:@SVM IN PREC
 PTYPE = PREC1, @FM
 PREC1, COL2() = ""
 PKEY = PREC1, @FM
 PREC1, COL2() = ""
 IF PTYPE = "W" THEN
 WRITE PREC TO IDX.FV, PKEY ELSE FLAG = FALSE$
 END ELSE
 DELETE IDX.FV, PKEY ELSE FLAG = FALSE$
 END
 PIX += 1
 WHILE FLAG
 REPEAT
 IF FLAG THEN
 DELETE IDX.FV, "XTRANS" ELSE NULL
 END
 RETURN

*----------------
OPTIMIZE_RELATIONAL:
 ID.LEN = LEN(OLDX)
 ID.COL = 1
 OLD.ID.LIST = ""
 LOOP WHILE ID.COL LE ID.LEN
 NEXT.ID = OLDXID.COL, @VM
 ID.COL = COL2() + 1
 LOCATE NEXT.ID IN NEWX USING @VM SETTING NUM ELSE
 OLD.ID.LIST<1,-1] = NEXT.ID
 END
 REPEAT
*
 ID.LEN = LEN(NEWX)
 ID.COL = 1
 NEW.ID.LIST = ""
 LOOP WHILE ID.COL LE ID.LEN
 NEXT.ID = NEWXID.COL, @VM
 ID.COL = COL2() + 1
 LOCATE NEXT.ID IN OLDX USING @VM SETTING NUM ELSE
 NEW.ID.LIST<1,-1] = NEXT.ID
 END
 REPEAT
*
 TRANSFER NEW.ID.LIST TO NEWX
 TRANSFER OLD.ID.LIST TO OLDX
 RETURN

At 03 JAN 1998 11:09AM Andrew P McAuley wrote:

Yup it was from FKB - see the citation at the end of the article!

Toodles

[email protected]

Sprezzatura Ltd

World Leaders in all things RevSoft


At 03 JAN 1998 04:06PM Cameron Revelation wrote:

Aaron,

SI.MFS executes this with a calculate or calculatex (probably the latter)

Correct (as usual, King Friday). Calculatex is just a shell around calculate that makes sure that some globals don't get trashed. The SI.MFS code sets up @ans to the file handle you see parsed in the !! code then calls calculatex against the ! "dictionary item".

Cameron Purdy

Revelation Software


At 03 JAN 1998 04:10PM Cameron Revelation wrote:

Don,

If so, then are the dependencies stored outside of the window, like in the dictionary?

The dictionary field dependencies are constructed on the fly by parsing the symbolic code or other dictionary information.

There are dependencies generated at the form level, but they are for form i/o (e.g. is the key filled in?) and display updates (e.g. symbolic needs redisplay) only, not for indexing.

Cameron Purdy

Revelation Software

View this thread on the forum...

  • third_party_content/community/commentary/forums_nonworks/004a6a09c583e7ce8525657e001a56f7.txt
  • Last modified: 2024/01/04 21:00
  • by 127.0.0.1