Indexes on Synbolics (OpenInsight Specific)
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,
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.
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 FSMSGOPEN "!INDEXING" TO IFILE THENGOSUB GET_VOL_INFOGOSUB UPDATE_INDEX_FILEEND ELSEFSMSG()ENDRETURNGET_VOL_INFO:FILE_REC=XLATE("FILES",FILE,"","X")VOL_REC =XLATE("VOLUMES",FILE_REC,"","X")VOL_INFO=FILE_REC:"*":FILE_REC:"*":VOL_RECRETURNUPDATE_INDEX_FILE:UPDATE_REC =VOL_INFO ; * Volume InformationUPDATE_REC=1 ; * Number of transactionsUPDATE_REC=FIELD ; * Index to updateUPDATE_REC=%%ALL.IDS%%" ; * Rebuild FlagUPDATE_REC := @FM : @FM : @FMREAD ZERO_REC FROM IFILE, "0" ELSE ZERO_REC=@FM
Ensure there is a trailing field markIF INDEX(ZERO_REC,@FM,1) ELSE ZERO_REC := @FMZERO_REC := UPDATE_RECWRITE ZERO_REC TO IFILE, "0"CALL INDEX.FLUSH(VOL_INFO,'')RETURN(Volume 2, Issue 8, Page 7)
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 LEDGERSMITH J 200 PERSONNELJONES A 300 STAFF ACCOUNTINGand the STAFF ACCOUNTING department was changed to PAYROLL the employee list
would now display in an incorrectly sorted order.
BROWN A 100 BOUGHT LEDGERSMITH J 200 PERSONNELJONES A 300 PAYROLLWhat 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 recordSystem must know of existence of indexes on external recordsSystem must detect change and reevaluate external symbolicsAn 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 buildthe indexAs a relational index is to be set up between the Employee fileand the Departments file, add a multivalued field definition (EGEMP.KEYS) to the Department file to store the relationally indexedkeys from the Employee file.Define a relational index from the Department Number in theEmployees files to the EMP.KEYS field in the Department file.(This is most easily accomplished from Shift-F1 in the DICT windowrather than the indexing menu).At TCL, edit the symbolic which XLATES the description (in thiscase the Department Name Symbolic in the Employees file). Ensurethat no extra lines are inserted or deleted by turning Ins Lineoff. Move the cursor to line 21 (the "depends on" field) anddefine this item as related to the department file by insertinginformation in the format FILE*FIELD, in this caseDEPARTMENTS*EMP.KEYS. Save this symbolic. (Try a LISTINDEX onEmployees 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)
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,
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,
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.
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,
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 ErrorStuffthen 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.
* 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: nothingCOMMON /%%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 1EQU FALSE$ TO 0EQU READ.RECORD TO 1EQU WRITE.RECORD TO 3EQU DELETE.RECORD TO 4EQU SI.WRITE$ TO 0EQU SI.DELETE$ TO 1EQU SI.CLEARFILE$ TO 2DECLARE SUBROUTINE MSG, BATCH.INDEXING, DELAYDECLARE 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 = 0FNAME =!DON*SYSPROG*13:47:47 23 APR 1993"1,"F*"IF BATCH.MODE% THEN IDX.FV = INDEXES.FILEVAREND* CHECK FOR CLEAR-FILE OPERATIONIF @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:@FMEND 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 networkITEM.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* ENDEND* Check for old record cached by read logicOPTIMIZED = FALSE$ ;* remember if old record cachedIF 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 ENDEND* If old record wasn't cached then get it nowIF 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$ ENDENDIF 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.4END* Time to actually do the record write or deleteINDEXES = TRUE$ ;* Set SC.XLATE.RESETIF @MV EQ SI.DELETE$ THEN CALL @NEXTFS(DELETE.RECORD,FS,FVAR,@ID,'','', FLAG)END ELSE CALL @NEXTFS(WRITE.RECORD,FS,FVAR,@ID,'',@RECORD, FLAG)ENDIF 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 FLAGEND* Loop through all files, compute new field valuesDON.UPD = ''DON.CNT = 0IF @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.4ENDIF NEW.1 NE OLD.1 THEN DON.UPD := 'INVOICE_DATE':@FM:@ID:@FM:OLD.1:@FM:NEW.1:@FM DON.CNT += 1ENDIF NEW.2 NE OLD.2 THEN DON.UPD := 'INVOICE_MONYR':@FM:@ID:@FM:OLD.2:@FM:NEW.2:@FM DON.CNT += 1ENDIF NEW.3 NE OLD.3 THEN DON.UPD := 'PAYMENT_DATE':@FM:@ID:@FM:OLD.3:@FM:NEW.3:@FM DON.CNT += 1ENDIF NEW.4 NE OLD.4 THEN DON.UPD := 'PAYMENT_MONYR':@FM:@ID:@FM:OLD.4:@FM:NEW.4:@FM DON.CNT += 1ENDUPDATE.LIST = ''IF DON.UPD NE '' THEN UPDATE.LIST := DON.UPDEND* End of clearfile elseEND* 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% = "" ENDEND* Skip final processing if clearfileIF @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 ENDENDRETURN 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
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