Beispiel #1
0
/*
** Duplicate an Upsert object.
*/
Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
  if( p==0 ) return 0;
  return sqlite3UpsertNew(db,
           sqlite3ExprListDup(db, p->pUpsertTarget, 0),
           sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
           sqlite3ExprListDup(db, p->pUpsertSet, 0),
           sqlite3ExprDup(db, p->pUpsertWhere, 0)
         );
}
Beispiel #2
0
/*
** Make a copy of all components of the given trigger step.  This has
** the effect of copying all Expr.token.z values into memory obtained
** from sqliteMalloc().  As initially created, the Expr.token.z values
** all point to the input string that was fed to the parser.  But that
** string is ephemeral - it will go away as soon as the sqlite3_exec()
** call that started the parser exits.  This routine makes a persistent
** copy of all the Expr.token.z strings so that the TriggerStep structure
** will be valid even after the sqlite3_exec() call returns.
*/
static void sqlitePersistTriggerStep(TriggerStep *p){
  if( p->target.z ){
    p->target.z = sqliteStrNDup(p->target.z, p->target.n);
    p->target.dyn = 1;
  }
  if( p->pSelect ){
    Select *pNew = sqlite3SelectDup(p->pSelect);
    sqlite3SelectDelete(p->pSelect);
    p->pSelect = pNew;
  }
  if( p->pWhere ){
    Expr *pNew = sqlite3ExprDup(p->pWhere);
    sqlite3ExprDelete(p->pWhere);
    p->pWhere = pNew;
  }
  if( p->pExprList ){
    ExprList *pNew = sqlite3ExprListDup(p->pExprList);
    sqlite3ExprListDelete(p->pExprList);
    p->pExprList = pNew;
  }
  if( p->pIdList ){
    IdList *pNew = sqlite3IdListDup(p->pIdList);
    sqlite3IdListDelete(p->pIdList);
    p->pIdList = pNew;
  }
}
/*
 ** Build a trigger step out of an INSERT statement.  Return a pointer
 ** to the new trigger step.
 **
 ** The parser calls this routine when it sees an INSERT inside the
 ** body of a trigger.
 */
SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
                                                     sqlite3 *db,        /* The database connection */
                                                     Token *pTableName,  /* Name of the table into which we insert */
                                                     IdList *pColumn,    /* List of columns in pTableName to insert into */
                                                     ExprList *pEList,   /* The VALUE clause: a list of values to be inserted */
                                                     Select *pSelect,    /* A SELECT statement that supplies values */
                                                     u8 orconf           /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
){
    TriggerStep *pTriggerStep;
    
    assert(pEList == 0 || pSelect == 0);
    assert(pEList != 0 || pSelect != 0 || db->mallocFailed);
    
    pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
    if( pTriggerStep ){
        pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
        pTriggerStep->pIdList = pColumn;
        pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
        pTriggerStep->orconf = orconf;
    }else{
        sqlite3IdListDelete(db, pColumn);
    }
    sqlite3ExprListDelete(db, pEList);
    sqlite3SelectDelete(db, pSelect);
    
    return pTriggerStep;
}
Beispiel #4
0
/*
** Construct a trigger step that implements an UPDATE statement and return
** a pointer to that trigger step.  The parser calls this routine when it
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerUpdateStep(
  Parse *pParse,          /* Parser */
  Token *pTableName,   /* Name of the table to be updated */
  ExprList *pEList,    /* The SET clause: list of column and new values */
  Expr *pWhere,        /* The WHERE clause */
  u8 orconf,           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
  const char *zStart,  /* Start of SQL text */
  const char *zEnd     /* End of SQL text */
){
  sqlite3 *db = pParse->db;
  TriggerStep *pTriggerStep;

  pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd);
  if( pTriggerStep ){
    if( IN_RENAME_OBJECT ){
      pTriggerStep->pExprList = pEList;
      pTriggerStep->pWhere = pWhere;
      pEList = 0;
      pWhere = 0;
    }else{
      pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
      pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
    }
    pTriggerStep->orconf = orconf;
  }
  sqlite3ExprListDelete(db, pEList);
  sqlite3ExprDelete(db, pWhere);
  return pTriggerStep;
}
/*
** Make a copy of all components of the given trigger step.  This has
** the effect of copying all Expr.token.z values into memory obtained
** from sqlite3_malloc().  As initially created, the Expr.token.z values
** all point to the input string that was fed to the parser.  But that
** string is ephemeral - it will go away as soon as the sqlite3_exec()
** call that started the parser exits.  This routine makes a persistent
** copy of all the Expr.token.z strings so that the TriggerStep structure
** will be valid even after the sqlite3_exec() call returns.
*/
static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
  if( p->target.z ){
    p->target.z = (u8*)sqlite3DbStrNDup(db, (char*)p->target.z, p->target.n);
    p->target.dyn = 1;
  }
  if( p->pSelect ){
    Select *pNew = sqlite3SelectDup(db, p->pSelect);
    sqlite3SelectDelete(db, p->pSelect);
    p->pSelect = pNew;
  }
  if( p->pWhere ){
    Expr *pNew = sqlite3ExprDup(db, p->pWhere);
    sqlite3ExprDelete(db, p->pWhere);
    p->pWhere = pNew;
  }
  if( p->pExprList ){
    ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
    sqlite3ExprListDelete(db, p->pExprList);
    p->pExprList = pNew;
  }
  if( p->pIdList ){
    IdList *pNew = sqlite3IdListDup(db, p->pIdList);
    sqlite3IdListDelete(db, p->pIdList);
    p->pIdList = pNew;
  }
}
/*
 ** Construct a trigger step that implements an UPDATE statement and return
 ** a pointer to that trigger step.  The parser calls this routine when it
 ** sees an UPDATE statement inside the body of a CREATE TRIGGER.
 */
SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
                                                     sqlite3 *db,         /* The database connection */
                                                     Token *pTableName,   /* Name of the table to be updated */
                                                     ExprList *pEList,    /* The SET clause: list of column and new values */
                                                     Expr *pWhere,        /* The WHERE clause */
                                                     u8 orconf            /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
){
    TriggerStep *pTriggerStep;
    
    pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
    if( pTriggerStep ){
        pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
        pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
        pTriggerStep->orconf = orconf;
    }
    sqlite3ExprListDelete(db, pEList);
    sqlite3ExprDelete(db, pWhere);
    return pTriggerStep;
}
Beispiel #7
0
/*
** Generate VDBE code for zero or more statements inside the body of a
** trigger.  
*/
static int codeTriggerProgram(
  Parse *pParse,            /* The parser context */
  TriggerStep *pStepList,   /* List of statements inside the trigger body */
  int orconfin              /* Conflict algorithm. (OE_Abort, etc) */  
){
  TriggerStep * pTriggerStep = pStepList;
  int orconf;

  while( pTriggerStep ){
    int saveNTab = pParse->nTab;
 
    orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
    pParse->trigStack->orconf = orconf;
    switch( pTriggerStep->op ){
      case TK_SELECT: {
	Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);		  
	assert(ss);
	assert(ss->pSrc);
	sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
	sqlite3SelectDelete(ss);
	break;
      }
      case TK_UPDATE: {
        SrcList *pSrc;
        pSrc = targetSrcList(pParse, pTriggerStep);
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
        sqlite3Update(pParse, pSrc,
		sqlite3ExprListDup(pTriggerStep->pExprList), 
		sqlite3ExprDup(pTriggerStep->pWhere), orconf);
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
        break;
      }
      case TK_INSERT: {
        SrcList *pSrc;
        pSrc = targetSrcList(pParse, pTriggerStep);
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
        sqlite3Insert(pParse, pSrc,
          sqlite3ExprListDup(pTriggerStep->pExprList), 
          sqlite3SelectDup(pTriggerStep->pSelect), 
          sqlite3IdListDup(pTriggerStep->pIdList), orconf);
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
        break;
      }
      case TK_DELETE: {
        SrcList *pSrc;
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
        pSrc = targetSrcList(pParse, pTriggerStep);
        sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere));
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
        sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
        break;
      }
      default:
        assert(0);
    } 
    pParse->nTab = saveNTab;
    pTriggerStep = pTriggerStep->pNext;
  }

  return 0;
}
Beispiel #8
0
/*
** Generate an expression tree to implement the WHERE, ORDER BY,
** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
**
**     DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
**                            \__________________________/
**                               pLimitWhere (pInClause)
*/
Expr *sqlite3LimitWhere(
  Parse *pParse,               /* The parser context */
  SrcList *pSrc,               /* the FROM clause -- which tables to scan */
  Expr *pWhere,                /* The WHERE clause.  May be null */
  ExprList *pOrderBy,          /* The ORDER BY clause.  May be null */
  Expr *pLimit,                /* The LIMIT clause.  May be null */
  char *zStmtType              /* Either DELETE or UPDATE.  For err msgs. */
){
  sqlite3 *db = pParse->db;
  Expr *pLhs = NULL;           /* LHS of IN(SELECT...) operator */
  Expr *pInClause = NULL;      /* WHERE rowid IN ( select ) */
  ExprList *pEList = NULL;     /* Expression list contaning only pSelectRowid */
  SrcList *pSelectSrc = NULL;  /* SELECT rowid FROM x ... (dup of pSrc) */
  Select *pSelect = NULL;      /* Complete SELECT tree */
  Table *pTab;

  /* Check that there isn't an ORDER BY without a LIMIT clause.
  */
  if( pOrderBy && pLimit==0 ) {
    sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
    sqlite3ExprDelete(pParse->db, pWhere);
    sqlite3ExprListDelete(pParse->db, pOrderBy);
    return 0;
  }

  /* We only need to generate a select expression if there
  ** is a limit/offset term to enforce.
  */
  if( pLimit == 0 ) {
    return pWhere;
  }

  /* Generate a select expression tree to enforce the limit/offset 
  ** term for the DELETE or UPDATE statement.  For example:
  **   DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
  ** becomes:
  **   DELETE FROM table_a WHERE rowid IN ( 
  **     SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
  **   );
  */

  pTab = pSrc->a[0].pTab;
  if( HasRowid(pTab) ){
    pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
    pEList = sqlite3ExprListAppend(
        pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
    );
  }else{
    Index *pPk = sqlite3PrimaryKeyIndex(pTab);
    if( pPk->nKeyCol==1 ){
      const char *zName = pTab->aCol[pPk->aiColumn[0]].zName;
      pLhs = sqlite3Expr(db, TK_ID, zName);
      pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
    }else{
      int i;
      for(i=0; i<pPk->nKeyCol; i++){
        Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName);
        pEList = sqlite3ExprListAppend(pParse, pEList, p);
      }
      pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
      if( pLhs ){
        pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0);
      }
    }
  }

  /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
  ** and the SELECT subtree. */
  pSrc->a[0].pTab = 0;
  pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
  pSrc->a[0].pTab = pTab;
  pSrc->a[0].pIBIndex = 0;

  /* generate the SELECT expression tree. */
  pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0, 
      pOrderBy,0,pLimit
  );

  /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
  pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0);
  sqlite3PExprAddSelect(pParse, pInClause, pSelect);
  return pInClause;
}
/*
 ** Generate VDBE code for the statements inside the body of a single
 ** trigger.
 */
static int codeTriggerProgram(
                              Parse *pParse,            /* The parser context */
                              TriggerStep *pStepList,   /* List of statements inside the trigger body */
                              int orconf                /* Conflict algorithm. (OE_Abort, etc) */
){
    TriggerStep *pStep;
    Vdbe *v = pParse->pVdbe;
    sqlite3 *db = pParse->db;
    
    assert( pParse->pTriggerTab && pParse->pToplevel );
    assert( pStepList );
    assert( v!=0 );
    for(pStep=pStepList; pStep; pStep=pStep->pNext){
        /* Figure out the ON CONFLICT policy that will be used for this step
         ** of the trigger program. If the statement that caused this trigger
         ** to fire had an explicit ON CONFLICT, then use it. Otherwise, use
         ** the ON CONFLICT policy that was specified as part of the trigger
         ** step statement. Example:
         **
         **   CREATE TRIGGER AFTER INSERT ON t1 BEGIN;
         **     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
         **   END;
         **
         **   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
         **   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
         */
        pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
        
        /* Clear the cookieGoto flag. When coding triggers, the cookieGoto
         ** variable is used as a flag to indicate to sqlite3ExprCodeConstants()
         ** that it is not safe to refactor constants (this happens after the
         ** start of the first loop in the SQL statement is coded - at that
         ** point code may be conditionally executed, so it is no longer safe to
         ** initialize constant register values).  */
        assert( pParse->cookieGoto==0 || pParse->cookieGoto==-1 );
        pParse->cookieGoto = 0;
        
        switch( pStep->op ){
            case TK_UPDATE: {
                sqlite3Update(pParse,
                              targetSrcList(pParse, pStep),
                              sqlite3ExprListDup(db, pStep->pExprList, 0),
                              sqlite3ExprDup(db, pStep->pWhere, 0),
                              pParse->eOrconf
                              );
                break;
            }
            case TK_INSERT: {
                sqlite3Insert(pParse,
                              targetSrcList(pParse, pStep),
                              sqlite3ExprListDup(db, pStep->pExprList, 0),
                              sqlite3SelectDup(db, pStep->pSelect, 0),
                              sqlite3IdListDup(db, pStep->pIdList),
                              pParse->eOrconf
                              );
                break;
            }
            case TK_DELETE: {
                sqlite3DeleteFrom(pParse,
                                  targetSrcList(pParse, pStep),
                                  sqlite3ExprDup(db, pStep->pWhere, 0)
                                  );
                break;
            }
            default: assert( pStep->op==TK_SELECT ); {
                SelectDest sDest;
                Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0);
                sqlite3SelectDestInit(&sDest, SRT_Discard, 0);
                sqlite3Select(pParse, pSelect, &sDest);
                sqlite3SelectDelete(db, pSelect);
                break;
            }
        }
        if( pStep->op!=TK_SELECT ){
            sqlite3VdbeAddOp0(v, OP_ResetCount);
        }
    }
    
    return 0;
}
Beispiel #10
0
/*
** Generate VDBE code for zero or more statements inside the body of a
** trigger.  
*/
static int codeTriggerProgram(
  Parse *pParse,            /* The parser context */
  TriggerStep *pStepList,   /* List of statements inside the trigger body */
  int orconfin              /* Conflict algorithm. (OE_Abort, etc) */  
){
  TriggerStep * pTriggerStep = pStepList;
  int orconf;
  Vdbe *v = pParse->pVdbe;
  sqlite3 *db = pParse->db;

  assert( pTriggerStep!=0 );
  assert( v!=0 );
  sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0);
  VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name));
  while( pTriggerStep ){
    orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
    pParse->trigStack->orconf = orconf;
    switch( pTriggerStep->op ){
      case TK_SELECT: {
        Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect);
        if( ss ){
          sqlite3SelectResolve(pParse, ss, 0);
          sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
          sqlite3SelectDelete(ss);
        }
        break;
      }
      case TK_UPDATE: {
        SrcList *pSrc;
        pSrc = targetSrcList(pParse, pTriggerStep);
        sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
        sqlite3Update(pParse, pSrc,
                sqlite3ExprListDup(db, pTriggerStep->pExprList), 
                sqlite3ExprDup(db, pTriggerStep->pWhere), orconf);
        sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
        break;
      }
      case TK_INSERT: {
        SrcList *pSrc;
        pSrc = targetSrcList(pParse, pTriggerStep);
        sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
        sqlite3Insert(pParse, pSrc,
          sqlite3ExprListDup(db, pTriggerStep->pExprList), 
          sqlite3SelectDup(db, pTriggerStep->pSelect), 
          sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
        sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
        break;
      }
      case TK_DELETE: {
        SrcList *pSrc;
        sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
        pSrc = targetSrcList(pParse, pTriggerStep);
        sqlite3DeleteFrom(pParse, pSrc, 
                          sqlite3ExprDup(db, pTriggerStep->pWhere));
        sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
        break;
      }
      default:
        assert(0);
    } 
    pTriggerStep = pTriggerStep->pNext;
  }
  sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
  VdbeComment((v, "# end trigger %s", pStepList->pTrig->name));

  return 0;
}
Beispiel #11
0
/*
** Generate VDBE code for the statements inside the body of a single 
** trigger.
*/
static int codeTriggerProgram(
  Parse *pParse,            /* The parser context */
  TriggerStep *pStepList,   /* List of statements inside the trigger body */
  int orconf                /* Conflict algorithm. (OE_Abort, etc) */  
){
  TriggerStep *pStep;
  Vdbe *v = pParse->pVdbe;
  sqlite3 *db = pParse->db;

  assert( pParse->pTriggerTab && pParse->pToplevel );
  assert( pStepList );
  assert( v!=0 );
  for(pStep=pStepList; pStep; pStep=pStep->pNext){
    /* Figure out the ON CONFLICT policy that will be used for this step
    ** of the trigger program. If the statement that caused this trigger
    ** to fire had an explicit ON CONFLICT, then use it. Otherwise, use
    ** the ON CONFLICT policy that was specified as part of the trigger
    ** step statement. Example:
    **
    **   CREATE TRIGGER AFTER INSERT ON t1 BEGIN;
    **     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
    **   END;
    **
    **   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
    **   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
    */
    pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
    assert( pParse->okConstFactor==0 );

    switch( pStep->op ){
      case TK_UPDATE: {
        sqlite3Update(pParse, 
          targetSrcList(pParse, pStep),
          sqlite3ExprListDup(db, pStep->pExprList, 0), 
          sqlite3ExprDup(db, pStep->pWhere, 0), 
          pParse->eOrconf
        );
        break;
      }
      case TK_INSERT: {
        sqlite3Insert(pParse, 
          targetSrcList(pParse, pStep),
          sqlite3SelectDup(db, pStep->pSelect, 0), 
          sqlite3IdListDup(db, pStep->pIdList), 
          pParse->eOrconf
        );
        break;
      }
      case TK_DELETE: {
        sqlite3DeleteFrom(pParse, 
          targetSrcList(pParse, pStep),
          sqlite3ExprDup(db, pStep->pWhere, 0)
        );
        break;
      }
      default: assert( pStep->op==TK_SELECT ); {
        SelectDest sDest;
        Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0);
        sqlite3SelectDestInit(&sDest, SRT_Discard, 0);
        sqlite3Select(pParse, pSelect, &sDest);
        sqlite3SelectDelete(db, pSelect);
        break;
      }
    } 
    if( pStep->op!=TK_SELECT ){
      sqlite3VdbeAddOp0(v, OP_ResetCount);
    }
  }

  return 0;
}
Beispiel #12
0
/*
** This function is called when an UPDATE or DELETE operation is being 
** compiled on table pTab, which is the parent table of foreign-key pFKey.
** If the current operation is an UPDATE, then the pChanges parameter is
** passed a pointer to the list of columns being modified. If it is a
** DELETE, pChanges is passed a NULL pointer.
**
** It returns a pointer to a Trigger structure containing a trigger
** equivalent to the ON UPDATE or ON DELETE action specified by pFKey.
** If the action is "NO ACTION" or "RESTRICT", then a NULL pointer is
** returned (these actions require no special handling by the triggers
** sub-system, code for them is created by fkScanChildren()).
**
** For example, if pFKey is the foreign key and pTab is table "p" in 
** the following schema:
**
**   CREATE TABLE p(pk PRIMARY KEY);
**   CREATE TABLE c(ck REFERENCES p ON DELETE CASCADE);
**
** then the returned trigger structure is equivalent to:
**
**   CREATE TRIGGER ... DELETE ON p BEGIN
**     DELETE FROM c WHERE ck = old.pk;
**   END;
**
** The returned pointer is cached as part of the foreign key object. It
** is eventually freed along with the rest of the foreign key object by 
** sqlite3FkDelete().
*/
static Trigger *fkActionTrigger(
  Parse *pParse,                  /* Parse context */
  Table *pTab,                    /* Table being updated or deleted from */
  FKey *pFKey,                    /* Foreign key to get action for */
  ExprList *pChanges              /* Change-list for UPDATE, NULL for DELETE */
){
  sqlite3 *db = pParse->db;       /* Database handle */
  int action;                     /* One of OE_None, OE_Cascade etc. */
  Trigger *pTrigger;              /* Trigger definition to return */
  int iAction = (pChanges!=0);    /* 1 for UPDATE, 0 for DELETE */

  action = pFKey->aAction[iAction];
  pTrigger = pFKey->apTrigger[iAction];

  if( action!=OE_None && !pTrigger ){
    u8 enableLookaside;           /* Copy of db->lookaside.bEnabled */
    char const *zFrom;            /* Name of child table */
    int nFrom;                    /* Length in bytes of zFrom */
    Index *pIdx = 0;              /* Parent key index for this FK */
    int *aiCol = 0;               /* child table cols -> parent key cols */
    TriggerStep *pStep = 0;        /* First (only) step of trigger program */
    Expr *pWhere = 0;             /* WHERE clause of trigger step */
    ExprList *pList = 0;          /* Changes list if ON UPDATE CASCADE */
    Select *pSelect = 0;          /* If RESTRICT, "SELECT RAISE(...)" */
    int i;                        /* Iterator variable */
    Expr *pWhen = 0;              /* WHEN clause for the trigger */

    if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0;
    assert( aiCol || pFKey->nCol==1 );

    for(i=0; i<pFKey->nCol; i++){
      Token tOld = { "old", 3 };  /* Literal "old" token */
      Token tNew = { "new", 3 };  /* Literal "new" token */
      Token tFromCol;             /* Name of column in child table */
      Token tToCol;               /* Name of column in parent table */
      int iFromCol;               /* Idx of column in child table */
      Expr *pEq;                  /* tFromCol = OLD.tToCol */

      iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
      assert( iFromCol>=0 );
      tToCol.z = pIdx ? pTab->aCol[pIdx->aiColumn[i]].zName : "oid";
      tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;

      tToCol.n = sqlite3Strlen30(tToCol.z);
      tFromCol.n = sqlite3Strlen30(tFromCol.z);

      /* Create the expression "OLD.zToCol = zFromCol". It is important
      ** that the "OLD.zToCol" term is on the LHS of the = operator, so
      ** that the affinity and collation sequence associated with the
      ** parent table are used for the comparison. */
      pEq = sqlite3PExpr(pParse, TK_EQ,
          sqlite3PExpr(pParse, TK_DOT, 
            sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld),
            sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol)
          , 0),
          sqlite3PExpr(pParse, TK_ID, 0, 0, &tFromCol)
      , 0);
      pWhere = sqlite3ExprAnd(db, pWhere, pEq);

      /* For ON UPDATE, construct the next term of the WHEN clause.
      ** The final WHEN clause will be like this:
      **
      **    WHEN NOT(old.col1 IS new.col1 AND ... AND old.colN IS new.colN)
      */
      if( pChanges ){
        pEq = sqlite3PExpr(pParse, TK_IS,
            sqlite3PExpr(pParse, TK_DOT, 
              sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld),
              sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol),
              0),
            sqlite3PExpr(pParse, TK_DOT, 
              sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew),
              sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol),
              0),
            0);
        pWhen = sqlite3ExprAnd(db, pWhen, pEq);
      }
  
      if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){
        Expr *pNew;
        if( action==OE_Cascade ){
          pNew = sqlite3PExpr(pParse, TK_DOT, 
            sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew),
            sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol)
          , 0);
        }else if( action==OE_SetDflt ){
          Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
          if( pDflt ){
            pNew = sqlite3ExprDup(db, pDflt, 0);
          }else{
            pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
          }
        }else{
          pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
        }
        pList = sqlite3ExprListAppend(pParse, pList, pNew);
        sqlite3ExprListSetName(pParse, pList, &tFromCol, 0);
      }
    }
    sqlite3DbFree(db, aiCol);

    zFrom = pFKey->pFrom->zName;
    nFrom = sqlite3Strlen30(zFrom);

    if( action==OE_Restrict ){
      Token tFrom;
      Expr *pRaise; 

      tFrom.z = zFrom;
      tFrom.n = nFrom;
      pRaise = sqlite3Expr(db, TK_RAISE, "foreign key constraint failed");
      if( pRaise ){
        pRaise->affinity = OE_Abort;
      }
      pSelect = sqlite3SelectNew(pParse, 
          sqlite3ExprListAppend(pParse, 0, pRaise),
          sqlite3SrcListAppend(db, 0, &tFrom, 0),
          pWhere,
          0, 0, 0, 0, 0, 0
      );
      pWhere = 0;
    }

    /* Disable lookaside memory allocation */
    enableLookaside = db->lookaside.bEnabled;
    db->lookaside.bEnabled = 0;

    pTrigger = (Trigger *)sqlite3DbMallocZero(db, 
        sizeof(Trigger) +         /* struct Trigger */
        sizeof(TriggerStep) +     /* Single step in trigger program */
        nFrom + 1                 /* Space for pStep->target.z */
    );
    if( pTrigger ){
      pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
      pStep->target.z = (char *)&pStep[1];
      pStep->target.n = nFrom;
      memcpy((char *)pStep->target.z, zFrom, nFrom);
  
      pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
      pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
      pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
      if( pWhen ){
        pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0);
        pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
      }
    }

    /* Re-enable the lookaside buffer, if it was disabled earlier. */
    db->lookaside.bEnabled = enableLookaside;

    sqlite3ExprDelete(db, pWhere);
    sqlite3ExprDelete(db, pWhen);
    sqlite3ExprListDelete(db, pList);
    sqlite3SelectDelete(db, pSelect);
    if( db->mallocFailed==1 ){
      fkTriggerDelete(db, pTrigger);
      return 0;
    }
    assert( pStep!=0 );

    switch( action ){
      case OE_Restrict:
        pStep->op = TK_SELECT; 
        break;
      case OE_Cascade: 
        if( !pChanges ){ 
          pStep->op = TK_DELETE; 
          break; 
        }
      default:
        pStep->op = TK_UPDATE;
    }
    pStep->pTrig = pTrigger;
    pTrigger->pSchema = pTab->pSchema;
    pTrigger->pTabSchema = pTab->pSchema;
    pFKey->apTrigger[iAction] = pTrigger;
    pTrigger->op = (pChanges ? TK_UPDATE : TK_DELETE);
  }

  return pTrigger;
}