OLD | NEW |
1 /* | 1 /* |
2 ** | 2 ** |
3 ** The author disclaims copyright to this source code. In place of | 3 ** The author disclaims copyright to this source code. In place of |
4 ** a legal notice, here is a blessing: | 4 ** a legal notice, here is a blessing: |
5 ** | 5 ** |
6 ** May you do good and not evil. | 6 ** May you do good and not evil. |
7 ** May you find forgiveness for yourself and forgive others. | 7 ** May you find forgiveness for yourself and forgive others. |
8 ** May you share freely, never taking more than you give. | 8 ** May you share freely, never taking more than you give. |
9 ** | 9 ** |
10 ************************************************************************* | 10 ************************************************************************* |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 int isTemp, /* True if the TEMPORARY keyword is present */ | 89 int isTemp, /* True if the TEMPORARY keyword is present */ |
90 int noErr /* Suppress errors if the trigger already exists */ | 90 int noErr /* Suppress errors if the trigger already exists */ |
91 ){ | 91 ){ |
92 Trigger *pTrigger = 0; /* The new trigger */ | 92 Trigger *pTrigger = 0; /* The new trigger */ |
93 Table *pTab; /* Table that the trigger fires off of */ | 93 Table *pTab; /* Table that the trigger fires off of */ |
94 char *zName = 0; /* Name of the trigger */ | 94 char *zName = 0; /* Name of the trigger */ |
95 sqlite3 *db = pParse->db; /* The database connection */ | 95 sqlite3 *db = pParse->db; /* The database connection */ |
96 int iDb; /* The database to store the trigger in */ | 96 int iDb; /* The database to store the trigger in */ |
97 Token *pName; /* The unqualified db name */ | 97 Token *pName; /* The unqualified db name */ |
98 DbFixer sFix; /* State vector for the DB fixer */ | 98 DbFixer sFix; /* State vector for the DB fixer */ |
99 int iTabDb; /* Index of the database holding pTab */ | |
100 | 99 |
101 assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ | 100 assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ |
102 assert( pName2!=0 ); | 101 assert( pName2!=0 ); |
103 assert( op==TK_INSERT || op==TK_UPDATE || op==TK_DELETE ); | 102 assert( op==TK_INSERT || op==TK_UPDATE || op==TK_DELETE ); |
104 assert( op>0 && op<0xff ); | 103 assert( op>0 && op<0xff ); |
105 if( isTemp ){ | 104 if( isTemp ){ |
106 /* If TEMP was specified, then the trigger name may not be qualified. */ | 105 /* If TEMP was specified, then the trigger name may not be qualified. */ |
107 if( pName2->n>0 ){ | 106 if( pName2->n>0 ){ |
108 sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name"); | 107 sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name"); |
109 goto trigger_cleanup; | 108 goto trigger_cleanup; |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ | 201 if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ |
203 sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", | 202 sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", |
204 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); | 203 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); |
205 goto trigger_cleanup; | 204 goto trigger_cleanup; |
206 } | 205 } |
207 if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ | 206 if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ |
208 sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" | 207 sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" |
209 " trigger on table: %S", pTableName, 0); | 208 " trigger on table: %S", pTableName, 0); |
210 goto trigger_cleanup; | 209 goto trigger_cleanup; |
211 } | 210 } |
212 iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); | |
213 | 211 |
214 #ifndef SQLITE_OMIT_AUTHORIZATION | 212 #ifndef SQLITE_OMIT_AUTHORIZATION |
215 { | 213 { |
| 214 int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
216 int code = SQLITE_CREATE_TRIGGER; | 215 int code = SQLITE_CREATE_TRIGGER; |
217 const char *zDb = db->aDb[iTabDb].zName; | 216 const char *zDb = db->aDb[iTabDb].zDbSName; |
218 const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb; | 217 const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb; |
219 if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; | 218 if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; |
220 if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ | 219 if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ |
221 goto trigger_cleanup; | 220 goto trigger_cleanup; |
222 } | 221 } |
223 if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){ | 222 if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){ |
224 goto trigger_cleanup; | 223 goto trigger_cleanup; |
225 } | 224 } |
226 } | 225 } |
227 #endif | 226 #endif |
228 | 227 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 | 279 |
281 pParse->pNewTrigger = 0; | 280 pParse->pNewTrigger = 0; |
282 if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; | 281 if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; |
283 zName = pTrig->zName; | 282 zName = pTrig->zName; |
284 iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); | 283 iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); |
285 pTrig->step_list = pStepList; | 284 pTrig->step_list = pStepList; |
286 while( pStepList ){ | 285 while( pStepList ){ |
287 pStepList->pTrig = pTrig; | 286 pStepList->pTrig = pTrig; |
288 pStepList = pStepList->pNext; | 287 pStepList = pStepList->pNext; |
289 } | 288 } |
290 nameToken.z = pTrig->zName; | 289 sqlite3TokenInit(&nameToken, pTrig->zName); |
291 nameToken.n = sqlite3Strlen30(nameToken.z); | |
292 sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); | 290 sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); |
293 if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) | 291 if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) |
294 || sqlite3FixExpr(&sFix, pTrig->pWhen) | 292 || sqlite3FixExpr(&sFix, pTrig->pWhen) |
295 ){ | 293 ){ |
296 goto triggerfinish_cleanup; | 294 goto triggerfinish_cleanup; |
297 } | 295 } |
298 | 296 |
299 /* if we are not initializing, | 297 /* if we are not initializing, |
300 ** build the sqlite_master entry | 298 ** build the sqlite_master entry |
301 */ | 299 */ |
302 if( !db->init.busy ){ | 300 if( !db->init.busy ){ |
303 Vdbe *v; | 301 Vdbe *v; |
304 char *z; | 302 char *z; |
305 | 303 |
306 /* Make an entry in the sqlite_master table */ | 304 /* Make an entry in the sqlite_master table */ |
307 v = sqlite3GetVdbe(pParse); | 305 v = sqlite3GetVdbe(pParse); |
308 if( v==0 ) goto triggerfinish_cleanup; | 306 if( v==0 ) goto triggerfinish_cleanup; |
309 sqlite3BeginWriteOperation(pParse, 0, iDb); | 307 sqlite3BeginWriteOperation(pParse, 0, iDb); |
310 z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); | 308 z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); |
311 sqlite3NestedParse(pParse, | 309 sqlite3NestedParse(pParse, |
312 "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", | 310 "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", |
313 db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, | 311 db->aDb[iDb].zDbSName, MASTER_NAME, zName, |
314 pTrig->table, z); | 312 pTrig->table, z); |
315 sqlite3DbFree(db, z); | 313 sqlite3DbFree(db, z); |
316 sqlite3ChangeCookie(pParse, iDb); | 314 sqlite3ChangeCookie(pParse, iDb); |
317 sqlite3VdbeAddParseSchemaOp(v, iDb, | 315 sqlite3VdbeAddParseSchemaOp(v, iDb, |
318 sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); | 316 sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); |
319 } | 317 } |
320 | 318 |
321 if( db->init.busy ){ | 319 if( db->init.busy ){ |
322 Trigger *pLink = pTrig; | 320 Trigger *pLink = pTrig; |
323 Hash *pHash = &db->aDb[iDb].pSchema->trigHash; | 321 Hash *pHash = &db->aDb[iDb].pSchema->trigHash; |
324 assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); | 322 assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
325 pTrig = sqlite3HashInsert(pHash, zName, pTrig); | 323 pTrig = sqlite3HashInsert(pHash, zName, pTrig); |
326 if( pTrig ){ | 324 if( pTrig ){ |
327 db->mallocFailed = 1; | 325 sqlite3OomFault(db); |
328 }else if( pLink->pSchema==pLink->pTabSchema ){ | 326 }else if( pLink->pSchema==pLink->pTabSchema ){ |
329 Table *pTab; | 327 Table *pTab; |
330 pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table); | 328 pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table); |
331 assert( pTab!=0 ); | 329 assert( pTab!=0 ); |
332 pLink->pNext = pTab->pTrigger; | 330 pLink->pNext = pTab->pTrigger; |
333 pTab->pTrigger = pLink; | 331 pTab->pTrigger = pLink; |
334 } | 332 } |
335 } | 333 } |
336 | 334 |
337 triggerfinish_cleanup: | 335 triggerfinish_cleanup: |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
492 if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ | 490 if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
493 goto drop_trigger_cleanup; | 491 goto drop_trigger_cleanup; |
494 } | 492 } |
495 | 493 |
496 assert( pName->nSrc==1 ); | 494 assert( pName->nSrc==1 ); |
497 zDb = pName->a[0].zDatabase; | 495 zDb = pName->a[0].zDatabase; |
498 zName = pName->a[0].zName; | 496 zName = pName->a[0].zName; |
499 assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); | 497 assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); |
500 for(i=OMIT_TEMPDB; i<db->nDb; i++){ | 498 for(i=OMIT_TEMPDB; i<db->nDb; i++){ |
501 int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ | 499 int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ |
502 if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; | 500 if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue; |
503 assert( sqlite3SchemaMutexHeld(db, j, 0) ); | 501 assert( sqlite3SchemaMutexHeld(db, j, 0) ); |
504 pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); | 502 pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); |
505 if( pTrigger ) break; | 503 if( pTrigger ) break; |
506 } | 504 } |
507 if( !pTrigger ){ | 505 if( !pTrigger ){ |
508 if( !noErr ){ | 506 if( !noErr ){ |
509 sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); | 507 sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); |
510 }else{ | 508 }else{ |
511 sqlite3CodeVerifyNamedSchema(pParse, zDb); | 509 sqlite3CodeVerifyNamedSchema(pParse, zDb); |
512 } | 510 } |
(...skipping 25 matching lines...) Expand all Loading... |
538 int iDb; | 536 int iDb; |
539 | 537 |
540 iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); | 538 iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); |
541 assert( iDb>=0 && iDb<db->nDb ); | 539 assert( iDb>=0 && iDb<db->nDb ); |
542 pTable = tableOfTrigger(pTrigger); | 540 pTable = tableOfTrigger(pTrigger); |
543 assert( pTable ); | 541 assert( pTable ); |
544 assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); | 542 assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); |
545 #ifndef SQLITE_OMIT_AUTHORIZATION | 543 #ifndef SQLITE_OMIT_AUTHORIZATION |
546 { | 544 { |
547 int code = SQLITE_DROP_TRIGGER; | 545 int code = SQLITE_DROP_TRIGGER; |
548 const char *zDb = db->aDb[iDb].zName; | 546 const char *zDb = db->aDb[iDb].zDbSName; |
549 const char *zTab = SCHEMA_TABLE(iDb); | 547 const char *zTab = SCHEMA_TABLE(iDb); |
550 if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; | 548 if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; |
551 if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || | 549 if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || |
552 sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ | 550 sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ |
553 return; | 551 return; |
554 } | 552 } |
555 } | 553 } |
556 #endif | 554 #endif |
557 | 555 |
558 /* Generate code to destroy the database record of the trigger. | 556 /* Generate code to destroy the database record of the trigger. |
559 */ | 557 */ |
560 assert( pTable!=0 ); | 558 assert( pTable!=0 ); |
561 if( (v = sqlite3GetVdbe(pParse))!=0 ){ | 559 if( (v = sqlite3GetVdbe(pParse))!=0 ){ |
562 sqlite3NestedParse(pParse, | 560 sqlite3NestedParse(pParse, |
563 "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", | 561 "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", |
564 db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrigger->zName | 562 db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName |
565 ); | 563 ); |
566 sqlite3ChangeCookie(pParse, iDb); | 564 sqlite3ChangeCookie(pParse, iDb); |
567 sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); | 565 sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); |
568 } | 566 } |
569 } | 567 } |
570 | 568 |
571 /* | 569 /* |
572 ** Remove a trigger from the hash tables of the sqlite* pointer. | 570 ** Remove a trigger from the hash tables of the sqlite* pointer. |
573 */ | 571 */ |
574 void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ | 572 void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 sqlite3 *db = pParse->db; | 655 sqlite3 *db = pParse->db; |
658 int iDb; /* Index of the database to use */ | 656 int iDb; /* Index of the database to use */ |
659 SrcList *pSrc; /* SrcList to be returned */ | 657 SrcList *pSrc; /* SrcList to be returned */ |
660 | 658 |
661 pSrc = sqlite3SrcListAppend(db, 0, 0, 0); | 659 pSrc = sqlite3SrcListAppend(db, 0, 0, 0); |
662 if( pSrc ){ | 660 if( pSrc ){ |
663 assert( pSrc->nSrc>0 ); | 661 assert( pSrc->nSrc>0 ); |
664 pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); | 662 pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); |
665 iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); | 663 iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); |
666 if( iDb==0 || iDb>=2 ){ | 664 if( iDb==0 || iDb>=2 ){ |
| 665 const char *zDb; |
667 assert( iDb<db->nDb ); | 666 assert( iDb<db->nDb ); |
668 pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); | 667 zDb = db->aDb[iDb].zDbSName; |
| 668 pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb); |
669 } | 669 } |
670 } | 670 } |
671 return pSrc; | 671 return pSrc; |
672 } | 672 } |
673 | 673 |
674 /* | 674 /* |
675 ** Generate VDBE code for the statements inside the body of a single | 675 ** Generate VDBE code for the statements inside the body of a single |
676 ** trigger. | 676 ** trigger. |
677 */ | 677 */ |
678 static int codeTriggerProgram( | 678 static int codeTriggerProgram( |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
872 } | 872 } |
873 sqlite3VdbeAddOp0(v, OP_Halt); | 873 sqlite3VdbeAddOp0(v, OP_Halt); |
874 VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); | 874 VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); |
875 | 875 |
876 transferParseError(pParse, pSubParse); | 876 transferParseError(pParse, pSubParse); |
877 if( db->mallocFailed==0 ){ | 877 if( db->mallocFailed==0 ){ |
878 pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); | 878 pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); |
879 } | 879 } |
880 pProgram->nMem = pSubParse->nMem; | 880 pProgram->nMem = pSubParse->nMem; |
881 pProgram->nCsr = pSubParse->nTab; | 881 pProgram->nCsr = pSubParse->nTab; |
882 pProgram->nOnce = pSubParse->nOnce; | |
883 pProgram->token = (void *)pTrigger; | 882 pProgram->token = (void *)pTrigger; |
884 pPrg->aColmask[0] = pSubParse->oldmask; | 883 pPrg->aColmask[0] = pSubParse->oldmask; |
885 pPrg->aColmask[1] = pSubParse->newmask; | 884 pPrg->aColmask[1] = pSubParse->newmask; |
886 sqlite3VdbeDelete(v); | 885 sqlite3VdbeDelete(v); |
887 } | 886 } |
888 | 887 |
889 assert( !pSubParse->pAinc && !pSubParse->pZombieTab ); | 888 assert( !pSubParse->pAinc && !pSubParse->pZombieTab ); |
890 assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); | 889 assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); |
891 sqlite3ParserReset(pSubParse); | 890 sqlite3ParserReset(pSubParse); |
892 sqlite3StackFree(db, pSubParse); | 891 sqlite3StackFree(db, pSubParse); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ | 944 Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ |
946 TriggerPrg *pPrg; | 945 TriggerPrg *pPrg; |
947 pPrg = getRowTrigger(pParse, p, pTab, orconf); | 946 pPrg = getRowTrigger(pParse, p, pTab, orconf); |
948 assert( pPrg || pParse->nErr || pParse->db->mallocFailed ); | 947 assert( pPrg || pParse->nErr || pParse->db->mallocFailed ); |
949 | 948 |
950 /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program | 949 /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program |
951 ** is a pointer to the sub-vdbe containing the trigger program. */ | 950 ** is a pointer to the sub-vdbe containing the trigger program. */ |
952 if( pPrg ){ | 951 if( pPrg ){ |
953 int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers)); | 952 int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers)); |
954 | 953 |
955 sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem); | 954 sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem, |
956 sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM); | 955 (const char *)pPrg->pProgram, P4_SUBPROGRAM); |
957 VdbeComment( | 956 VdbeComment( |
958 (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf))); | 957 (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf))); |
959 | 958 |
960 /* Set the P5 operand of the OP_Program instruction to non-zero if | 959 /* Set the P5 operand of the OP_Program instruction to non-zero if |
961 ** recursive invocation of this trigger program is disallowed. Recursive | 960 ** recursive invocation of this trigger program is disallowed. Recursive |
962 ** invocation is disallowed if (a) the sub-program is really a trigger, | 961 ** invocation is disallowed if (a) the sub-program is really a trigger, |
963 ** not a foreign key action, and (b) the flag to enable recursive triggers | 962 ** not a foreign key action, and (b) the flag to enable recursive triggers |
964 ** is clear. */ | 963 ** is clear. */ |
965 sqlite3VdbeChangeP5(v, (u8)bRecursive); | 964 sqlite3VdbeChangeP5(v, (u8)bRecursive); |
966 } | 965 } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1091 if( pPrg ){ | 1090 if( pPrg ){ |
1092 mask |= pPrg->aColmask[isNew]; | 1091 mask |= pPrg->aColmask[isNew]; |
1093 } | 1092 } |
1094 } | 1093 } |
1095 } | 1094 } |
1096 | 1095 |
1097 return mask; | 1096 return mask; |
1098 } | 1097 } |
1099 | 1098 |
1100 #endif /* !defined(SQLITE_OMIT_TRIGGER) */ | 1099 #endif /* !defined(SQLITE_OMIT_TRIGGER) */ |
OLD | NEW |