Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fixes for new triggers scheme. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
9eb91efda5241609ff18ff15ef5eaa0e |
User & Date: | dan 2009-08-30 11:42:52.000 |
Context
2009-08-31
| ||
05:23 | Fix another test problem and some instances where an OOM may cause a segfault. (check-in: 31199db0f7 user: dan tags: trunk) | |
2009-08-30
| ||
11:42 | Fixes for new triggers scheme. (check-in: 9eb91efda5 user: dan tags: trunk) | |
2009-08-28
| ||
18:53 | Changes to support recursive triggers. (check-in: 9b9c192115 user: dan tags: trunk) | |
Changes
Changes to src/delete.c.
︙ | ︙ | |||
404 405 406 407 408 409 410 411 412 413 414 | sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid); /* Populate the OLD.* pseudo-table */ assert( regOld==iRowid+1 ); for(i=0; i<pTab->nCol; i++){ if( mask==0xffffffff || mask&(1<<i) ){ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i); } } sqlite3CodeRowTrigger(pParse, pTrigger, | > > > | | | 404 405 406 407 408 409 410 411 412 413 414 415 416 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 | sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid); /* Populate the OLD.* pseudo-table */ assert( regOld==iRowid+1 ); for(i=0; i<pTab->nCol; i++){ if( mask==0xffffffff || mask&(1<<i) ){ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i); sqlite3ColumnDefault(v, pTab, i, regOld+i); } } sqlite3VdbeAddOp2(v, OP_Affinity, regOld, pTab->nCol); sqlite3TableAffinityStr(v, pTab); sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, iRowid, OE_Default, addr ); } if( !isView ){ /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB); }else #endif { sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0); } } /* Code the AFTER triggers. This is a no-op if there are no triggers. */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, iRowid, OE_Default, addr ); /* End of the delete loop */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); sqlite3VdbeResolveLabel(v, end); /* Close the cursors open on the table and its indexes. */ |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
86 87 88 89 90 91 92 | CollSeq *pColl = 0; Expr *p = pExpr; while( ALWAYS(p) ){ int op; pColl = p->pColl; if( pColl ) break; op = p->op; | > | > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | CollSeq *pColl = 0; Expr *p = pExpr; while( ALWAYS(p) ){ int op; pColl = p->pColl; if( pColl ) break; op = p->op; if( p->pTab!=0 && ( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER )){ /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally ** a TK_COLUMN but was previously evaluated and cached in a register */ const char *zColl; int j = p->iColumn; if( j>=0 ){ sqlite3 *db = pParse->db; zColl = p->pTab->aCol[j].zColl; |
︙ | ︙ | |||
2553 2554 2555 2556 2557 2558 2559 | } 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 | } case TK_UPLUS: { inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); break; } case TK_TRIGGER: { int iVal = pExpr->iTable * (pExpr->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 )); break; } /* ** Form A: |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 | static int autoIncBegin( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ if( pTab->tabFlags & TF_Autoincrement ){ AutoincInfo *pInfo; | > | | | | | | > > > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | static int autoIncBegin( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ if( pTab->tabFlags & TF_Autoincrement ){ Parse *pRoot = (pParse->pRoot ? pParse->pRoot : pParse); AutoincInfo *pInfo; pInfo = pRoot->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo)); if( pInfo==0 ) return 0; pInfo->pNext = pRoot->pAinc; pRoot->pAinc = pInfo; pInfo->pTab = pTab; pInfo->iDb = iDb; pRoot->nMem++; /* Register to hold name of table */ pInfo->regCtr = ++pRoot->nMem; /* Max rowid register */ pRoot->nMem++; /* Rowid in sqlite_sequence */ } memId = pInfo->regCtr; } return memId; } /* ** This routine generates code that will initialize all of the ** register used by the autoincrement tracker. */ void sqlite3AutoincrementBegin(Parse *pParse){ AutoincInfo *p; /* Information about an AUTOINCREMENT */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* Database only autoinc table */ int memId; /* Register holding max rowid */ int addr; /* A VDBE address */ Vdbe *v = pParse->pVdbe; /* VDBE under construction */ /* If currently generating a trigger program, this call is a no-op */ if( pParse->pTriggerTab ) return; assert( v ); /* We failed long ago if this is not so */ for(p = pParse->pAinc; p; p = p->pNext){ pDb = &db->aDb[p->iDb]; memId = p->regCtr; sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); addr = sqlite3VdbeCurrentAddr(v); |
︙ | ︙ | |||
801 802 803 804 805 806 807 | } regData = regRowid+1; /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(v); if( tmask & TRIGGER_BEFORE ){ | < | < | | | | | | < | | | | | < | | 805 806 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 833 834 835 836 837 838 839 840 841 842 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 874 875 876 877 878 879 880 881 882 | } regData = regRowid+1; /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(v); if( tmask & TRIGGER_BEFORE ){ int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1); /* build the NEW.* reference row. Note that if there is an INTEGER ** PRIMARY KEY into which a NULL is being inserted, that NULL will be ** translated into a unique ID for the row. But on a BEFORE trigger, ** we do not know what the unique ID will be (because the insert has ** not happened yet) so we substitute a rowid of -1 */ if( keyColumn<0 ){ sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); }else{ int j1; if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regCols); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regCols); } j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); } /* Cannot have triggers on a virtual table. If it were possible, ** this block would have to account for hidden column. */ assert( !IsVirtual(pTab) ); /* Create the new column data */ for(i=0; i<pTab->nCol; i++){ if( pColumn==0 ){ j = i; }else{ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==i ) break; } } if( pColumn && j>=pColumn->nId ){ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1); } } /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. ** If this is a real table, attempt conversions as required by the ** table column affinities. */ if( !isView ){ sqlite3VdbeAddOp2(v, OP_Affinity, regCols+1, pTab->nCol); sqlite3TableAffinityStr(v, pTab); } /* Fire BEFORE or INSTEAD OF triggers */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, pTab, -1, regCols-pTab->nCol-1, onError, endOfLoop); sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1); } /* Push the record number for the new entry onto the stack. The ** record number is a randomly generate integer created by NewRowid ** except when the table has an INTEGER PRIMARY KEY column, in which ** case the record number is the same as that column. */ |
︙ | ︙ | |||
990 991 992 993 994 995 996 | if( (db->flags & SQLITE_CountRows)!=0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } if( pTrigger ){ /* Code AFTER triggers */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, | | | 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 | if( (db->flags & SQLITE_CountRows)!=0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } if( pTrigger ){ /* Code AFTER triggers */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, pTab, -1, regData-2-pTab->nCol, onError, endOfLoop); } /* The bottom of the main insertion loop, if the data source ** is a SELECT statement. */ sqlite3VdbeResolveLabel(v, endOfLoop); if( useTempTable ){ |
︙ | ︙ | |||
1149 1150 1151 1152 1153 1154 1155 | v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; regData = regRowid + 1; | < | 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 | v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; regData = regRowid + 1; /* Test all NOT NULL constraints. */ for(i=0; i<nCol; i++){ if( i==pTab->iPKey ){ continue; } onError = pTab->aCol[i].notNull; |
︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 | onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError!=OE_Replace || pTab->pIndex ){ if( isUpdate ){ | | | 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError!=OE_Replace || pTab->pIndex ){ if( isUpdate ){ j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, rowidChng); } j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 | db->nextPagesize = 0; db->flags |= SQLITE_ShortColNames #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION | SQLITE_LoadExtension #endif ; sqlite3HashInit(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3HashInit(&db->aModule); #endif | > > > | 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 | db->nextPagesize = 0; db->flags |= SQLITE_ShortColNames #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION | SQLITE_LoadExtension #endif #ifdef SQLITE_DISABLE_RECURSIVE_TRIGGERS | SQLITE_NoRecTriggers #endif ; sqlite3HashInit(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3HashInit(&db->aModule); #endif |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
186 187 188 189 190 191 192 193 194 195 196 197 198 199 | /* The following is VERY experimental */ { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode }, { "omit_readlock", SQLITE_NoReadlock }, /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted ** flag if there are any active statements. */ { "read_uncommitted", SQLITE_ReadUncommitted }, }; int i; const struct sPragmaType *p; for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){ if( sqlite3StrICmp(zLeft, p->zName)==0 ){ sqlite3 *db = pParse->db; Vdbe *v; | > | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | /* The following is VERY experimental */ { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode }, { "omit_readlock", SQLITE_NoReadlock }, /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted ** flag if there are any active statements. */ { "read_uncommitted", SQLITE_ReadUncommitted }, { "disable_recursive_triggers", SQLITE_NoRecTriggers }, }; int i; const struct sPragmaType *p; for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){ if( sqlite3StrICmp(zLeft, p->zName)==0 ){ sqlite3 *db = pParse->db; Vdbe *v; |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
907 908 909 910 911 912 913 914 915 916 917 918 919 920 | #define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */ #define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ #define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */ #define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */ #define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */ #define SQLITE_ReverseOrder 0x00100000 /* Reverse unordered SELECTs */ /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. */ #define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ | > | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | #define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */ #define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ #define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */ #define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */ #define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */ #define SQLITE_ReverseOrder 0x00100000 /* Reverse unordered SELECTs */ #define SQLITE_NoRecTriggers 0x00200000 /* Disable recursive triggers */ /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. */ #define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
693 694 695 696 697 698 699 700 701 702 703 704 705 706 | ** 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), | > > > > | 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 | ** 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; if( pStep->op!=TK_SELECT ){ sqlite3VdbeAddOp1(v, OP_ResetCount, 0); } switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, targetSrcList(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), |
︙ | ︙ | |||
730 731 732 733 734 735 736 737 738 739 740 741 742 743 | Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0); sqlite3SelectDestInit(&sDest, SRT_Discard, 0); sqlite3Select(pParse, pSelect, &sDest); sqlite3SelectDelete(db, pSelect); break; } } pStep = pStep->pNext; } /* sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); */ return 0; } | > > > | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0); sqlite3SelectDestInit(&sDest, SRT_Discard, 0); sqlite3Select(pParse, pSelect, &sDest); sqlite3SelectDelete(db, pSelect); break; } } if( pStep->op!=TK_SELECT ){ sqlite3VdbeAddOp1(v, OP_ResetCount, 1); } pStep = pStep->pNext; } /* sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); */ return 0; } |
︙ | ︙ | |||
814 815 816 817 818 819 820 | pSubParse->pRoot = pRoot; /* Push an entry on to the auth context stack */ sqlite3AuthContextPush(pParse, &sContext, pTrigger->name); v = sqlite3GetVdbe(pSubParse); if( v ){ | > | | > > > > > | > > | 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 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 | pSubParse->pRoot = pRoot; /* Push an entry on to the auth context stack */ sqlite3AuthContextPush(pParse, &sContext, pTrigger->name); v = sqlite3GetVdbe(pSubParse); if( v ){ VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", pTrigger->zName, onErrorText(orconf), (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"), (op==TK_UPDATE ? "UPDATE" : ""), (op==TK_INSERT ? "INSERT" : ""), (op==TK_DELETE ? "DELETE" : ""), pTab->zName )); #ifndef SQLITE_OMIT_TRACE sqlite3VdbeChangeP4(v, -1, sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC ); #endif if( pTrigger->pWhen ){ /* Code the WHEN clause. If it evaluates to false (or NULL) the ** sub-vdbe is immediately halted. */ pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0); if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) ){ iEndTrigger = sqlite3VdbeMakeLabel(v); sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); } sqlite3ExprDelete(db, pWhen); } /* Code the trigger program into the sub-vdbe. */ codeTriggerProgram(pSubParse, pTrigger->step_list, orconf); if( iEndTrigger ){ sqlite3VdbeResolveLabel(v, iEndTrigger); } sqlite3VdbeAddOp0(v, OP_Halt); VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); transferParseError(pParse, pSubParse); pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pParse->nArg); pProgram->nMem = pSubParse->nMem; pProgram->nCsr = pSubParse->nTab; pProgram->token = (void *)pTrigger; pC->oldmask = pSubParse->oldmask; pC->newmask = pSubParse->newmask; |
︙ | ︙ | |||
957 958 959 960 961 962 963 | CodedTrigger *pC; pC = getRowTrigger(pParse, p, op, pTab, orconf); assert( pC || 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( pC ){ | | | | 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 | CodedTrigger *pC; pC = getRowTrigger(pParse, p, op, pTab, orconf); assert( pC || 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( pC ){ sqlite3VdbeAddOp3(v, OP_Program, oldIdx, ignoreJump, ++pParse->nMem); pC->pProgram->nRef++; sqlite3VdbeChangeP4(v, -1, (const char *)pC->pProgram, P4_SUBPROGRAM); VdbeComment((v, "Call: %s.%s", p->zName, onErrorText(orconf))); } } } } void sqlite3TriggerUses( Parse *pParse, /* Parse context */ |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ int regOldRowid; /* The old rowid */ int regNewRowid; /* The new rowid */ int regNew; int regOld; int regRowSet = 0; /* Rowset of rows to be updated */ memset(&sContext, 0, sizeof(sContext)); db = pParse->db; if( pParse->nErr || db->mallocFailed ){ goto update_cleanup; } assert( pTabList->nSrc==1 ); /* Locate the table which we want to update. */ pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ) goto update_cleanup; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); /* Figure out if we have any triggers and if the table being | > | | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ int regOldRowid; /* The old rowid */ int regNewRowid; /* The new rowid */ int regNew; int regOld; int regRowSet = 0; /* Rowset of rows to be updated */ int regRec; /* Register used for new table record to insert */ memset(&sContext, 0, sizeof(sContext)); db = pParse->db; if( pParse->nErr || db->mallocFailed ){ goto update_cleanup; } assert( pTabList->nSrc==1 ); /* Locate the table which we want to update. */ pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ) goto update_cleanup; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); /* Figure out if we have any triggers and if the table being ** updated is a view. */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, 0); isView = pTab->pSelect!=0; #else # define pTrigger 0 # define isView 0 |
︙ | ︙ | |||
278 279 280 281 282 283 284 285 286 287 288 289 290 291 | pParse->nMem += pTab->nCol; } if( chngRowid || pTrigger ){ regNewRowid = ++pParse->nMem; } regNew = pParse->nMem + 1; pParse->nMem += pTab->nCol; /* Start the view context. */ if( isView ){ sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* If there are any triggers, set old_col_mask and new_col_mask. */ | > | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | pParse->nMem += pTab->nCol; } if( chngRowid || pTrigger ){ regNewRowid = ++pParse->nMem; } regNew = pParse->nMem + 1; pParse->nMem += pTab->nCol; regRec = ++pParse->nMem; /* Start the view context. */ if( isView ){ sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* If there are any triggers, set old_col_mask and new_col_mask. */ |
︙ | ︙ | |||
416 417 418 419 420 421 422 423 424 425 426 | sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew+i); 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. */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, | > > > > > > > > > > > > > | | | | > > > > > > > > > > > > > | | 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 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew+i); sqlite3ColumnDefault(v, pTab, i, regNew+i); }else{ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); } } } /* If this is not a view, create the record that will be inserted into ** the table (assuming no constraint checks fail). A side effect of ** creating the record is applying affinity transformations to the ** array of registers populated by the block above. This needs to be ** done before the BEFORE triggers are fired. */ #if 0 if( !isView ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regNew, pTab->nCol, regRec); sqlite3TableAffinityStr(v, pTab); sqlite3ExprCacheAffinityChange(pParse, regNew, pTab->nCol); } #endif /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ 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, -1, 0, 0); #if 0 for(i=0; i<nIdx; i++){ if( aRegIdx[i] ){ sqlite3VdbeAddOp2(v, OP_IdxInsert, iCur+1+i, aRegIdx[i]); } } sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, regNewRowid); if( !pParse->nested ){ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC); sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_ISUPDATE); } #endif } /* Increment the row counter */ if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab, -1, regOldRowid, onError, addr); /* Repeat the above with the next record to be updated, until ** all record selected by the WHERE clause have been updated. */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); sqlite3VdbeJumpHere(v, addr); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
848 849 850 851 852 853 854 855 856 857 858 859 860 861 | 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 ){ } break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pc; if( pOp->p4.z ){ | > | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 | 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 ){ |
︙ | ︙ | |||
3542 3543 3544 3545 3546 3547 3548 | /* Opcode: NewRowid P1 P2 P3 * * ** ** Get a new integer record number (a.k.a "rowid") used as the key to a table. ** The record number is not previously used as a key in the database ** table that cursor P1 points to. The new record number is written ** written to register P2. ** | | | | | | > | 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 | /* Opcode: NewRowid P1 P2 P3 * * ** ** Get a new integer record number (a.k.a "rowid") used as the key to a table. ** The record number is not previously used as a key in the database ** table that cursor P1 points to. The new record number is written ** written to register P2. ** ** If P3>0 then P3 is a register in the root frame of this VDBE that holds ** the largest previously generated record number. No new record numbers are ** allowed to be less than this value. When this value reaches its maximum, ** a SQLITE_FULL error is generated. The P3 register is updated with the ' ** generated record number. This P3 mechanism is used to help implement the ** AUTOINCREMENT feature. */ case OP_NewRowid: { /* out2-prerelease */ i64 v; /* The new rowid */ VdbeCursor *pC; /* Cursor of table to get the new rowid */ int res; /* Result of an sqlite3BtreeLast() */ int cnt; /* Counter to limit the number of searches */ Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */ VdbeFrame *pFrame; /* Root frame of VDBE */ v = 0; res = 0; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); if( NEVER(pC->pCursor==0) ){ |
︙ | ︙ | |||
3613 3614 3615 3616 3617 3618 3619 | v++; } } } #ifndef SQLITE_OMIT_AUTOINCREMENT if( pOp->p3 ){ | > > | > | > > > > | | 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 | v++; } } } #ifndef SQLITE_OMIT_AUTOINCREMENT if( pOp->p3 ){ if( p->pFrame ){ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); pMem = &pFrame->aMem[pOp->p3]; }else{ pMem = &p->aMem[pOp->p3]; } /* Assert that P3 is a valid memory cell. */ assert( pOp->p3>0 && pOp->p3<=(p->pFrame ? pFrame->nMem : p->nMem) ); REGISTER_TRACE(pOp->p3, pMem); sqlite3VdbeMemIntegerify(pMem); assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ rc = SQLITE_FULL; goto abort_due_to_error; } if( v<pMem->u.i+1 ){ |
︙ | ︙ | |||
4736 4737 4738 4739 4740 4741 4742 | sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); } break; } #ifndef SQLITE_OMIT_TRIGGER | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | < | > | | < < < | | < | | | > | | 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 | sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); } break; } #ifndef SQLITE_OMIT_TRIGGER /* Opcode: Program P1 P2 P3 P4 * ** ** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). ** ** P1 contains the address of the memory cell that contains the first memory ** cell in an array of values used as arguments to the sub-program. P2 ** contains the address to jump to if the sub-program throws an IGNORE ** exception using the RAISE() function. Register P3 contains the address ** of a memory cell in this (the parent) VM that is used to allocate the ** memory required by the sub-vdbe at runtime. ** ** P4 is a pointer to the VM containing the trigger program. */ case OP_Program: { /* jump */ VdbeFrame *pFrame; SubProgram *pProgram = pOp->p4.pProgram; Mem *pRt = &p->aMem[pOp->p3]; /* Register to allocate runtime space */ assert( pProgram->nOp>0 ); /* If the SQLITE_NoRecTriggers flag it set, then recursive invocation of ** triggers is disabled for backwards compatibility (flag set/cleared by ** the "PRAGMA disable_recursive_triggers" command). ** ** It is recursive invocation of triggers, at the SQL level, that is ** disabled. In some cases a single trigger may generate more than one ** SubProgram (if the trigger may be executed with more than one different ** ON CONFLICT algorithm). SubProgram structures associated with a ** single trigger all have the same value for the SubProgram.token ** variable. */ if( db->flags&SQLITE_NoRecTriggers ){ void *t = pProgram->token; for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent); if( pFrame ) break; } /* TODO: This constant should be configurable. */ if( p->nFrame>1000 ){ |
︙ | ︙ | |||
4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 | assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem ); assert( pProgram->nCsr==pFrame->nChildCsr ); assert( pc==pFrame->pc ); } p->nFrame++; pFrame->pParent = p->pFrame; 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; pc = -1; break; } | > > | > | > | | < < | < < | | | | | < < < > > | | | > > > > > > > > | 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 | assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem ); assert( pProgram->nCsr==pFrame->nChildCsr ); 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; pc = -1; break; } /* Opcode: Param P1 P2 * * * ** ** This opcode is only ever present in sub-programs called via the ** OP_Program instruction. Copy a value currently stored in a memory ** cell of the calling (parent) frame to cell P2 in the current frames ** address space. This is used by trigger programs to access the new.* ** and old.* values. ** ** The address of the cell in the parent frame is determined by adding ** the value of the P1 argument to the value of the P1 argument to the ** calling OP_Program instruction. */ case OP_Param: { /* out2-prerelease */ VdbeFrame *pFrame = p->pFrame; Mem *pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1]; sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem); break; } #endif /* #ifndef SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_AUTOINCREMENT /* Opcode: MemMax P1 P2 * * * ** ** P1 is a register in the root frame of this VM (the root frame is ** different from the current frame if this instruction is being executed ** within a sub-program). Set the value of register P1 to the maximum of ** its current value and the value in register P2. ** ** This instruction throws an error if the memory cell is not initially ** an integer. */ case OP_MemMax: { /* in2 */ Mem *pIn1; VdbeFrame *pFrame; if( p->pFrame ){ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); pIn1 = &pFrame->aMem[pOp->p1]; }else{ pIn1 = &p->aMem[pOp->p1]; } sqlite3VdbeMemIntegerify(pIn1); sqlite3VdbeMemIntegerify(pIn2); if( pIn1->u.i<pIn2->u.i){ pIn1->u.i = pIn2->u.i; } break; } |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
99 100 101 102 103 104 105 106 107 108 109 110 111 112 | int nMem; /* Number of entries in aMem */ VdbeCursor **apCsr; /* Element of Vdbe cursors */ u16 nCursor; /* Number of entries in apCsr */ VdbeFrame *pParent; /* Parent of this frame */ void *token; /* Copy of SubProgram.token */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ }; #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* ** A value for VdbeCursor.cacheValid that means the cache is always invalid. */ | > > | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | int nMem; /* Number of entries in aMem */ VdbeCursor **apCsr; /* Element of Vdbe cursors */ u16 nCursor; /* Number of entries in apCsr */ VdbeFrame *pParent; /* Parent of this frame */ void *token; /* Copy of SubProgram.token */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ int nChange; /* Statement changes (Vdbe.nChanges) */ }; #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* ** A value for VdbeCursor.cacheValid that means the cache is always invalid. */ |
︙ | ︙ | |||
239 240 241 242 243 244 245 | */ typedef struct Set Set; struct Set { Hash hash; /* A set is just a hash table */ HashElem *prev; /* Previously accessed hash elemen */ }; | < < < < < < < < < < < < < < < | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | */ typedef struct Set Set; struct Set { Hash hash; /* A set is just a hash table */ HashElem *prev; /* Previously accessed hash elemen */ }; /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile() ** is really a pointer to an instance of this structure. ** |
︙ | ︙ | |||
293 294 295 296 297 298 299 | u16 nVar; /* Number of entries in aVar[] */ Mem *aVar; /* Values for the OP_Variable opcode. */ char **azVar; /* Name of variables */ u32 magic; /* Magic number for sanity checking */ int nMem; /* Number of memory locations currently allocated */ Mem *aMem; /* The memory locations */ int cacheCtr; /* VdbeCursor row cache generation counter */ | < < < | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | u16 nVar; /* Number of entries in aVar[] */ Mem *aVar; /* Values for the OP_Variable opcode. */ char **azVar; /* Name of variables */ u32 magic; /* Magic number for sanity checking */ int nMem; /* Number of memory locations currently allocated */ Mem *aMem; /* The memory locations */ int cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ char *zErrMsg; /* Error message written here */ u8 explain; /* True if EXPLAIN present on SQL command */ u8 changeCntOn; /* True to update the change-counter */ u8 expired; /* True if the VM needs to be recompiled */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
291 292 293 294 295 296 297 | hasStatementBegin = 1; p->usesStmtJournal = 1; }else if( opcode==OP_Destroy ){ doesStatementRollback = 1; }else if( opcode==OP_Transaction && pOp->p2!=0 ){ p->readOnly = 0; #ifndef SQLITE_OMIT_VIRTUALTABLE | | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | hasStatementBegin = 1; p->usesStmtJournal = 1; }else if( opcode==OP_Destroy ){ doesStatementRollback = 1; }else if( opcode==OP_Transaction && pOp->p2!=0 ){ p->readOnly = 0; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( opcode==OP_VUpdate || opcode==OP_VRename || opcode==OP_Program ){ doesStatementRollback = 1; }else if( opcode==OP_VFilter ){ int n; assert( p->nOp - i >= 3 ); assert( pOp[-1].opcode==OP_Integer ); n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n; |
︙ | ︙ | |||
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 | Vdbe *v = pFrame->v; v->aOp = pFrame->aOp; v->nOp = pFrame->nOp; v->aMem = pFrame->aMem; v->nMem = pFrame->nMem; v->apCsr = pFrame->apCsr; v->nCursor = pFrame->nCursor; return pFrame->pc; } /* ** Close all cursors. ** ** Also release any dynamic memory held by the VM in the Vdbe.aMem memory | > > | 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 | Vdbe *v = pFrame->v; v->aOp = pFrame->aOp; v->nOp = pFrame->nOp; v->aMem = pFrame->aMem; v->nMem = pFrame->nMem; v->apCsr = pFrame->apCsr; v->nCursor = pFrame->nCursor; v->db->lastRowid = pFrame->lastRowid; v->nChange = pFrame->nChange; return pFrame->pc; } /* ** Close all cursors. ** ** Also release any dynamic memory held by the VM in the Vdbe.aMem memory |
︙ | ︙ | |||
1383 1384 1385 1386 1387 1388 1389 | /* Execute assert() statements to ensure that the Vdbe.apCsr[] and ** Vdbe.aMem[] arrays have already been cleaned up. */ int i; for(i=0; i<p->nCursor; i++){ assert( p->apCsr[i]==0 ); } for(i=1; i<=p->nMem; i++){ assert( p->aMem[i].flags==MEM_Null ); } #endif | < < < < < < | 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 | /* Execute assert() statements to ensure that the Vdbe.apCsr[] and ** Vdbe.aMem[] arrays have already been cleaned up. */ int i; for(i=0; i<p->nCursor; i++){ assert( p->apCsr[i]==0 ); } for(i=1; i<=p->nMem; i++){ assert( p->aMem[i].flags==MEM_Null ); } #endif sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; p->pResultSet = 0; } /* ** Set the number of result columns that will be returned by this SQL |
︙ | ︙ |
Changes to test/autoinc.test.
︙ | ︙ | |||
553 554 555 556 557 558 559 560 561 562 563 564 565 566 | INSERT INTO t2 VALUES(NULL, 1); CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b); INSERT INTO t3 SELECT * FROM t2 WHERE y>1; SELECT * FROM sqlite_sequence WHERE name='t3'; } } {t3 0} # Ticket #3928. Make sure that triggers to not make extra slots in # the SQLITE_SEQUENCE table. # do_test autoinc-3928.1 { db eval { CREATE TABLE t3928(a INTEGER PRIMARY KEY AUTOINCREMENT, b); | > > | 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 | INSERT INTO t2 VALUES(NULL, 1); CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b); INSERT INTO t3 SELECT * FROM t2 WHERE y>1; SELECT * FROM sqlite_sequence WHERE name='t3'; } } {t3 0} catchsql { pragma disable_recursive_triggers = 1 } # Ticket #3928. Make sure that triggers to not make extra slots in # the SQLITE_SEQUENCE table. # do_test autoinc-3928.1 { db eval { CREATE TABLE t3928(a INTEGER PRIMARY KEY AUTOINCREMENT, b); |
︙ | ︙ |
Changes to test/misc2.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # left out of other test files. # # $Id: misc2.test,v 1.28 2007/09/12 17:01:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {trigger} { # Test for ticket #360 # do_test misc2-1.1 { catchsql { CREATE TABLE FOO(bar integer); CREATE TRIGGER foo_insert BEFORE INSERT ON foo BEGIN | > > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # left out of other test files. # # $Id: misc2.test,v 1.28 2007/09/12 17:01:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # The tests in this file were written before SQLite supported recursive # trigger invocation, and some tests depend on that to pass. So disable # recursive triggers for this file. catchsql { pragma disable_recursive_triggers = 1 } ifcapable {trigger} { # Test for ticket #360 # do_test misc2-1.1 { catchsql { CREATE TABLE FOO(bar integer); CREATE TRIGGER foo_insert BEFORE INSERT ON foo BEGIN |
︙ | ︙ | |||
354 355 356 357 358 359 360 361 362 363 364 365 366 367 | execsql {SELECT * FROM t1} } {1 2 3 4 5 6 7 8 9 10} } db close file delete -force test.db sqlite3 db test.db # Ticket #453. If the SQL ended with "-", the tokenizer was calling that # an incomplete token, which caused problem. The solution was to just call # it a minus sign. # do_test misc2-8.1 { catchsql {-} | > | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | execsql {SELECT * FROM t1} } {1 2 3 4 5 6 7 8 9 10} } db close file delete -force test.db sqlite3 db test.db catchsql { pragma disable_recursive_triggers = 1 } # Ticket #453. If the SQL ended with "-", the tokenizer was calling that # an incomplete token, which caused problem. The solution was to just call # it a minus sign. # do_test misc2-8.1 { catchsql {-} |
︙ | ︙ |
Changes to test/tkt3731.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } do_test tkt3731-1.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t1 VALUES(new.a || '+', new.b || '+'); END; | > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # The tests in this file were written before SQLite supported recursive # trigger invocation, and some tests depend on that to pass. So disable # recursive triggers for this file. catchsql { pragma disable_recursive_triggers = 1 } do_test tkt3731-1.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t1 VALUES(new.a || '+', new.b || '+'); END; |
︙ | ︙ |
Changes to test/tkt3992.test.
︙ | ︙ | |||
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); | > > > > > | 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 50 51 52 53 54 | 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); } } {} puts [execsql { SELECT *,typeof(mountcnt),typeof(version) FROM parameters1 }] do_test tkt3992-1.2 { execsql { UPDATE parameters1 SET mountcnt = mountcnt + 1; SELECT * FROM parameters1; } } {2 1.0} do_test tkt3992-1.3 { explain { UPDATE parameters2 SET mountcnt = mountcnt + 1 } breakpoint execsql { pragma vdbe_trace = 1; UPDATE parameters2 SET mountcnt = mountcnt + 1; pragma vdbe_trace = 0; SELECT * FROM parameters2; } } {2 1.0} do_test tkt3992-2.1 { execsql { CREATE TABLE t1(a, b); |
︙ | ︙ | |||
68 69 70 71 72 73 74 | SELECT tcl('set res', typeof(new.c)); END; UPDATE t2 SET a = 'I'; } set res } {real} | < < < | 73 74 75 76 77 78 79 80 81 82 | SELECT tcl('set res', typeof(new.c)); END; UPDATE t2 SET a = 'I'; } set res } {real} finish_test |
Changes to test/trigger2.test.
︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # 1. ifcapable subquery { set ii 0 set tbl_definitions [list \ {CREATE TABLE tbl (a, b);} \ {CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} \ | > > > > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # The tests in this file were written before SQLite supported recursive # trigger invocation, and some tests depend on that to pass. So disable # recursive triggers for this file. catchsql { pragma disable_recursive_triggers = 1 } # 1. ifcapable subquery { set ii 0 set tbl_definitions [list \ {CREATE TABLE tbl (a, b);} \ {CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} \ |
︙ | ︙ |
Changes to test/trigger3.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # Test that we can cause ROLLBACK, FAIL and ABORT correctly | > > > > > < < | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # The tests in this file were written before SQLite supported recursive } # trigger invocation, and some tests depend on that to pass. So disable # recursive triggers for this file. catchsql { pragma disable_recursive_triggers = 1 } # Test that we can cause ROLLBACK, FAIL and ABORT correctly # catchsql { CREATE TABLE tbl(a, b ,c) } execsql { CREATE TRIGGER before_tbl_insert BEFORE INSERT ON tbl BEGIN SELECT CASE WHEN (new.a = 4) THEN RAISE(IGNORE) END; END; CREATE TRIGGER after_tbl_insert AFTER INSERT ON tbl BEGIN SELECT CASE WHEN (new.a = 1) THEN RAISE(ABORT, 'Trigger abort') |
︙ | ︙ | |||
50 51 52 53 54 55 56 | do_test trigger3-1.3 { execsql {SELECT * FROM tbl} } {} # FAIL do_test trigger3-2.1 { catchsql { | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | do_test trigger3-1.3 { execsql {SELECT * FROM tbl} } {} # FAIL do_test trigger3-2.1 { catchsql { BEGIN; INSERT INTO tbl VALUES (5, 5, 6); INSERT INTO tbl VALUES (2, 5, 6); } } {1 {Trigger fail}} do_test trigger3-2.2 { execsql { SELECT * FROM tbl; |
︙ | ︙ |
Changes to test/trigger9.test.
︙ | ︙ | |||
71 72 73 74 75 76 77 | END; DELETE FROM t1; SELECT * FROM t2; } } {1 2 3} do_test trigger9-1.3.2 { has_rowdata {DELETE FROM t1} | | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | END; DELETE FROM t1; SELECT * FROM t2; } } {1 2 3} do_test trigger9-1.3.2 { has_rowdata {DELETE FROM t1} } 0 do_test trigger9-1.3.3 { execsql { ROLLBACK } } {} do_test trigger9-1.4.1 { execsql { BEGIN; CREATE TRIGGER trig1 BEFORE DELETE ON t1 WHEN old.x='1' BEGIN INSERT INTO t2 VALUES(old.rowid); END; DELETE FROM t1; SELECT * FROM t2; } } {1} do_test trigger9-1.4.2 { has_rowdata {DELETE FROM t1} } 0 do_test trigger9-1.4.3 { execsql { ROLLBACK } } {} do_test trigger9-1.5.1 { execsql { BEGIN; CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN INSERT INTO t2 VALUES(old.rowid); |
︙ | ︙ | |||
116 117 118 119 120 121 122 | END; UPDATE t1 SET y = ''; SELECT * FROM t2; } } {1 2 3} do_test trigger9-1.6.2 { has_rowdata {UPDATE t1 SET y = ''} | | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | END; UPDATE t1 SET y = ''; SELECT * FROM t2; } } {1 2 3} do_test trigger9-1.6.2 { has_rowdata {UPDATE t1 SET y = ''} } 0 do_test trigger9-1.6.3 { execsql { ROLLBACK } } {} do_test trigger9-1.7.1 { execsql { BEGIN; CREATE TRIGGER trig1 BEFORE UPDATE ON t1 WHEN old.x>='2' BEGIN INSERT INTO t2 VALUES(old.x); END; UPDATE t1 SET y = ''; SELECT * FROM t2; } } {2 3} do_test trigger9-1.7.2 { has_rowdata {UPDATE t1 SET y = ''} } 0 do_test trigger9-1.7.3 { execsql { ROLLBACK } } {} do_test trigger9-3.1 { execsql { CREATE TABLE t3(a, b); INSERT INTO t3 VALUES(1, 'one'); INSERT INTO t3 VALUES(2, 'two'); |
︙ | ︙ |