Example #1
0
/*
** This function is called when deleting or updating a row to implement
** any required CASCADE, SET NULL or SET DEFAULT actions.
*/
void sqlite3FkActions(
  Parse *pParse,                  /* Parse context */
  Table *pTab,                    /* Table being updated or deleted from */
  ExprList *pChanges,             /* Change-list for UPDATE, NULL for DELETE */
  int regOld                      /* Address of array containing old row */
){
  /* If foreign-key support is enabled, iterate through all FKs that 
  ** refer to table pTab. If there is an action associated with the FK 
  ** for this operation (either update or delete), invoke the associated 
  ** trigger sub-program.  */
  if( pParse->db->flags&SQLITE_ForeignKeys ){
    FKey *pFKey;                  /* Iterator variable */
    for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
      Trigger *pAction = fkActionTrigger(pParse, pTab, pFKey, pChanges);
      if( pAction ){
        sqlite3CodeRowTriggerDirect(pParse, pAction, pTab, regOld, OE_Abort, 0);
      }
    }
  }
}
/*
 ** This is called to code the required FOR EACH ROW triggers for an operation
 ** on table pTab. The operation to code triggers for (INSERT, UPDATE or DELETE)
 ** is given by the op parameter. The tr_tm parameter determines whether the
 ** BEFORE or AFTER triggers are coded. If the operation is an UPDATE, then
 ** parameter pChanges is passed the list of columns being modified.
 **
 ** If there are no triggers that fire at the specified time for the specified
 ** operation on pTab, this function is a no-op.
 **
 ** The reg argument is the address of the first in an array of registers
 ** that contain the values substituted for the new.* and old.* references
 ** in the trigger program. If N is the number of columns in table pTab
 ** (a copy of pTab->nCol), then registers are populated as follows:
 **
 **   Register       Contains
 **   ------------------------------------------------------
 **   reg+0          OLD.rowid
 **   reg+1          OLD.* value of left-most column of pTab
 **   ...            ...
 **   reg+N          OLD.* value of right-most column of pTab
 **   reg+N+1        NEW.rowid
 **   reg+N+2        OLD.* value of left-most column of pTab
 **   ...            ...
 **   reg+N+N+1      NEW.* value of right-most column of pTab
 **
 ** For ON DELETE triggers, the registers containing the NEW.* values will
 ** never be accessed by the trigger program, so they are not allocated or 
 ** populated by the caller (there is no data to populate them with anyway). 
 ** Similarly, for ON INSERT triggers the values stored in the OLD.* registers
 ** are never accessed, and so are not allocated by the caller. So, for an
 ** ON INSERT trigger, the value passed to this function as parameter reg
 ** is not a readable register, although registers (reg+N) through 
 ** (reg+N+N+1) are.
 **
 ** Parameter orconf is the default conflict resolution algorithm for the
 ** trigger program to use (REPLACE, IGNORE etc.). Parameter ignoreJump
 ** is the instruction that control should jump to if a trigger program
 ** raises an IGNORE exception.
 */
SQLITE_PRIVATE void sqlite3CodeRowTrigger(
                                          Parse *pParse,       /* Parse context */
                                          Trigger *pTrigger,   /* List of triggers on table pTab */
                                          int op,              /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
                                          ExprList *pChanges,  /* Changes list for any UPDATE OF triggers */
                                          int tr_tm,           /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
                                          Table *pTab,         /* The table to code triggers from */
                                          int reg,             /* The first in an array of registers (see above) */
                                          int orconf,          /* ON CONFLICT policy */
                                          int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */
){
    Trigger *p;          /* Used to iterate through pTrigger list */
    
    assert( op==TK_UPDATE || op==TK_INSERT || op==TK_DELETE );
    assert( tr_tm==TRIGGER_BEFORE || tr_tm==TRIGGER_AFTER );
    assert( (op==TK_UPDATE)==(pChanges!=0) );
    
    for(p=pTrigger; p; p=p->pNext){
        
        /* Sanity checking:  The schema for the trigger and for the table are
         ** always defined.  The trigger must be in the same schema as the table
         ** or else it must be a TEMP trigger. */
        assert( p->pSchema!=0 );
        assert( p->pTabSchema!=0 );
        assert( p->pSchema==p->pTabSchema 
               || p->pSchema==pParse->db->aDb[1].pSchema );
        
        /* Determine whether we should code this trigger */
        if( p->op==op 
           && p->tr_tm==tr_tm 
           && checkColumnOverlap(p->pColumns, pChanges)
           ){
            sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump);
        }
    }
}