>Hilmar,
>
>thanks a lot for your answer, somtimes it really helps to go one step back,
>or write a question on UT to get around not seeing easy things.
>
>>Why do you need to mess with the RI? Usually, you can just add functions like this:
>>If your RI-code is: __ri_MyTable_Update()
>>You convert it to: __ri_MyTable_Update() AND MyAdditionalFunction()
>We already tried your solution quite a while ago and ran into the following problem: This works fine as long as the trigger is called directly. Lets say you habe 3 tables: Table1, Table2, Table3 wich have RI for cascading delete.
>
>The __ri_MyTable_Update() of Table3 works fine when I delete a record in Table2. I get into my code and have the record wich is planed to delete as actual record.
>
>If I delete the according record in Table1 my Table3-Code fires, but the record pointer of table3 stands anywhere? So I can't find out wich record is planed to be deleted, so I can't perform my action!
>
>Is this a known issue. I am really confused, because I never ran in any problems like this ? Perhaps our RI Code is not OK ? Any ideas ?
>Marcus
Marcus,
Not sure what you mean.
When the trigger of table3 fires, you
are on the record of table3 that is being deleted. It does not matter which table (1 or 2) initiated it.
Actually, deleting a record in table1 will start deleting records in table2. Then Table2 RI is fired, which deletes a record in table3. So it is always table2 that initiates the trigger
Also, the trigger fires for each record of table3 that is being deleted. When the code of table3 is fired, you are on the record that is about to be deleted.
By the way, have you written your own RI code to cascade the deletes ?
In that case, table buffering may confuse you.
If you have table buffering (say mode 4 or 5) active when you open eg table2 inside the ri, then delete a bunch in table2, the delete triggers of table2 won't fire until you close table2.
For each record you delete, best is to (1) lock it, (2) delete it, (3) TableUpdate if buffering, (4) unlock the record
As an example, a code excerpt below for the cascade. Look at the code in the scan. It illustrates the 4 steps above
Hope it helps
case (_rule == 'C' )
local ParentValue, ChildIndexExpr, OldSelect
ParentValue = oldval(obj.thisIndexExpr)
ChildIndexExpr = obj.OtherIndexExpr
if( seek(ParentValue, s) and NO_ERROR )
OldSelect = select(0)
select (s)
scan rest while NO_ERROR and ( eval(ChildIndexExpr) == ParentValue)
if( !_TriggerLockRecord() )
__t__error = -1
exit
else
if( !deleted() )
delete
Success = Success and _TriggerTableUpdate()
endif
=_TriggerUnLockRecord()
endif
endscan
select (OldSelect)
endif
function _TriggerTableUpdate()
do case
case (CursorGetProp('Buffering') > 1)
do case
case !TableUpdate()
=TableRevert()
return FALSE
endcase
endcase
endfunc
function _TriggerLockRecord()
local Success
Success = TRUE
do case
case (IsRLocked() and !Deleted())
Success = FALSE
case !RLock()
Success = FALSE
endcase
do case
case !Success
local msg, _table
_table = CursorGetProp('SourceName')
msg = 'Cannot lock record in ' + _table
=_TriggerError(-1, 'Cannot lock record', '', '', msg, ;
_Table, '', '', '' )
endcase
return Success
endfunc
function _TriggerUnLockRecord()
unlock record (recno())
endfunc
Gregory