Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Changes to the trigger.c module that facilitate full coverage testing. (CVS 6621) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
567ccc68cc8c73b952a91c71a0e00b08 |
User & Date: | drh 2009-05-09 00:18:38.000 |
Context
2009-05-09
| ||
15:17 | Change sqlite_blob_open() so that it zeros the output pBlob pointer when it fails. The other sqlite3_blob interfaces accept a NULL pointer as input. (CVS 6622) (check-in: 999d507b44 user: drh tags: trunk) | |
00:18 | Changes to the trigger.c module that facilitate full coverage testing. (CVS 6621) (check-in: 567ccc68cc user: drh tags: trunk) | |
2009-05-08
| ||
11:34 | Fix a warning in the osx-specific part of os_unix.c. Ticket #3847. (CVS 6620) (check-in: 254ca3273c user: danielk1977 tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.433 2009/05/09 00:18:38 drh Exp $ */ #include "sqliteInt.h" /* ** Return the 'affinity' of the expression pExpr if any. ** ** If pExpr is a column, a reference to a column via an 'AS' alias, |
︙ | ︙ | |||
862 863 864 865 866 867 868 869 870 871 872 873 874 875 | } void sqlite3TokenCopy(sqlite3 *db, Token *pTo, const Token *pFrom){ if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z); if( pFrom->z ){ pTo->n = pFrom->n; pTo->z = (u8*)sqlite3DbStrNDup(db, (char*)pFrom->z, pFrom->n); pTo->dyn = 1; }else{ pTo->z = 0; } } ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ ExprList *pNew; struct ExprList_item *pItem, *pOldItem; | > | 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 | } void sqlite3TokenCopy(sqlite3 *db, Token *pTo, const Token *pFrom){ if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z); if( pFrom->z ){ pTo->n = pFrom->n; pTo->z = (u8*)sqlite3DbStrNDup(db, (char*)pFrom->z, pFrom->n); pTo->dyn = 1; pTo->quoted = pFrom->quoted; }else{ pTo->z = 0; } } ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ ExprList *pNew; struct ExprList_item *pItem, *pOldItem; |
︙ | ︙ |
Changes to src/trigger.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** ** $Id: trigger.c,v 1.139 2009/05/09 00:18:38 drh Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_TRIGGER /* ** Delete a linked list of TriggerStep structures. */ |
︙ | ︙ | |||
32 33 34 35 36 37 38 39 40 41 42 43 44 45 | sqlite3DbFree(db, pTmp); } } /* ** Given table pTab, return a list of all the triggers attached to ** the table. The list is connected by Trigger.pNext pointers. */ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ Schema * const pTmpSchema = pParse->db->aDb[1].pSchema; Trigger *pList = 0; /* List of triggers to return */ if( pTmpSchema!=pTab->pSchema ){ HashElem *p; | > > > > > > > > > > | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | sqlite3DbFree(db, pTmp); } } /* ** Given table pTab, return a list of all the triggers attached to ** the table. The list is connected by Trigger.pNext pointers. ** ** All of the triggers on pTab that are in the same database as pTab ** are already attached to pTab->pTrigger. But there might be additional ** triggers on pTab in the TEMP schema. This routine prepends all ** TEMP triggers on pTab to the beginning of the pTab->pTrigger list ** and returns the combined list. ** ** To state it another way: This routine returns a list of all triggers ** that fire off of pTab. The list will include any TEMP triggers on ** pTab as well as the triggers lised in pTab->pTrigger. */ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ Schema * const pTmpSchema = pParse->db->aDb[1].pSchema; Trigger *pList = 0; /* List of triggers to return */ if( pTmpSchema!=pTab->pSchema ){ HashElem *p; |
︙ | ︙ | |||
204 205 206 207 208 209 210 | pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); pTrigger->pColumns = sqlite3IdListDup(db, pColumns); | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); pTrigger->pColumns = sqlite3IdListDup(db, pColumns); sqlite3TokenCopy(db, &pTrigger->nameToken, pName); assert( pParse->pNewTrigger==0 ); pParse->pNewTrigger = pTrigger; trigger_cleanup: sqlite3DbFree(db, zName); sqlite3SrcListDelete(db, pTableName); sqlite3IdListDelete(db, pColumns); |
︙ | ︙ | |||
237 238 239 240 241 242 243 | char *zName; /* Name of trigger */ sqlite3 *db = pParse->db; /* The database */ DbFixer sFix; int iDb; /* Database containing the trigger */ pTrig = pParse->pNewTrigger; pParse->pNewTrigger = 0; | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | char *zName; /* Name of trigger */ sqlite3 *db = pParse->db; /* The database */ DbFixer sFix; int iDb; /* Database containing the trigger */ pTrig = pParse->pNewTrigger; pParse->pNewTrigger = 0; if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; zName = pTrig->name; iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; pStepList = pStepList->pNext; } |
︙ | ︙ | |||
456 457 458 459 460 461 462 | void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->name); sqlite3DbFree(db, pTrigger->table); sqlite3ExprDelete(db, pTrigger->pWhen); sqlite3IdListDelete(db, pTrigger->pColumns); | > | | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->name); sqlite3DbFree(db, pTrigger->table); sqlite3ExprDelete(db, pTrigger->pWhen); sqlite3IdListDelete(db, pTrigger->pColumns); assert( pTrigger->nameToken.dyn ); sqlite3DbFree(db, (char*)pTrigger->nameToken.z); sqlite3DbFree(db, pTrigger); } /* ** This function is called to drop a trigger from the database schema. ** ** This may be called directly from the parser and therefore identifies |
︙ | ︙ | |||
578 579 580 581 582 583 584 | /* ** Remove a trigger from the hash tables of the sqlite* pointer. */ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ Hash *pHash = &(db->aDb[iDb].pSchema->trigHash); Trigger *pTrigger; pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0); | | | | | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | /* ** Remove a trigger from the hash tables of the sqlite* pointer. */ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ Hash *pHash = &(db->aDb[iDb].pSchema->trigHash); Trigger *pTrigger; pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0); if( ALWAYS(pTrigger) ){ if( pTrigger->pSchema==pTrigger->pTabSchema ){ Table *pTab = tableOfTrigger(pTrigger); Trigger **pp; for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext)); *pp = (*pp)->pNext; } sqlite3DeleteTrigger(db, 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==0 || NEVER(pEList==0) ) return 1; for(e=0; e<pEList->nExpr; e++){ if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; } return 0; } /* |
︙ | ︙ | |||
626 627 628 629 630 631 632 | int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ ){ int mask = 0; Trigger *pList = sqlite3TriggerList(pParse, pTab); Trigger *p; assert( pList==0 || IsVirtual(pTab)==0 ); for(p=pList; p; p=p->pNext){ | | | 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ ){ int mask = 0; Trigger *pList = sqlite3TriggerList(pParse, pTab); Trigger *p; assert( pList==0 || IsVirtual(pTab)==0 ); for(p=pList; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; } } if( pMask ){ *pMask = mask; } return (mask ? pList : 0); |
︙ | ︙ | |||
690 691 692 693 694 695 696 | sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0); VdbeComment((v, "begin trigger %s", pStepList->pTrig->name)); while( pTriggerStep ){ sqlite3ExprCacheClear(pParse); orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; pParse->trigStack->orconf = orconf; switch( pTriggerStep->op ){ | < < < < < < < < < < < | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 | sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0); VdbeComment((v, "begin trigger %s", pStepList->pTrig->name)); while( pTriggerStep ){ sqlite3ExprCacheClear(pParse); orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; pParse->trigStack->orconf = orconf; switch( pTriggerStep->op ){ case TK_UPDATE: { SrcList *pSrc; pSrc = targetSrcList(pParse, pTriggerStep); sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0); sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db, pTriggerStep->pExprList, 0), sqlite3ExprDup(db, pTriggerStep->pWhere, 0), orconf); |
︙ | ︙ | |||
731 732 733 734 735 736 737 | sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0); pSrc = targetSrcList(pParse, pTriggerStep); sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(db, pTriggerStep->pWhere, 0)); sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0); break; } | | > > > | > > > > > > | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0); pSrc = targetSrcList(pParse, pTriggerStep); sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(db, pTriggerStep->pWhere, 0)); sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0); break; } default: assert( pTriggerStep->op==TK_SELECT ); { Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect, 0); if( ss ){ SelectDest dest; sqlite3SelectDestInit(&dest, SRT_Discard, 0); sqlite3Select(pParse, ss, &dest); sqlite3SelectDelete(db, ss); } break; } } pTriggerStep = pTriggerStep->pNext; } sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); VdbeComment((v, "end trigger %s", pStepList->pTrig->name)); return 0; |
︙ | ︙ | |||
798 799 800 801 802 803 804 805 806 807 808 | assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER ); assert(newIdx != -1 || oldIdx != -1); for(p=pTrigger; p; p=p->pNext){ int fire_this = 0; /* Determine whether we should code this trigger */ if( p->op==op && p->tr_tm==tr_tm && | > > > > > > > < | | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 | assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER ); assert(newIdx != -1 || oldIdx != -1); for(p=pTrigger; p; p=p->pNext){ int fire_this = 0; /* 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==db->aDb[1].pSchema ); /* Determine whether we should code this trigger */ if( p->op==op && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns,pChanges) ){ TriggerStack *pS; /* Pointer to trigger-stack entry */ for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext){} if( !pS ){ fire_this = 1; } #if 0 /* Give no warning for recursive triggers. Just do not do them */ |
︙ | ︙ |