Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Make sure the value of an INTEGER PRIMARY KEY column supplied to triggers and especially to FK constraints really contains the ROWID and not the NULL that is stored in the column itself. Ticket [dd08e5a988d00dec]. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
636f86095eb1f4bdcfb0c9ed846c4c6b |
User & Date: | drh 2010-05-14 19:24:02.000 |
References
2010-07-29
| ||
01:55 | • Ticket [ce7c133ea6] Foreign key constraint fails when it should succeed. status still Open with 4 other changes (artifact: 6fb11fefa6 user: drh) | |
2010-07-28
| ||
20:57 | • New ticket [ce7c133ea6]. (artifact: 4202cdf359 user: drh) | |
Context
2010-05-14
| ||
20:15 | Fix a typo that (by bad luck) was not a syntax error but which caused some important lines of code to be skipped when SQLITE_DEBUG was not used. (check-in: 9ef99d97d2 user: drh tags: trunk) | |
19:24 | Make sure the value of an INTEGER PRIMARY KEY column supplied to triggers and especially to FK constraints really contains the ROWID and not the NULL that is stored in the column itself. Ticket [dd08e5a988d00dec]. (check-in: 636f86095e user: drh tags: trunk) | |
14:52 | Simplifications to the SHM implementation in os_unix.c, taking advantage of the removal of the LinuxThreads mess. (check-in: d1debe5def user: drh tags: trunk) | |
Changes
Changes to src/delete.c.
︙ | ︙ | |||
504 505 506 507 508 509 510 | pParse->nMem += (1 + pTab->nCol); /* Populate the OLD.* pseudo-table register array. These values will be ** used by any BEFORE and AFTER triggers that exist. */ sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld); for(iCol=0; iCol<pTab->nCol; iCol++){ if( mask==0xffffffff || mask&(1<<iCol) ){ | < < | | 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | pParse->nMem += (1 + pTab->nCol); /* Populate the OLD.* pseudo-table register array. These values will be ** used by any BEFORE and AFTER triggers that exist. */ sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld); for(iCol=0; iCol<pTab->nCol; iCol++){ if( mask==0xffffffff || mask&(1<<iCol) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, iOld+iCol+1); } } /* Invoke BEFORE DELETE trigger programs. */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel ); |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 | struct yColCache *p; for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ if( p->iReg==iReg ){ p->tempReg = 0; } } } /* ** Generate code that will extract the iColumn-th column from ** table pTab and store the column value in a register. An effort ** is made to store the column value in register iReg, but this is ** not guaranteed. The location of the column value is returned. ** | > > > > > > > > > > > > > > > > > > > > > | 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 | struct yColCache *p; for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ if( p->iReg==iReg ){ p->tempReg = 0; } } } /* ** Generate code to extract the value of the iCol-th column of a table. */ void sqlite3ExprCodeGetColumnOfTable( Vdbe *v, /* The VDBE under construction */ Table *pTab, /* The table containing the value */ int iTabCur, /* The cursor for this table */ int iCol, /* Index of the column to extract */ int regOut /* Extract the valud into this register */ ){ if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; sqlite3VdbeAddOp3(v, op, iTabCur, iCol, regOut); } if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); } } /* ** Generate code that will extract the iColumn-th column from ** table pTab and store the column value in a register. An effort ** is made to store the column value in register iReg, but this is ** not guaranteed. The location of the column value is returned. ** |
︙ | ︙ | |||
2106 2107 2108 2109 2110 2111 2112 | if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){ p->lru = pParse->iCacheCnt++; sqlite3ExprCachePinRegister(pParse, p->iReg); return p->iReg; } } assert( v!=0 ); | < < < < < | < | 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 | if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){ p->lru = pParse->iCacheCnt++; sqlite3ExprCachePinRegister(pParse, p->iReg); return p->iReg; } } assert( v!=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg); sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg); return iReg; } /* ** Clear all column cache entries. */ |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 | Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, char *); #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16); void sqlite3WhereEnd(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCodeCopy(Parse*, int, int, int); void sqlite3ExprCacheStore(Parse*, int, int, int); void sqlite3ExprCachePush(Parse*); void sqlite3ExprCachePop(Parse*, int); void sqlite3ExprCacheRemove(Parse*, int, int); void sqlite3ExprCacheClear(Parse*); | > | 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 | Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, char *); #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16); void sqlite3WhereEnd(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCodeCopy(Parse*, int, int, int); void sqlite3ExprCacheStore(Parse*, int, int, int); void sqlite3ExprCachePush(Parse*); void sqlite3ExprCachePop(Parse*, int); void sqlite3ExprCacheRemove(Parse*, int, int); void sqlite3ExprCacheClear(Parse*); |
︙ | ︙ |
Changes to src/update.c.
1 2 3 4 5 6 7 8 9 10 | /* ** 2001 September 15 ** ** 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 | /* ** 2001 September 15 ** ** 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. ** sqlite************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_VIRTUALTABLE /* Forward declaration */ |
︙ | ︙ | |||
392 393 394 395 396 397 398 | if( hasFK || pTrigger ){ u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0); oldmask |= sqlite3TriggerColmask(pParse, pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError ); for(i=0; i<pTab->nCol; i++){ if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){ | < | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | if( hasFK || pTrigger ){ u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0); oldmask |= sqlite3TriggerColmask(pParse, pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError ); for(i=0; i<pTab->nCol; i++){ if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); } } if( chngRowid==0 ){ sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } |
︙ | ︙ |
Changes to test/fkey2.test.
︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 | # # fkey2-18.*: Test that the authorization callback is invoked when processing # FK constraints. # # fkey2-genfkey.*: Tests that were used with the shell tool .genfkey # command. Recycled to test the built-in implementation. # execsql { PRAGMA foreign_keys = on } set FkeySimpleSchema { PRAGMA foreign_keys = on; CREATE TABLE t1(a PRIMARY KEY, b); | > > > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | # # fkey2-18.*: Test that the authorization callback is invoked when processing # FK constraints. # # fkey2-genfkey.*: Tests that were used with the shell tool .genfkey # command. Recycled to test the built-in implementation. # # fkey2-dd08e5.*: Tests to verify that ticket dd08e5a988d00decc4a543daa8d # has been fixed. # execsql { PRAGMA foreign_keys = on } set FkeySimpleSchema { PRAGMA foreign_keys = on; CREATE TABLE t1(a PRIMARY KEY, b); |
︙ | ︙ | |||
1795 1796 1797 1798 1799 1800 1801 1802 1803 | do_test fkey2-genfkey.3.6 { execsql { UPDATE t3 SET h = 2, i = 2; DELETE FROM t1; SELECT * FROM t3; } } {hello {} {}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 | do_test fkey2-genfkey.3.6 { execsql { UPDATE t3 SET h = 2, i = 2; DELETE FROM t1; SELECT * FROM t3; } } {hello {} {}} #------------------------------------------------------------------------- # Verify that ticket dd08e5a988d00decc4a543daa8dbbfab9c577ad8 has been # fixed. # do_test fkey2-dd08e5.1.1 { execsql { PRAGMA foreign_keys=ON; CREATE TABLE tdd08(a INTEGER PRIMARY KEY, b); CREATE UNIQUE INDEX idd08 ON tdd08(a,b); INSERT INTO tdd08 VALUES(200,300); CREATE TABLE tdd08_b(w,x,y, FOREIGN KEY(x,y) REFERENCES tdd08(a,b)); INSERT INTO tdd08_b VALUES(100,200,300); } } {} do_test fkey2-dd08e5.1.2 { catchsql { DELETE FROM tdd08; } } {1 {foreign key constraint failed}} do_test fkey2-dd08e5.1.3 { execsql { SELECT * FROM tdd08; } } {200 300} do_test fkey2-dd08e5.1.4 { catchsql { INSERT INTO tdd08_b VALUES(400,500,300); } } {1 {foreign key constraint failed}} do_test fkey2-dd08e5.1.5 { catchsql { UPDATE tdd08_b SET x=x+1; } } {1 {foreign key constraint failed}} do_test fkey2-dd08e5.1.6 { catchsql { UPDATE tdd08 SET a=a+1; } } {1 {foreign key constraint failed}} finish_test |