⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trigger.c

📁 qt-x11-opensource-src-4.1.4.tar.gz源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ** Recursively delete a Trigger structure*/void sqlite3DeleteTrigger(Trigger *pTrigger){  if( pTrigger==0 ) return;  sqlite3DeleteTriggerStep(pTrigger->step_list);  sqliteFree(pTrigger->name);  sqliteFree(pTrigger->table);  sqlite3ExprDelete(pTrigger->pWhen);  sqlite3IdListDelete(pTrigger->pColumns);  if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);  sqliteFree(pTrigger);}/*** This function is called to drop a trigger from the database schema. **** This may be called directly from the parser and therefore identifies** the trigger by name.  The sqlite3DropTriggerPtr() routine does the** same job as this routine except it takes a pointer to the trigger** instead of the trigger name.**/void sqlite3DropTrigger(Parse *pParse, SrcList *pName){  Trigger *pTrigger = 0;  int i;  const char *zDb;  const char *zName;  int nName;  sqlite3 *db = pParse->db;  if( sqlite3_malloc_failed ) goto drop_trigger_cleanup;  if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){    goto drop_trigger_cleanup;  }  assert( pName->nSrc==1 );  zDb = pName->a[0].zDatabase;  zName = pName->a[0].zName;  nName = strlen(zName);  for(i=OMIT_TEMPDB; i<db->nDb; i++){    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */    if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;    pTrigger = sqlite3HashFind(&(db->aDb[j].trigHash), zName, nName+1);    if( pTrigger ) break;  }  if( !pTrigger ){    sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);    goto drop_trigger_cleanup;  }  sqlite3DropTriggerPtr(pParse, pTrigger, 0);drop_trigger_cleanup:  sqlite3SrcListDelete(pName);}/*** Return a pointer to the Table structure for the table that a trigger** is set on.*/static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){  return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);}/*** Drop a trigger given a pointer to that trigger.  If nested is false,** then also generate code to remove the trigger from the SQLITE_MASTER** table.*/void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){  Table   *pTable;  Vdbe *v;  sqlite3 *db = pParse->db;  int iDb;  iDb = pTrigger->iDb;  assert( iDb>=0 && iDb<db->nDb );  pTable = tableOfTrigger(db, pTrigger);  assert(pTable);  assert( pTable->iDb==iDb || iDb==1 );#ifndef SQLITE_OMIT_AUTHORIZATION  {    int code = SQLITE_DROP_TRIGGER;    const char *zDb = db->aDb[iDb].zName;    const char *zTab = SCHEMA_TABLE(iDb);    if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;    if( sqlite3AuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||      sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){      return;    }  }#endif  /* Generate code to destroy the database record of the trigger.  */  if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){    int base;    static const VdbeOpList dropTrigger[] = {      { OP_Rewind,     0, ADDR(9),  0},      { OP_String8,    0, 0,        0}, /* 1 */      { OP_Column,     0, 1,        0},      { OP_Ne,         0, ADDR(8),  0},      { OP_String8,    0, 0,        "trigger"},      { OP_Column,     0, 0,        0},      { OP_Ne,         0, ADDR(8),  0},      { OP_Delete,     0, 0,        0},      { OP_Next,       0, ADDR(1),  0}, /* 8 */    };    sqlite3BeginWriteOperation(pParse, 0, iDb);    sqlite3OpenMasterTable(v, iDb);    base = sqlite3VdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);    sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);    sqlite3ChangeCookie(db, v, iDb);    sqlite3VdbeAddOp(v, OP_Close, 0, 0);    sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0);  }}/*** Remove a trigger from the hash tables of the sqlite* pointer.*/void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){  Trigger *pTrigger;  int nName = strlen(zName);  pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0);  if( pTrigger ){    Table *pTable = tableOfTrigger(db, pTrigger);    assert( pTable!=0 );    if( pTable->pTrigger == pTrigger ){      pTable->pTrigger = pTrigger->pNext;    }else{      Trigger *cc = pTable->pTrigger;      while( cc ){         if( cc->pNext == pTrigger ){          cc->pNext = cc->pNext->pNext;          break;        }        cc = cc->pNext;      }      assert(cc);    }    sqlite3DeleteTrigger(pTrigger);    db->flags |= SQLITE_InternChanges;  }}/*** pEList is the SET clause of an UPDATE statement.  Each entry** in pEList is of the format <id>=<expr>.  If any of the entries** in pEList have an <id> which matches an identifier in pIdList,** then return TRUE.  If pIdList==NULL, then it is considered a** wildcard that matches anything.  Likewise if pEList==NULL then** it matches anything so always return true.  Return false only** if there is no match.*/static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){  int e;  if( !pIdList || !pEList ) return 1;  for(e=0; e<pEList->nExpr; e++){    if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;  }  return 0; }/*** Return a bit vector to indicate what kind of triggers exist for operation** "op" on table pTab.  If pChanges is not NULL then it is a list of columns** that are being updated.  Triggers only match if the ON clause of the** trigger definition overlaps the set of columns being updated.**** The returned bit vector is some combination of TRIGGER_BEFORE and** TRIGGER_AFTER.*/int sqlite3TriggersExist(  Parse *pParse,          /* Used to check for recursive triggers */  Table *pTab,            /* The table the contains the triggers */  int op,                 /* one of TK_DELETE, TK_INSERT, TK_UPDATE */  ExprList *pChanges      /* Columns that change in an UPDATE statement */){  Trigger *pTrigger = pTab->pTrigger;  int mask = 0;  while( pTrigger ){    if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){      TriggerStack *ss;      ss = pParse->trigStack;      while( ss && ss->pTrigger!=pTab->pTrigger ){	ss = ss->pNext;      }      if( ss==0 ){        mask |= pTrigger->tr_tm;      }    }    pTrigger = pTrigger->pNext;  }  return mask;}/*** Convert the pStep->target token into a SrcList and return a pointer** to that SrcList.**** This routine adds a specific database name, if needed, to the target when** forming the SrcList.  This prevents a trigger in one database from** referring to a target in another database.  An exception is when the** trigger is in TEMP in which case it can refer to any other database it** wants.*/static SrcList *targetSrcList(  Parse *pParse,       /* The parsing context */  TriggerStep *pStep   /* The trigger containing the target token */){  Token sDb;           /* Dummy database name token */  int iDb;             /* Index of the database to use */  SrcList *pSrc;       /* SrcList to be returned */  iDb = pStep->pTrig->iDb;  if( iDb==0 || iDb>=2 ){    assert( iDb<pParse->db->nDb );    sDb.z = pParse->db->aDb[iDb].zName;    sDb.n = strlen(sDb.z);    pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target);  } else {    pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);  }  return pSrc;}/*** 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;  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(pTriggerStep->pSelect);		  	assert(ss);	assert(ss->pSrc);        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(pTriggerStep->pExprList), 		sqlite3ExprDup(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(pTriggerStep->pExprList),           sqlite3SelectDup(pTriggerStep->pSelect),           sqlite3IdListDup(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(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;}/*** This is called to code FOR EACH ROW triggers.**** When the code that this function generates is executed, the following ** must be true:**** 1. No cursors may be open in the main database.  (But newIdx and oldIdx**    can be indices of cursors in temporary tables.  See below.)**** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then**    a temporary vdbe cursor (index newIdx) must be open and pointing at**    a row containing values to be substituted for new.* expressions in the**    trigger program(s).**** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then**    a temporary vdbe cursor (index oldIdx) must be open and pointing at**    a row containing values to be substituted for old.* expressions in the**    trigger program(s).***/int sqlite3CodeRowTrigger(  Parse *pParse,       /* Parse context */  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 newIdx,          /* The indice of the "new" row to access */  int oldIdx,          /* The indice of the "old" row to access */  int orconf,          /* ON CONFLICT policy */  int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */){  Trigger *pTrigger;  TriggerStack *pStack;  TriggerStack trigStackEntry;  assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);  assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );  assert(newIdx != -1 || oldIdx != -1);  pTrigger = pTab->pTrigger;  while( pTrigger ){    int fire_this = 0;    /* determine whether we should code this trigger */    if( pTrigger->op == op && pTrigger->tr_tm == tr_tm ){      fire_this = 1;      for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){        if( pStack->pTrigger==pTrigger ){	  fire_this = 0;	}      }      if( op == TK_UPDATE && pTrigger->pColumns &&          !checkColumnOverLap(pTrigger->pColumns, pChanges) ){        fire_this = 0;      }    }     if( fire_this ){      int endTrigger;      Expr * whenExpr;      AuthContext sContext;      NameContext sNC;      memset(&sNC, 0, sizeof(sNC));      sNC.pParse = pParse;      /* Push an entry on to the trigger stack */      trigStackEntry.pTrigger = pTrigger;      trigStackEntry.newIdx = newIdx;      trigStackEntry.oldIdx = oldIdx;      trigStackEntry.pTab = pTab;      trigStackEntry.pNext = pParse->trigStack;      trigStackEntry.ignoreJump = ignoreJump;      pParse->trigStack = &trigStackEntry;      sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);      /* code the WHEN clause */      endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);      whenExpr = sqlite3ExprDup(pTrigger->pWhen);      if( sqlite3ExprResolveNames(&sNC, whenExpr) ){        pParse->trigStack = trigStackEntry.pNext;        sqlite3ExprDelete(whenExpr);        return 1;      }      sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);      sqlite3ExprDelete(whenExpr);      codeTriggerProgram(pParse, pTrigger->step_list, orconf);       /* Pop the entry off the trigger stack */      pParse->trigStack = trigStackEntry.pNext;      sqlite3AuthContextPop(&sContext);      sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);    }    pTrigger = pTrigger->pNext;  }  return 0;}#endif /* !defined(SQLITE_OMIT_TRIGGER) */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -