Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | More fixes for test cases. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
85d9f23be1e8673dbda42e43b9b23332 |
User & Date: | dan 2009-08-31 15:27:28.000 |
Context
2009-09-01
| ||
12:16 | More fixes and comment updates. (check-in: 38a9327bad user: dan tags: trunk) | |
2009-08-31
| ||
15:27 | More fixes for test cases. (check-in: 85d9f23be1 user: dan tags: trunk) | |
08:22 | Fix some authorization callback problems. (check-in: 8a746fbfd5 user: dan tags: trunk) | |
Changes
Changes to src/delete.c.
︙ | ︙ | |||
387 388 389 390 391 392 393 | addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid); /* If there are triggers, populate an array of registers with the ** data required by the old.* references in the trigger bodies. */ if( pTrigger ){ u32 mask = 0; /* Mask of OLD.* columns in use */ | < | | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid); /* If there are triggers, populate an array of registers with the ** data required by the old.* references in the trigger bodies. */ if( pTrigger ){ u32 mask = 0; /* Mask of OLD.* columns in use */ pParse->nMem += pTab->nCol; /* Open the pseudo-table used to store OLD if there are triggers. */ mask = sqlite3TriggerOldmask( pParse, pTrigger, TK_DELETE, 0, pTab, OE_Default); /* If the record is no longer present in the table, jump to the ** next iteration of the loop through the contents of the fifo. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid); /* Populate the OLD.* pseudo-table */ |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
2555 2556 2557 2558 2559 2560 2561 | } case TK_UPLUS: { inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); break; } case TK_TRIGGER: { | > | > > > > > | 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 | } case TK_UPLUS: { inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); break; } case TK_TRIGGER: { Table *pTab = pExpr->pTab; int iVal = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn; sqlite3VdbeAddOp2(v, OP_Param, iVal, target); VdbeComment((v, "%s.%s -> $%d", (pExpr->iTable ? "new" : "old"), (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName), target )); if( pExpr->iColumn>=0 && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } break; } /* ** Form A: ** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
975 976 977 978 979 980 981 | #endif { int isReplace; /* Set to true if constraints may cause a replace */ sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx, keyColumn>=0, 0, onError, endOfLoop, &isReplace ); sqlite3CompleteInsertion( | | < | 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 | #endif { int isReplace; /* Set to true if constraints may cause a replace */ sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx, keyColumn>=0, 0, onError, endOfLoop, &isReplace ); sqlite3CompleteInsertion( pParse, pTab, baseCur, regIns, aRegIdx, 0, appendFlag, isReplace==0 ); } } /* Update the count of rows that are inserted */ if( (db->flags & SQLITE_CountRows)!=0 ){ |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 | void sqlite3CompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int baseCur, /* Index of a read/write cursor pointing at pTab */ int regRowid, /* Range of content */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ int isUpdate, /* True for UPDATE, False for INSERT */ | < | 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 | void sqlite3CompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int baseCur, /* Index of a read/write cursor pointing at pTab */ int regRowid, /* Range of content */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ int isUpdate, /* True for UPDATE, False for INSERT */ int appendBias, /* True if this is likely to be an append */ int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */ ){ int i; Vdbe *v; int nIdx; Index *pIdx; |
︙ | ︙ |
Changes to src/prepare.c.
︙ | ︙ | |||
672 673 674 675 676 677 678 | if( zErrMsg ){ sqlite3Error(db, rc, "%s", zErrMsg); sqlite3DbFree(db, zErrMsg); }else{ sqlite3Error(db, rc, 0); } | | | | | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 | if( zErrMsg ){ sqlite3Error(db, rc, "%s", zErrMsg); sqlite3DbFree(db, zErrMsg); }else{ sqlite3Error(db, rc, 0); } while( pParse->pTriggerPrg ){ TriggerPrg *pT = pParse->pTriggerPrg; pParse->pTriggerPrg = pT->pNext; sqlite3VdbeProgramDelete(db, pT->pProgram, 0); sqlite3DbFree(db, pT); } end_prepare: sqlite3StackFree(db, pParse); |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
221 222 223 224 225 226 227 | #ifndef SQLITE_OMIT_TRIGGER /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference */ if( zDb==0 && zTab!=0 && cnt==0 && pParse->pTriggerTab!=0 ){ Table *pTab = 0; | < < < < < < < < < < > > > > | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | #ifndef SQLITE_OMIT_TRIGGER /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference */ if( zDb==0 && zTab!=0 && cnt==0 && pParse->pTriggerTab!=0 ){ Table *pTab = 0; if( pParse->triggerOp!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){ pExpr->iTable = 1; pTab = pParse->pTriggerTab; }else if( pParse->triggerOp!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){ pExpr->iTable = 0; pTab = pParse->pTriggerTab; } if( pTab ){ int iCol; pSchema = pTab->pSchema; cntTab++; if( sqlite3IsRowid(zCol) ){ iCol = -1; }else{ for(iCol=0; iCol<pTab->nCol; iCol++){ Column *pCol = &pTab->aCol[iCol]; if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ if( iCol==pTab->iPKey ){ iCol = -1; } break; } } } if( iCol<pTab->nCol ){ cnt++; if( iCol<0 ){ pExpr->affinity = SQLITE_AFF_INTEGER; }else if( pExpr->iTable==0 ){ testcase( iCol==31 ); testcase( iCol==32 ); pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol)); } pExpr->iColumn = iCol; pExpr->pTab = pTab; isTrigger = 1; } } } |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
607 608 609 610 611 612 613 | typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SrcList SrcList; typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; | | | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SrcList SrcList; typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; typedef struct Trigger Trigger; typedef struct UnpackedRecord UnpackedRecord; typedef struct VTable VTable; typedef struct Walker Walker; typedef struct WherePlan WherePlan; typedef struct WhereInfo WhereInfo; |
︙ | ︙ | |||
1573 1574 1575 1576 1577 1578 1579 | /* If the EP_Reduced flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to ** access them will result in a segfault or malfunction. *********************************************************************/ int iTable; /* TK_COLUMN: cursor number of table holding column | | > | 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 | /* If the EP_Reduced flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to ** access them will result in a segfault or malfunction. *********************************************************************/ int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old */ i16 iColumn; /* TK_COLUMN: column index. -1 for rowid */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ u8 flags2; /* Second set of flags. EP2_... */ u8 op2; /* If a TK_REGISTER, the original value of Expr.op */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ Table *pTab; /* Table for TK_COLUMN expressions. */ |
︙ | ︙ | |||
2012 2013 2014 2015 2016 2017 2018 | /* ** Size of the column cache */ #ifndef SQLITE_N_COLCACHE # define SQLITE_N_COLCACHE 10 #endif | > > > > > > > > > > > | > | > > | < < < | | 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 | /* ** Size of the column cache */ #ifndef SQLITE_N_COLCACHE # define SQLITE_N_COLCACHE 10 #endif /* ** At least one instance of the following structure is created for each ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE ** statement. All such objects are stored in the linked list headed at ** Parse.pTriggerPrg and deleted once statement compilation has been ** completed. ** ** A Vdbe sub-program that implements the body and WHEN clause of trigger ** TriggerPrg.pTrigger, assuming a default ON CONFLICT clause of ** TriggerPrg.orconf, is stored in the TriggerPrg.pProgram variable. ** The Parse.pTriggerPrg list never contains two entries with the same ** values for both pTrigger and orconf. */ struct TriggerPrg { Trigger *pTrigger; /* Trigger this program was coded from */ int orconf; /* Default ON CONFLICT policy */ SubProgram *pProgram; /* Program implementing pTrigger/orconf */ u32 oldmask; /* Mask of old.* columns accessed */ TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */ }; /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to ** carry around information that is global to the entire parse. ** |
︙ | ︙ | |||
2108 2109 2110 2111 2112 2113 2114 | int *aAlias; /* Register used to hold aliased result */ u8 explain; /* True if the EXPLAIN flag is found on the query */ Token sNameToken; /* Token with unqualified schema object name */ Token sLastToken; /* The last token parsed */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ | < < < | | 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 | int *aAlias; /* Register used to hold aliased result */ u8 explain; /* True if the EXPLAIN flag is found on the query */ Token sNameToken; /* Token with unqualified schema object name */ Token sLastToken; /* The last token parsed */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE Token sArg; /* Complete text of a module argument */ u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ int nVtabLock; /* Number of virtual tables to lock */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif int nHeight; /* Expression tree height of current sub-select */ Table *pZombieTab; /* List of Table objects to delete after code gen */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ }; #ifdef SQLITE_OMIT_VIRTUALTABLE #define IN_DECLARE_VTAB 0 #else #define IN_DECLARE_VTAB (pParse->declareVtab) #endif |
︙ | ︙ | |||
2237 2238 2239 2240 2241 2242 2243 | Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE. VALUES clause for INSERT */ IdList *pIdList; /* Column names for INSERT */ TriggerStep *pNext; /* Next in the link-list */ TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ }; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 | Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE. VALUES clause for INSERT */ IdList *pIdList; /* Column names for INSERT */ TriggerStep *pNext; /* Next in the link-list */ TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ }; /* ** The following structure contains information used by the sqliteFix... ** routines as they walk the parse tree to make database references ** explicit. */ typedef struct DbFixer DbFixer; struct DbFixer { |
︙ | ︙ | |||
2670 2671 2672 2673 2674 2675 2676 | int sqlite3ExprIsInteger(Expr*, int*); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int, int*,int,int,int,int,int*); | | | 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 | int sqlite3ExprIsInteger(Expr*, int*); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int, int*,int,int,int,int,int*); void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int); int sqlite3OpenTableAndIndices(Parse*, Table*, int, int); void sqlite3BeginWriteOperation(Parse*, int, int); Expr *sqlite3ExprDup(sqlite3*,Expr*,int); ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); IdList *sqlite3IdListDup(sqlite3*,IdList*); Select *sqlite3SelectDup(sqlite3*,Select*,int); |
︙ | ︙ | |||
2717 2718 2719 2720 2721 2722 2723 | TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*); TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*, ExprList*,Select*,u8); TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8); TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*); void sqlite3DeleteTrigger(sqlite3*, Trigger*); void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); | | | 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 | TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*); TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*, ExprList*,Select*,u8); TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8); TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*); void sqlite3DeleteTrigger(sqlite3*, Trigger*); void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); u32 sqlite3TriggerOldmask(Parse*,Trigger*,int,ExprList*,Table*,int); #else # define sqlite3TriggersExist(B,C,D,E,F) 0 # define sqlite3DeleteTrigger(A,B) # define sqlite3DropTriggerPtr(A,B) # define sqlite3UnlinkAndDeleteTrigger(A,B,C) # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J) # define sqlite3TriggerList(X, Y) 0 |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
677 678 679 680 681 682 683 | TriggerStep * pStep = pStepList; Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; assert( pParse->pRoot ); assert( pStep!=0 ); assert( v!=0 ); | < < < < < | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 | TriggerStep * pStep = pStepList; Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; assert( pParse->pRoot ); assert( pStep!=0 ); assert( v!=0 ); while( pStep ){ /* 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->orconf = (orconfin==OE_Default)?pStep->orconf:orconfin; switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, targetSrcList(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), pParse->orconf |
︙ | ︙ | |||
739 740 741 742 743 744 745 | } } if( pStep->op!=TK_SELECT ){ sqlite3VdbeAddOp1(v, OP_ResetCount, 1); } pStep = pStep->pNext; } | < | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | } } if( pStep->op!=TK_SELECT ){ sqlite3VdbeAddOp1(v, OP_ResetCount, 1); } pStep = pStep->pNext; } return 0; } #ifdef SQLITE_DEBUG /* ** This function is used to add VdbeComment() annotations to a VDBE |
︙ | ︙ | |||
778 779 780 781 782 783 784 | pTo->zErrMsg = pFrom->zErrMsg; pTo->nErr = pFrom->nErr; }else{ sqlite3DbFree(pFrom->db, pFrom->zErrMsg); } } | | | < | | | | | | | | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 | pTo->zErrMsg = pFrom->zErrMsg; pTo->nErr = pFrom->nErr; }else{ sqlite3DbFree(pFrom->db, pFrom->zErrMsg); } } static TriggerPrg *codeRowTrigger( Parse *pRoot, /* Root parse context */ Parse *pParse, /* Current parse context */ Trigger *pTrigger, /* Trigger to code */ int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ Table *pTab, /* The table to code triggers from */ int orconf ){ sqlite3 *db = pParse->db; TriggerPrg *pPrg; Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ Vdbe *v; /* Temporary VM */ NameContext sNC; /* Name context for sub-vdbe */ SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ Parse *pSubParse; /* Parse context for sub-vdbe */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg)); if( !pPrg ) return 0; pPrg->pNext = pRoot->pTriggerPrg; pRoot->pTriggerPrg = pPrg; pPrg->pProgram = pProgram = sqlite3DbMallocZero(db, sizeof(SubProgram)); if( !pProgram ) return 0; pProgram->nRef = 1; pSubParse = sqlite3StackAllocZero(db, sizeof(Parse)); if( !pSubParse ) return 0; pPrg->pProgram = pProgram; pPrg->pTrigger = pTrigger; pPrg->orconf = orconf; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pSubParse; pSubParse->db = db; pSubParse->pTriggerTab = pTab; pSubParse->pRoot = pRoot; pSubParse->zAuthContext = pTrigger->zName; |
︙ | ︙ | |||
861 862 863 864 865 866 867 | transferParseError(pParse, pSubParse); if( db->mallocFailed==0 ){ pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pParse->nArg); } pProgram->nMem = pSubParse->nMem; pProgram->nCsr = pSubParse->nTab; pProgram->token = (void *)pTrigger; | | < | | | | | | | | | | | | 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 | transferParseError(pParse, pSubParse); if( db->mallocFailed==0 ){ pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pParse->nArg); } pProgram->nMem = pSubParse->nMem; pProgram->nCsr = pSubParse->nTab; pProgram->token = (void *)pTrigger; pPrg->oldmask = pSubParse->oldmask; sqlite3VdbeDelete(v); while( pSubParse->pAinc ){ AutoincInfo *p = pSubParse->pAinc; pSubParse->pAinc = p->pNext; sqlite3DbFree(db, p); } } sqlite3StackFree(db, pSubParse); return pPrg; } static TriggerPrg *getRowTrigger( Parse *pParse, Trigger *pTrigger, /* Trigger to code */ int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ Table *pTab, /* The table to code triggers from */ int orconf ){ TriggerPrg *pPrg; Parse *pRoot = pParse; /* 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 ** a matching TriggerPrg.pTrigger field will be present somewhere ** in the Parse.pTriggerPrg list. Search for such an entry. */ if( pParse->pRoot ){ pRoot = pParse->pRoot; } for(pPrg=pRoot->pTriggerPrg; pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); pPrg=pPrg->pNext ); if( !pPrg ){ pPrg = codeRowTrigger(pRoot, pParse, pTrigger, op, pTab, orconf); } return pPrg; } /* ** This is called to code FOR EACH ROW triggers. ** ** When the code that this function generates is executed, the following ** must be true: |
︙ | ︙ | |||
965 966 967 968 969 970 971 | /* Determine whether we should code this trigger */ if( p->op==op && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns,pChanges) ){ Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ | | | | | | | > > > > > > > > > > > > > > > > > > > | | | < < > < > | | | | < | > | > | 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 | /* Determine whether we should code this trigger */ if( p->op==op && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns,pChanges) ){ Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, op, 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))); } } } } /* ** Triggers fired by UPDATE or DELETE statements may access values stored ** in the old.* pseudo-table. This function returns a 32-bit bitmask ** indicating which columns of the old.* table actually are used by ** triggers. This information may be used by the caller to avoid having ** to load the entire old.* record into memory when executing an UPDATE ** or DELETE command. ** ** Bit 0 of the returned mask is set if the left-most column of the ** table may be accessed using an old.<col> reference. Bit 1 is set if ** the second leftmost column value is required, and so on. If there ** are more than 32 columns in the table, and at least one of the columns ** with an index greater than 32 may be accessed, 0xffffffff is returned. ** ** It is not possible to determine if the old.rowid column is accessed ** by triggers. The caller must always assume that it is. ** ** There is no equivalent function for new.* references. */ 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 */ ){ 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; pPrg = getRowTrigger(pParse, p, op, pTab, orconf); if( pPrg ){ mask |= pPrg->oldmask; } } } return mask; } #endif /* !defined(SQLITE_OMIT_TRIGGER) */ |
Changes to src/update.c.
︙ | ︙ | |||
116 117 118 119 120 121 122 | int j1; /* Addresses of jump instructions */ int okOnePass; /* True for one-pass algorithm without the FIFO */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* Trying to update a view */ Trigger *pTrigger; /* List of triggers on pTab, if required */ #endif | | < | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | int j1; /* Addresses of jump instructions */ int okOnePass; /* True for one-pass algorithm without the FIFO */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* Trying to update a view */ Trigger *pTrigger; /* List of triggers on pTab, if required */ #endif u32 oldmask = 0; /* Mask of OLD.* columns in use */ /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ int regOldRowid; /* The old rowid */ int regNewRowid; /* The new rowid */ int regNew; int regOld; |
︙ | ︙ | |||
286 287 288 289 290 291 292 | regRec = ++pParse->nMem; /* Start the view context. */ if( isView ){ sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } | | | | < | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | regRec = ++pParse->nMem; /* Start the view context. */ if( isView ){ sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* If there are any triggers, set oldmask and new_col_mask. */ oldmask = sqlite3TriggerOldmask( pParse, pTrigger, TK_UPDATE, pChanges, pTab, onError); /* If we are trying to update a view, realize that view into ** a ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ sqlite3MaterializeView(pParse, pTab, pWhere, iCur); |
︙ | ︙ | |||
380 381 382 383 384 385 386 | ** for example, then jump to the next iteration of the RowSet loop. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); /* If there are triggers on this table, populate an array of registers ** with the required old.* column data. */ if( pTrigger ){ for(i=0; i<pTab->nCol; i++){ | | | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | ** for example, then jump to the next iteration of the RowSet loop. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); /* If there are triggers on this table, populate an array of registers ** with the required old.* column data. */ if( pTrigger ){ for(i=0; i<pTab->nCol; i++){ if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i); sqlite3ColumnDefault(v, pTab, i, regOld+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); } } } |
︙ | ︙ | |||
419 420 421 422 423 424 425 | sqlite3ColumnDefault(v, pTab, i, regNew+i); }else{ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); } } } | < < < < < < < < < < < < < > > > | | > | < < < < < < < < < < < < < | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | sqlite3ColumnDefault(v, pTab, i, regNew+i); }else{ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); } } } /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ if( pTrigger ){ sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol); sqlite3TableAffinityStr(v, pTab); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, -1, regOldRowid, onError, addr); } if( !isView ){ /* Do constraint checks. */ sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid, aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0); /* Delete the index entries associated with the current record. */ j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid); sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx); /* If changing the record number, delete the old record. */ if( chngRowid ){ sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0); } sqlite3VdbeJumpHere(v, j1); /* Insert the new index entries and the new record. */ sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, 0, 0); } /* Increment the row counter */ if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 | ** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { if( pOp->p1==SQLITE_OK && p->pFrame ){ VdbeFrame *pFrame = p->pFrame; p->pFrame = pFrame->pParent; p->nFrame--; pc = sqlite3VdbeFrameRestore(pFrame); if( pOp->p2==OE_Ignore ){ pc = p->aOp[pc].p2-1; } break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pc; if( pOp->p4.z ){ sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z); } rc = sqlite3VdbeHalt(p); | > > > > > > > > | 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 | ** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { if( pOp->p1==SQLITE_OK && p->pFrame ){ /* Halt the sub-program. Return control to the parent frame. */ VdbeFrame *pFrame = p->pFrame; p->pFrame = pFrame->pParent; p->nFrame--; sqlite3VdbeSetChanges(db, p->nChange); pc = sqlite3VdbeFrameRestore(pFrame); if( pOp->p2==OE_Ignore ){ /* Instruction pc is the OP_Program that invoked the sub-program ** currently being halted. If the p2 instruction of this OP_Halt ** instruction is set to OE_Ignore, then the sub-program is throwing ** an IGNORE exception. In this case jump to the address specified ** as the p2 of the calling OP_Program. */ pc = p->aOp[pc].p2-1; } break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pc; if( pOp->p4.z ){ sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z); } rc = sqlite3VdbeHalt(p); |
︙ | ︙ | |||
4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 | assert( pc==pFrame->pc ); } p->nFrame++; pFrame->pParent = p->pFrame; pFrame->lastRowid = db->lastRowid; pFrame->nChange = p->nChange; p->pFrame = pFrame; p->aMem = &VdbeFrameMem(pFrame)[-1]; p->nMem = pFrame->nChildMem; p->nCursor = pFrame->nChildCsr; p->apCsr = (VdbeCursor **)&p->aMem[p->nMem+1]; p->aOp = pProgram->aOp; p->nOp = pProgram->nOp; | > | 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 | assert( pc==pFrame->pc ); } p->nFrame++; pFrame->pParent = p->pFrame; pFrame->lastRowid = db->lastRowid; pFrame->nChange = p->nChange; p->nChange = 0; p->pFrame = pFrame; p->aMem = &VdbeFrameMem(pFrame)[-1]; p->nMem = pFrame->nChildMem; p->nCursor = pFrame->nChildCsr; p->apCsr = (VdbeCursor **)&p->aMem[p->nMem+1]; p->aOp = pProgram->aOp; p->nOp = pProgram->nOp; |
︙ | ︙ |
Changes to test/tkt3992.test.
︙ | ︙ | |||
25 26 27 28 29 30 31 | CREATE TABLE parameters2( mountcnt INT NOT NULL CHECK (typeof(mountcnt) == 'integer'), version REAL CHECK (typeof(version) == 'real') ); INSERT INTO parameters2(mountcnt, version) VALUES(1, 1.0); } } {} | < < < < < | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | CREATE TABLE parameters2( mountcnt INT NOT NULL CHECK (typeof(mountcnt) == 'integer'), version REAL CHECK (typeof(version) == 'real') ); INSERT INTO parameters2(mountcnt, version) VALUES(1, 1.0); } } {} do_test tkt3992-1.2 { execsql { UPDATE parameters1 SET mountcnt = mountcnt + 1; SELECT * FROM parameters1; } } {2 1.0} do_test tkt3992-1.3 { execsql { UPDATE parameters2 SET mountcnt = mountcnt + 1; SELECT * FROM parameters2; } } {2 1.0} do_test tkt3992-2.1 { execsql { CREATE TABLE t1(a, b); |
︙ | ︙ |