aboutsummaryrefslogtreecommitdiff
path: root/src/trigger.c
diff options
context:
space:
mode:
authordan <dan@noemail.net>2009-09-19 17:00:31 +0000
committerdan <dan@noemail.net>2009-09-19 17:00:31 +0000
commit1da40a381fcf28953cd914aa1cff2d4d2f30ffb0 (patch)
tree499fd358c9173002d540833d9a7a77c3421119d4 /src/trigger.c
parent3991bb0deec345af79e0346bc0b29a0f8a594a3a (diff)
downloadsqlite-1da40a381fcf28953cd914aa1cff2d4d2f30ffb0.tar.gz
sqlite-1da40a381fcf28953cd914aa1cff2d4d2f30ffb0.zip
Check in implementation of foreign key constraints.
FossilOrigin-Name: d5d399811876391642937edeb9e8434dd9e356f5
Diffstat (limited to 'src/trigger.c')
-rw-r--r--src/trigger.c53
1 files changed, 36 insertions, 17 deletions
diff --git a/src/trigger.c b/src/trigger.c
index f06226734..79f7f486d 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -795,7 +795,7 @@ static TriggerPrg *codeRowTrigger(
Parse *pSubParse; /* Parse context for sub-vdbe */
int iEndTrigger = 0; /* Label to jump to if WHEN is false */
- assert( pTab==tableOfTrigger(pTrigger) );
+ assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
/* Allocate the TriggerPrg and SubProgram objects. To ensure that they
** are freed if an error occurs, link them into the Parse.pTriggerPrg
@@ -896,7 +896,7 @@ static TriggerPrg *getRowTrigger(
Parse *pRoot = sqlite3ParseToplevel(pParse);
TriggerPrg *pPrg;
- assert( pTab==tableOfTrigger(pTrigger) );
+ assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
/* It may be that this trigger has already been coded (or is in the
** process of being coded). If this is the case, then an entry with
@@ -915,6 +915,38 @@ static TriggerPrg *getRowTrigger(
return pPrg;
}
+void sqlite3CodeRowTriggerDirect(
+ Parse *pParse, /* Parse context */
+ Trigger *p, /* Trigger to code */
+ Table *pTab, /* The table to code triggers from */
+ int oldIdx, /* The indice of the "old" row to access */
+ int orconf, /* ON CONFLICT policy */
+ int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
+){
+ Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */
+ TriggerPrg *pPrg;
+ pPrg = getRowTrigger(pParse, p, pTab, orconf);
+ assert( pPrg || pParse->nErr || pParse->db->mallocFailed );
+
+ /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
+ ** is a pointer to the sub-vdbe containing the trigger program. */
+ if( pPrg ){
+ sqlite3VdbeAddOp3(v, OP_Program, oldIdx, ignoreJump, ++pParse->nMem);
+ pPrg->pProgram->nRef++;
+ sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
+ VdbeComment(
+ (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
+
+ /* Set the P5 operand of the OP_Program instruction to non-zero if
+ ** recursive invocation of this trigger program is disallowed. Recursive
+ ** invocation is disallowed if (a) the sub-program is really a trigger,
+ ** not a foreign key action, and (b) the flag to enable recursive triggers
+ ** is clear. */
+ sqlite3VdbeChangeP5(v, p->zName && !(pParse->db->flags&SQLITE_RecTriggers));
+
+ }
+}
+
/*
** This is called to code FOR EACH ROW triggers.
**
@@ -976,19 +1008,7 @@ void sqlite3CodeRowTrigger(
&& p->tr_tm==tr_tm
&& checkColumnOverlap(p->pColumns,pChanges)
){
- Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */
- TriggerPrg *pPrg;
- pPrg = getRowTrigger(pParse, p, pTab, orconf);
- assert( pPrg || pParse->nErr || pParse->db->mallocFailed );
-
- /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
- ** is a pointer to the sub-vdbe containing the trigger program. */
- if( pPrg ){
- sqlite3VdbeAddOp3(v, OP_Program, oldIdx, ignoreJump, ++pParse->nMem);
- pPrg->pProgram->nRef++;
- sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
- VdbeComment((v, "Call: %s.%s", p->zName, onErrorText(orconf)));
- }
+ sqlite3CodeRowTriggerDirect(pParse, p, pTab, oldIdx, orconf, ignoreJump);
}
}
}
@@ -1015,15 +1035,14 @@ void sqlite3CodeRowTrigger(
u32 sqlite3TriggerOldmask(
Parse *pParse, /* Parse context */
Trigger *pTrigger, /* List of triggers on table pTab */
- int op, /* Either TK_UPDATE or TK_DELETE */
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
Table *pTab, /* The table to code triggers from */
int orconf /* Default ON CONFLICT policy for trigger steps */
){
+ const int op = pChanges ? TK_UPDATE : TK_DELETE;
u32 mask = 0;
Trigger *p;
- assert(op==TK_UPDATE || op==TK_DELETE);
for(p=pTrigger; p; p=p->pNext){
if( p->op==op && checkColumnOverlap(p->pColumns,pChanges) ){
TriggerPrg *pPrg;