Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
SEEK(),INDEXSEEK() or KeyMatch() or SELECT-SQL?
Message
 
 
To
12/04/2005 13:26:29
General information
Forum:
Visual FoxPro
Category:
Databases,Tables, Views, Indexing and SQL syntax
Environment versions
Visual FoxPro:
VFP 8 SP1
OS:
Windows XP SP2
Miscellaneous
Thread ID:
01002645
Message ID:
01003897
Views:
29
Bellow is the code I generated for a test database. You're right, that it has to be more robust. E.g. if triggerlevel <>1 I need to check, if it is the same parent initiated it.
But in this code I do not understand, why it is telling about Insert trigger violated while it is an Update trigger?
********************************************************************************
procedure __RI_UPDATE_calls
** "Referential integrity update trigger for" calls
LOCAL llRetVal
llRetVal = .t.
PRIVATE pcParentDBF,pnParentRec,pcChildDBF,pnChildRec,pcParentID,pcChildID
PRIVATE pcParentExpr,pcChildExpr
STORE "" TO pcParentDBF,pcChildDBF,pcParentID,pcChildID,pcParentExpr,pcChildExpr
STORE 0 TO pnParentRec,pnChildRec
IF _triggerlevel=1
  BEGIN TRANSACTION
  PRIVATE pcRIcursors,pcRIwkareas,pcRIolderror,pnerror,;
  pcOldDele,pcOldExact,pcOldTalk,pcOldCompat,PcOldDBC
  pcOldTalk=SET("TALK")
  SET TALK OFF
  pcOldDele=SET("DELETED")
  pcOldExact=SET("EXACT")
  pcOldCompat=SET("COMPATIBLE")
  SET COMPATIBLE OFF
  SET DELETED ON
  SET EXACT OFF
  pcRIcursors=""
  pcRIwkareas=""
  pcRIolderror=ON("error")
  pnerror=0
  ON ERROR pnerror=rierror(ERROR(),message(),message(1),program())
  IF TYPE('gaErrors(1)')<>"U"
    release gaErrors
  ENDIF
  PUBLIC gaErrors(1,12)
  pcOldDBC=DBC()
  SET DATA TO ("CONTACTS")
ENDIF first trigger
LOCAL lcParentID && parent's value to be sought in child
LOCAL lcOldParentID && previous parent id value
LOCAL lcChildWkArea && child work area handle returned by riopen
LOCAL lcChildID && child's value to be sought in parent
LOCAL lcOldChildID && old child id value
LOCAL lcParentWkArea && parentwork area handle returned by riopen
LOCAL lcStartArea
lcStartArea=select()
llRetVal=.t.
lcChildWkArea=select()
IF _triggerlevel=1 or type("pccascadeparent")#"C" or (NOT pccascadeparent=="CONTACTS")
  SELECT (lcChildWkArea)
  lcChildID=CONTACT_ID
  lcOldChildID=oldval("CONTACT_ID")
  pcChildDBF=dbf(lcChildWkArea)
  pnChildRec=recno(lcChildWkArea)
  pcChildID=lcOldChildID
  pcChildExpr="CONTACT_ID"
  IF lcChildID<>lcOldChildID
    lcParentWkArea=riopen("contacts","contact_id")
    IF lcParentWkArea<=0
      IF _triggerlevel=1
        DO riend WITH .F.
      ENDIF at the end of the highest trigger level
      SELECT (lcStartArea)
      RETURN .F.
    ENDIF not able to open the child work area
    pcParentDBF=dbf(lcParentWkArea)
    llRetVal=SEEK(lcChildID,lcParentWkArea)
    pnParentRec=recno(lcParentWkArea)
    =rireuse("contacts",lcParentWkArea)
    IF NOT llRetVal
      pnError = rierror(-1,"Insert restrict rule violated.","","")
      IF _triggerlevel=1
        DO riend WITH llRetVal
      ENDIF at the end of the highest trigger level
      SELECT (lcStartArea)
      RETURN llRetVal
    ENDIF no parent
  ENDIF this value was changed
ENDIF not part of a cascade from "contacts"
lcParentWkArea=lcChildWkArea
IF _triggerlevel=1
  do riend with llRetVal
ENDIF at the end of the highest trigger level
SELECT (lcStartArea)
RETURN llRetVal
** "End of Referential integrity Update trigger for" calls
>>>>It is actually becoming more and more interesting. I made bunch of other changes to fix bugs in cascading deletes/updates. Now I hope it works correctly...
>>>
>>>Hope for you too ;-)
>>>
>>>You'll have to test all scenario's though to be sure.
>>
>>I tested a couple, but I'm now trying to understand, how it should work.
>>
>>If we have a cascaded update, what should be our logic for our table as a child? So far I put a condition, that we check for our table as a child only in it is a first level of trigger execution, e.g. if our trigger was called as a result of cascading update on a parent, I do not run the second SCAN. However, I'm not 100% certain I'm correct.
>>
>>Can somebody with the good understanding of how triggers should behave explain to me all possible scenarios?
>>
>>Thanks in advance.
>
>The trigger level is imo irrelevant here
>
>if there is a cascaded update, the child update fires
>
>The child would normally check if there's a parent with that key.
>
>Doing this will give an illegal recursion. It's also not necessary to test this, if we trust the code of the parent
>
>There's a simple test: do not check any relations with the table one level above, in case of a cascade
>
>Suppose you keep an array, say CascadeInitiator[]
>Each time a trigger fires
>
>dime __t__CascadeInitiator[_triggerlevel]
>__t__CascadeInitiator[_triggerlevel] = ''
>
>
>if you are doing a cascaded update
>
>__t__CascadeInitiator[_TriggerLevel] = m.thistable
>replace .....
>
>
>All relations with __t__CascadeInitiator[_TriggerLevel - 1] should not be tested (error 1887)
>
>think that's about it
>
>To be sure. Use standard RI, set up a cascade delete and a cascade update. Generate the code and look at it
If it's not broken, fix it until it is.


My Blog
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform