Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a stack overflow problem with INSTEAD OF triggers. (CVS 1310) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | version_2 |
Files: | files | file ages | folders |
SHA1: |
5a33e0b06f495628704d0881940a792f |
User & Date: | drh 2004-04-29 16:16:29.000 |
Context
2004-05-07
| ||
00:57 | Add the sqlite_temp_directory global variable which, if set, defines the directory in which temporary files are created. (CVS 1316) (check-in: c90ed20dc4 user: drh tags: version_2) | |
2004-04-29
| ||
16:16 | Fix a stack overflow problem with INSTEAD OF triggers. (CVS 1310) (check-in: 5a33e0b06f user: drh tags: version_2) | |
2004-04-24
| ||
12:59 | Changes to lemon.c so that it compiles on OpenWatcom 1.3. Ticket #665. (CVS 1307) (check-in: b8b8ce5c81 user: drh tags: version_2) | |
Changes
Changes to src/update.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 C code routines that are called by the parser ** to handle UPDATE statements. ** | | | > > > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.70.2.1 2004/04/29 16:16:29 drh Exp $ */ #include "sqliteInt.h" /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; ** \_______/ \________/ \______/ \________________/ * onError pTabList pChanges pWhere */ void sqliteUpdate( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table in which we should change things */ ExprList *pChanges, /* Things to be changed */ Expr *pWhere, /* The WHERE clause. May be null */ int onError /* How to handle constraint errors */ ){ int i, j; /* Loop counters */ Table *pTab; /* The table to be updated */ int loopStart; /* VDBE instruction address of the start of the loop */ int jumpInst; /* Addr of VDBE instruction to jump out of loop */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Vdbe *v; /* The virtual database engine */ Index *pIdx; /* For looping over indices */ int nIdx; /* Number of indices that need updating */ int nIdxTotal; /* Total number of indices */ int iCur; /* VDBE Cursor number of pTab */ sqlite *db; /* The database structure */ Index **apIdx = 0; /* An array of indices that need updating too */ char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ int chngRecno; /* True if the record number is being changed */ Expr *pRecnoExpr; /* Expression defining the new record number */ int openAll; /* True if all indices need to be opened */ int isView; /* Trying to update a view */ int iStackDepth; /* Index of memory cell holding stack depth */ AuthContext sContext; /* The authorization context */ int before_triggers; /* True if there are any BEFORE triggers */ int after_triggers; /* True if there are any AFTER triggers */ int row_triggers_exist = 0; /* True if any row triggers exist */ int newIdx = -1; /* index of trigger "new" temp table */ int oldIdx = -1; /* index of trigger "old" temp table */ sContext.pParse = 0; if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; db = pParse->db; assert( pTabList->nSrc==1 ); iStackDepth = pParse->nMem++; /* Locate the table which we want to update. */ pTab = sqliteSrcListLookup(pParse, pTabList); if( pTab==0 ) goto update_cleanup; before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_UPDATE, TK_BEFORE, TK_ROW, pChanges); |
︙ | ︙ | |||
244 245 246 247 248 249 250 | */ sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0); /* The top of the update loop for when there are triggers. */ sqliteVdbeAddOp(v, OP_ListRewind, 0, 0); | > > > > | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | */ sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0); /* The top of the update loop for when there are triggers. */ sqliteVdbeAddOp(v, OP_ListRewind, 0, 0); sqliteVdbeAddOp(v, OP_StackDepth, 0, 0); sqliteVdbeAddOp(v, OP_MemStore, iStackDepth, 1); loopStart = sqliteVdbeAddOp(v, OP_MemLoad, iStackDepth, 0); sqliteVdbeAddOp(v, OP_StackReset, 0, 0); jumpInst = sqliteVdbeAddOp(v, OP_ListRead, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0); /* Open a cursor and make it point to the record that is ** being updated. */ sqliteVdbeAddOp(v, OP_Dup, 0, 0); if( !isView ){ |
︙ | ︙ | |||
291 292 293 294 295 296 297 | if( !isView ){ sqliteVdbeAddOp(v, OP_Close, iCur, 0); } /* Fire the BEFORE and INSTEAD OF triggers */ if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab, | | | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | if( !isView ){ sqliteVdbeAddOp(v, OP_Close, iCur, 0); } /* Fire the BEFORE and INSTEAD OF triggers */ if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab, newIdx, oldIdx, onError, loopStart) ){ goto update_cleanup; } } if( !isView ){ /* ** Open every index that needs updating. Note that if any |
︙ | ︙ | |||
332 333 334 335 336 337 338 | ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entires. ** So make the cursor point at the old record. */ if( !row_triggers_exist ){ sqliteVdbeAddOp(v, OP_ListRewind, 0, 0); | | | | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entires. ** So make the cursor point at the old record. */ if( !row_triggers_exist ){ sqliteVdbeAddOp(v, OP_ListRewind, 0, 0); jumpInst = loopStart = sqliteVdbeAddOp(v, OP_ListRead, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0); } sqliteVdbeAddOp(v, OP_NotExists, iCur, loopStart); /* If the record number will change, push the record number as it ** will be after the update. (The old record number is currently ** on top of the stack.) */ if( chngRecno ){ sqliteExprCode(pParse, pRecnoExpr); |
︙ | ︙ | |||
364 365 366 367 368 369 370 | sqliteExprCode(pParse, pChanges->a[j].pExpr); } } /* Do constraint checks */ sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, | | | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | sqliteExprCode(pParse, pChanges->a[j].pExpr); } } /* Do constraint checks */ sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, onError, loopStart); /* Delete the old indices for the current record. */ sqliteGenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed); /* If changing the record number, delete the old record. */ |
︙ | ︙ | |||
400 401 402 403 404 405 406 | if( openAll || aIdxUsed[i] ) sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0); } sqliteVdbeAddOp(v, OP_Close, iCur, 0); pParse->nTab = iCur; } if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab, | | | | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | if( openAll || aIdxUsed[i] ) sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0); } sqliteVdbeAddOp(v, OP_Close, iCur, 0); pParse->nTab = iCur; } if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab, newIdx, oldIdx, onError, loopStart) ){ goto update_cleanup; } } /* Repeat the above with the next record to be updated, until ** all record selected by the WHERE clause have been updated. */ sqliteVdbeAddOp(v, OP_Goto, 0, loopStart); sqliteVdbeChangeP2(v, jumpInst, sqliteVdbeCurrentAddr(v)); sqliteVdbeAddOp(v, OP_ListReset, 0, 0); /* Close all tables if there were no FOR EACH ROW triggers */ if( !row_triggers_exist ){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aIdxUsed[i] ){ sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.268.2.1 2004/04/29 16:16:30 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 | */ case OP_Vacuum: { if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; rc = sqliteRunVacuum(&p->zErrMsg, db); if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; break; } /* An other opcode is illegal... */ default: { sqlite_snprintf(sizeof(zBuf),zBuf,"%d",pOp->opcode); sqliteSetString(&p->zErrMsg, "unknown opcode ", zBuf, (char*)0); rc = SQLITE_INTERNAL; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 | */ case OP_Vacuum: { if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; rc = sqliteRunVacuum(&p->zErrMsg, db); if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; break; } /* Opcode: StackDepth * * * ** ** Push an integer onto the stack which is the depth of the stack prior ** to that integer being pushed. */ case OP_StackDepth: { int depth = (&pTos[1]) - p->aStack; pTos++; pTos->i = depth; pTos->flags = MEM_Int; break; } /* Opcode: StackReset * * * ** ** Pop a single integer off of the stack. Then pop the stack ** as many times as necessary to get the depth of the stack down ** to the value of the integer that was popped. */ case OP_StackReset: { int depth, goal; assert( pTos>=p->aStack ); Integerify(pTos); goal = pTos->i; depth = (&pTos[1]) - p->aStack; assert( goal<depth ); popStack(&pTos, depth-goal); break; } /* An other opcode is illegal... */ default: { sqlite_snprintf(sizeof(zBuf),zBuf,"%d",pOp->opcode); sqliteSetString(&p->zErrMsg, "unknown opcode ", zBuf, (char*)0); rc = SQLITE_INTERNAL; |
︙ | ︙ |