mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Refactor the INSERT, DELETE, and UPDATE code generators to distinguish between
the "data cursor" and the "first index cursor", which are no longer consecutive in the case of a WITHOUT ROWID table. FossilOrigin-Name: 1adfca6019847d37dee4a297669f29d5ca184066
This commit is contained in:
26
manifest
26
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Continue\sworking\sto\sget\sUPDATE\soperational\sfor\sWITHOUT\sROWID\stables.\nFix\sPRAGMA\sintegrity_check\sso\sthat\sit\sworks\son\sWITHOUT\sROWID\stables.
|
C Refactor\sthe\sINSERT,\sDELETE,\sand\sUPDATE\scode\sgenerators\sto\sdistinguish\sbetween\nthe\s"data\scursor"\sand\sthe\s"first\sindex\scursor",\swhich\sare\sno\slonger\sconsecutive\nin\sthe\scase\sof\sa\sWITHOUT\sROWID\stable.
|
||||||
D 2013-10-30T20:22:55.102
|
D 2013-10-31T11:15:09.631
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
|
F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -173,7 +173,7 @@ F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
|
|||||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||||
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
|
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
|
||||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||||
F src/delete.c 7b56fcc7e290f52e1825692cce37e2f001c7286b
|
F src/delete.c d50cc704030139e19f2e9d5ac7a49db04dfe08a9
|
||||||
F src/expr.c 3180b6332072b263f845592e72e92971af562ab0
|
F src/expr.c 3180b6332072b263f845592e72e92971af562ab0
|
||||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||||
F src/fkey.c 628f81177299660a86e40359b3689b81f517e125
|
F src/fkey.c 628f81177299660a86e40359b3689b81f517e125
|
||||||
@@ -182,7 +182,7 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
|||||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||||
F src/insert.c 4d832cca6d235ca0fc7f2c4acff23ca3246c8548
|
F src/insert.c 076f600e99cd49ce4509bcff3e0620df0fdcf46d
|
||||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||||
@@ -212,7 +212,7 @@ F src/parse.y 073a8294e1826f1b1656e84806b77e4199f4bb57
|
|||||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||||
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
|
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
|
||||||
F src/pragma.c c6612470d2db2cc30d226c1990faeaff7320a296
|
F src/pragma.c 74dec25a3f0d3e5da796345a0ca817cb445e9d2a
|
||||||
F src/prepare.c f47ba2bba7ac5650881ab6c41f6d33a6de1a8d52
|
F src/prepare.c f47ba2bba7ac5650881ab6c41f6d33a6de1a8d52
|
||||||
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
|
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
|
||||||
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
|
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
|
||||||
@@ -223,7 +223,7 @@ F src/shell.c d5eebdc6034014103de2b9d58e1d3f6f7de0fb50
|
|||||||
F src/sqlite.h.in 547a44dd4ff4d975e92a645ea2d609e543a83d0f
|
F src/sqlite.h.in 547a44dd4ff4d975e92a645ea2d609e543a83d0f
|
||||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||||
F src/sqliteInt.h f8fc23b598245de9460af2de163c91fc31d4fb27
|
F src/sqliteInt.h c41205f31edb0c803a7b1bad92fe91d552a9eec7
|
||||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||||
@@ -275,15 +275,15 @@ F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
|
|||||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||||
F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
|
F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
|
||||||
F src/trigger.c 53d6b5d50b3b23d4fcd0a36504feb5cff9aed716
|
F src/trigger.c 53d6b5d50b3b23d4fcd0a36504feb5cff9aed716
|
||||||
F src/update.c 103ab76ccd4211b4c298ad4fe4c7a16fbd274818
|
F src/update.c 3be9af558558062d335e35acb13f7507f053ff76
|
||||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||||
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
|
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
|
||||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||||
F src/vdbe.c 05857502186641716e8d9204de138b642208628f
|
F src/vdbe.c da933a7c58470db06e5705d001013d52020ef7e2
|
||||||
F src/vdbe.h c18a2dd91c838601b867a214e43c5f66d5d001ba
|
F src/vdbe.h c18a2dd91c838601b867a214e43c5f66d5d001ba
|
||||||
F src/vdbeInt.h 42dcff74dbeb2b071e569b53f885fc9c2e4b4cb0
|
F src/vdbeInt.h 42dcff74dbeb2b071e569b53f885fc9c2e4b4cb0
|
||||||
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
|
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
|
||||||
F src/vdbeaux.c 347cfece32afdbac935000fd6ea2b58930a99e8a
|
F src/vdbeaux.c 717c8c2eb30641a75790311669ee0dfe5504ec56
|
||||||
F src/vdbeblob.c ef973d8d9f8170015343dd8824f795da675caa87
|
F src/vdbeblob.c ef973d8d9f8170015343dd8824f795da675caa87
|
||||||
F src/vdbemem.c 6087553f2c61c06c8e1ab3959a60e174d6240c98
|
F src/vdbemem.c 6087553f2c61c06c8e1ab3959a60e174d6240c98
|
||||||
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
|
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
|
||||||
@@ -1076,7 +1076,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
|||||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||||
F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
|
F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
|
||||||
F test/without_rowid1.test 1c3d5a5df986d931a3c5c19ffef5804bd324d9e5
|
F test/without_rowid1.test fb3ceaa20bda4e0338f594696a49014c3cbeb30c
|
||||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||||
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
|
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
|
||||||
F tool/build-all-msvc.bat 38623a30fd58288fda5cc7f7df2682aaab75c9d5 x
|
F tool/build-all-msvc.bat 38623a30fd58288fda5cc7f7df2682aaab75c9d5 x
|
||||||
@@ -1128,7 +1128,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||||
P 6d9af6065fc0da8337aee2297a8da7511eecccf1
|
P 0d4fea7462c0f61cd1c736cbcd7bea5ec2034d54
|
||||||
R 00013e769d264c62972e72b68f63eb56
|
R 5cee3ee2f21ff3dcfee1d1450366398f
|
||||||
U drh
|
U drh
|
||||||
Z 05e092e5dbaf4f4f4e2497c5914c1170
|
Z 8325d71a27ada5d7265b86dd95f46d5a
|
||||||
|
@@ -1 +1 @@
|
|||||||
0d4fea7462c0f61cd1c736cbcd7bea5ec2034d54
|
1adfca6019847d37dee4a297669f29d5ca184066
|
110
src/delete.c
110
src/delete.c
@@ -231,7 +231,9 @@ void sqlite3DeleteFrom(
|
|||||||
int i; /* Loop counter */
|
int i; /* Loop counter */
|
||||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||||
Index *pIdx; /* For looping over indices of the table */
|
Index *pIdx; /* For looping over indices of the table */
|
||||||
int iCur; /* VDBE Cursor number for pTab */
|
int iTabCur; /* Cursor number for the table */
|
||||||
|
int iDataCur; /* VDBE cursor for the canonical data source */
|
||||||
|
int iIdxCur; /* Cursor number of the first index */
|
||||||
sqlite3 *db; /* Main database structure */
|
sqlite3 *db; /* Main database structure */
|
||||||
AuthContext sContext; /* Authorization context */
|
AuthContext sContext; /* Authorization context */
|
||||||
NameContext sNC; /* Name context to resolve expressions in */
|
NameContext sNC; /* Name context to resolve expressions in */
|
||||||
@@ -296,7 +298,7 @@ void sqlite3DeleteFrom(
|
|||||||
/* Assign cursor number to the table and all its indices.
|
/* Assign cursor number to the table and all its indices.
|
||||||
*/
|
*/
|
||||||
assert( pTabList->nSrc==1 );
|
assert( pTabList->nSrc==1 );
|
||||||
iCur = pTabList->a[0].iCursor = pParse->nTab++;
|
iTabCur = pTabList->a[0].iCursor = pParse->nTab++;
|
||||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||||
pParse->nTab++;
|
pParse->nTab++;
|
||||||
}
|
}
|
||||||
@@ -321,7 +323,7 @@ void sqlite3DeleteFrom(
|
|||||||
*/
|
*/
|
||||||
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
||||||
if( isView ){
|
if( isView ){
|
||||||
sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
|
sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -385,7 +387,7 @@ void sqlite3DeleteFrom(
|
|||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, 0, 0);
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, 0, 0);
|
||||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||||
for(i=0; i<nPk; i++){
|
for(i=0; i<nPk; i++){
|
||||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, pPk->aiColumn[i], iPk+i);
|
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i],iPk+i);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
|
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
|
||||||
sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
|
sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
|
||||||
@@ -394,23 +396,27 @@ void sqlite3DeleteFrom(
|
|||||||
|
|
||||||
/* Open cursors for all indices of the table.
|
/* Open cursors for all indices of the table.
|
||||||
*/
|
*/
|
||||||
sqlite3OpenTableAndIndices(pParse, pTab, iCur, iCur, OP_OpenWrite);
|
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite,
|
||||||
|
iTabCur, &iDataCur, &iIdxCur);
|
||||||
|
assert( iDataCur!=iTabCur );
|
||||||
|
assert( iDataCur>=iIdxCur );
|
||||||
|
|
||||||
/* Loop over the primary keys to be deleted. */
|
/* Loop over the primary keys to be deleted. */
|
||||||
addr = sqlite3VdbeAddOp1(v, OP_Rewind, iEph);
|
addr = sqlite3VdbeAddOp1(v, OP_Rewind, iEph);
|
||||||
sqlite3VdbeAddOp2(v, OP_RowKey, iEph, iPk);
|
sqlite3VdbeAddOp2(v, OP_RowKey, iEph, iPk);
|
||||||
|
|
||||||
/* Delete the row */
|
/* Delete the row */
|
||||||
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iCur, iPk, 0,
|
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
||||||
1, OE_Default);
|
iPk, nPk, 1, OE_Default);
|
||||||
|
|
||||||
/* End of the delete loop */
|
/* End of the delete loop */
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, iEph, addr+1);
|
sqlite3VdbeAddOp2(v, OP_Next, iEph, addr+1);
|
||||||
sqlite3VdbeJumpHere(v, addr);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
|
|
||||||
/* Close the cursors open on the table and its indexes. */
|
/* Close the cursors open on the table and its indexes. */
|
||||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
assert( iDataCur>=iIdxCur );
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, pIdx==pPk ? iCur : iCur + i, pIdx->tnum);
|
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur+i);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
/* There is a WHERE clause on a rowid table. Run a loop that extracts
|
/* There is a WHERE clause on a rowid table. Run a loop that extracts
|
||||||
@@ -427,7 +433,7 @@ void sqlite3DeleteFrom(
|
|||||||
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK, 0
|
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK, 0
|
||||||
);
|
);
|
||||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||||
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
|
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iRowid, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
|
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
|
||||||
if( db->flags & SQLITE_CountRows ){
|
if( db->flags & SQLITE_CountRows ){
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
|
||||||
@@ -444,7 +450,10 @@ void sqlite3DeleteFrom(
|
|||||||
** only effect this statement has is to fire the INSTEAD OF
|
** only effect this statement has is to fire the INSTEAD OF
|
||||||
** triggers. */
|
** triggers. */
|
||||||
if( !isView ){
|
if( !isView ){
|
||||||
sqlite3OpenTableAndIndices(pParse, pTab, iCur, -1, OP_OpenWrite);
|
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur,
|
||||||
|
&iDataCur, &iIdxCur);
|
||||||
|
assert( iDataCur==iTabCur );
|
||||||
|
assert( iIdxCur==iDataCur+1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
|
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
|
||||||
@@ -461,8 +470,8 @@ void sqlite3DeleteFrom(
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int count = (pParse->nested==0); /* True to count changes */
|
int count = (pParse->nested==0); /* True to count changes */
|
||||||
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iCur, iRowid, 0,
|
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
||||||
count, OE_Default);
|
iRowid, 1, count, OE_Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End of the delete loop */
|
/* End of the delete loop */
|
||||||
@@ -471,10 +480,10 @@ void sqlite3DeleteFrom(
|
|||||||
|
|
||||||
/* Close the cursors open on the table and its indexes. */
|
/* Close the cursors open on the table and its indexes. */
|
||||||
if( !isView && !IsVirtual(pTab) ){
|
if( !isView && !IsVirtual(pTab) ){
|
||||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx->tnum);
|
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp1(v, OP_Close, iCur);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,15 +528,16 @@ delete_from_cleanup:
|
|||||||
** The VDBE must be in a particular state when this routine is called.
|
** The VDBE must be in a particular state when this routine is called.
|
||||||
** These are the requirements:
|
** These are the requirements:
|
||||||
**
|
**
|
||||||
** 1. A read/write cursor pointing to pTab, the table containing the row
|
** 1. iDataCur is an open cursor on the btree that is the primary data
|
||||||
** to be deleted, must be opened as cursor number iCur (except for
|
** repository for the table. This will be either the table itself,
|
||||||
** WITHOUT ROWID tables which do not have a main table).
|
** in the case of a rowid table, or the PRIMARY KEY index in the case
|
||||||
|
** of a WITHOUT ROWID table.
|
||||||
**
|
**
|
||||||
** 2. Read/write cursors for all indices of pTab must be open as
|
** 2. Read/write cursors for all indices of pTab must be open as
|
||||||
** cursor number iCur+i for the i-th index.
|
** cursor number iIdxCur+i for the i-th index.
|
||||||
**
|
**
|
||||||
** 3. The primary key for the row to be deleted must be stored in a
|
** 3. The primary key for the row to be deleted must be stored in a
|
||||||
** sequence of memory cells starting at iPk.
|
** sequence of nPk memory cells starting at iPk.
|
||||||
**
|
**
|
||||||
** This routine generates code to remove both the table record and all
|
** This routine generates code to remove both the table record and all
|
||||||
** index entries that point to that record.
|
** index entries that point to that record.
|
||||||
@@ -536,7 +546,8 @@ void sqlite3GenerateRowDelete(
|
|||||||
Parse *pParse, /* Parsing context */
|
Parse *pParse, /* Parsing context */
|
||||||
Table *pTab, /* Table containing the row to be deleted */
|
Table *pTab, /* Table containing the row to be deleted */
|
||||||
Trigger *pTrigger, /* List of triggers to (potentially) fire */
|
Trigger *pTrigger, /* List of triggers to (potentially) fire */
|
||||||
int iCur, /* Cursor number for the table */
|
int iDataCur, /* Cursor from which column data is extracted */
|
||||||
|
int iIdxCur, /* First index cursor */
|
||||||
int iPk, /* First memory cell containing the PRIMARY KEY */
|
int iPk, /* First memory cell containing the PRIMARY KEY */
|
||||||
i16 nPk, /* Number of PRIMARY KEY memory cells */
|
i16 nPk, /* Number of PRIMARY KEY memory cells */
|
||||||
u8 count, /* If non-zero, increment the row change counter */
|
u8 count, /* If non-zero, increment the row change counter */
|
||||||
@@ -549,15 +560,15 @@ void sqlite3GenerateRowDelete(
|
|||||||
|
|
||||||
/* Vdbe is guaranteed to have been allocated by this stage. */
|
/* Vdbe is guaranteed to have been allocated by this stage. */
|
||||||
assert( v );
|
assert( v );
|
||||||
VdbeModuleComment((v, "BEGIN: GenerateRowDelete(%d,%d,%d)",
|
VdbeModuleComment((v, "BEGIN: GenerateRowDelete(%d,%d,%d,%d)",
|
||||||
iCur, iPk, (int)nPk));
|
iDataCur, iIdxCur, iPk, (int)nPk));
|
||||||
|
|
||||||
/* Seek cursor iCur to the row to delete. If this row no longer exists
|
/* Seek cursor iCur to the row to delete. If this row no longer exists
|
||||||
** (this can happen if a trigger program has already deleted it), do
|
** (this can happen if a trigger program has already deleted it), do
|
||||||
** not attempt to delete it or fire any DELETE triggers. */
|
** not attempt to delete it or fire any DELETE triggers. */
|
||||||
iLabel = sqlite3VdbeMakeLabel(v);
|
iLabel = sqlite3VdbeMakeLabel(v);
|
||||||
opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
|
opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
|
||||||
sqlite3VdbeAddOp4Int(v, opSeek, iCur, iLabel, iPk, nPk);
|
sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
|
||||||
|
|
||||||
/* If there are any triggers to fire, allocate a range of registers to
|
/* If there are any triggers to fire, allocate a range of registers to
|
||||||
** use for the old.* references in the triggers. */
|
** use for the old.* references in the triggers. */
|
||||||
@@ -579,7 +590,7 @@ void sqlite3GenerateRowDelete(
|
|||||||
sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld);
|
sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld);
|
||||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||||
if( mask==0xffffffff || mask&(1<<iCol) ){
|
if( mask==0xffffffff || mask&(1<<iCol) ){
|
||||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, iOld+iCol+1);
|
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +603,7 @@ void sqlite3GenerateRowDelete(
|
|||||||
** the BEFORE triggers coded above have already removed the row
|
** the BEFORE triggers coded above have already removed the row
|
||||||
** being deleted. Do not attempt to delete the row a second time, and
|
** being deleted. Do not attempt to delete the row a second time, and
|
||||||
** do not fire AFTER triggers. */
|
** do not fire AFTER triggers. */
|
||||||
sqlite3VdbeAddOp4Int(v, opSeek, iCur, iLabel, iPk, nPk);
|
sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
|
||||||
|
|
||||||
/* Do FK processing. This call checks that any FK constraints that
|
/* Do FK processing. This call checks that any FK constraints that
|
||||||
** refer to this table (i.e. constraints attached to other tables)
|
** refer to this table (i.e. constraints attached to other tables)
|
||||||
@@ -604,11 +615,8 @@ void sqlite3GenerateRowDelete(
|
|||||||
** a view (in which case the only effect of the DELETE statement is to
|
** a view (in which case the only effect of the DELETE statement is to
|
||||||
** fire the INSTEAD OF triggers). */
|
** fire the INSTEAD OF triggers). */
|
||||||
if( pTab->pSelect==0 ){
|
if( pTab->pSelect==0 ){
|
||||||
Index *pPk;
|
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
|
||||||
int iMainCur;
|
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
|
||||||
sqlite3PrincipleBtree(pTab, iCur, &pPk, &iMainCur);
|
|
||||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iMainCur, 0);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Delete, iMainCur, (count?OPFLAG_NCHANGE:0));
|
|
||||||
if( count ){
|
if( count ){
|
||||||
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
||||||
}
|
}
|
||||||
@@ -638,23 +646,22 @@ void sqlite3GenerateRowDelete(
|
|||||||
** The VDBE must be in a particular state when this routine is called.
|
** The VDBE must be in a particular state when this routine is called.
|
||||||
** These are the requirements:
|
** These are the requirements:
|
||||||
**
|
**
|
||||||
** 1. A read/write cursor pointing to pTab, the table containing the row
|
** 1. A read/write cursor "iDataCur" pointing to canonical storage
|
||||||
** to be deleted, must be opened as cursor number "iCur". For
|
** tree for the table pTab, which will be either the table itself
|
||||||
** WITHOUT ROWID tables that do not have a main table, the iCur
|
** for rowid tables or to the primary key index for WITHOUT ROWID
|
||||||
** cursor is unused.
|
** tables.
|
||||||
**
|
**
|
||||||
** 2. Read/write cursors for all indices of pTab must be open as
|
** 2. Read/write cursors for all indices of pTab must be open as
|
||||||
** cursor number iCur+i for the i-th index.
|
** cursor number iIdxCur+i for the i-th index.
|
||||||
**
|
**
|
||||||
** 3. The "iCur" cursor must be pointing to the row that is to be
|
** 3. The "iDataCur" cursor must be pointing to the row that is to be
|
||||||
** deleted. Or, for WITHOUT ROWID tables, the iCur+i cursor for
|
** deleted.
|
||||||
** the PRIMARY KEY index must be pointing to the row to that is
|
|
||||||
** to be deleted.
|
|
||||||
*/
|
*/
|
||||||
void sqlite3GenerateRowIndexDelete(
|
void sqlite3GenerateRowIndexDelete(
|
||||||
Parse *pParse, /* Parsing and code generating context */
|
Parse *pParse, /* Parsing and code generating context */
|
||||||
Table *pTab, /* Table containing the row to be deleted */
|
Table *pTab, /* Table containing the row to be deleted */
|
||||||
int iCur, /* Cursor number for the table */
|
int iDataCur, /* Cursor of table holding data. */
|
||||||
|
int iIdxCur, /* First index cursor */
|
||||||
int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
|
int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
|
||||||
){
|
){
|
||||||
int i;
|
int i;
|
||||||
@@ -665,11 +672,11 @@ void sqlite3GenerateRowIndexDelete(
|
|||||||
Index *pPk;
|
Index *pPk;
|
||||||
|
|
||||||
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
||||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||||
if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
|
if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
|
||||||
if( pIdx==pPk ) continue;
|
if( pIdx==pPk ) continue;
|
||||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 1, &iPartIdxLabel);
|
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel);
|
||||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iCur+i, r1,
|
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
||||||
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
||||||
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
||||||
}
|
}
|
||||||
@@ -679,7 +686,8 @@ void sqlite3GenerateRowIndexDelete(
|
|||||||
** Generate code that will assemble an index key and stores it in register
|
** Generate code that will assemble an index key and stores it in register
|
||||||
** regOut. The key with be for index pIdx which is an index on pTab.
|
** regOut. The key with be for index pIdx which is an index on pTab.
|
||||||
** iCur is the index of a cursor open on the pTab table and pointing to
|
** iCur is the index of a cursor open on the pTab table and pointing to
|
||||||
** the entry that needs indexing.
|
** the entry that needs indexing. If pTab is a WITHOUT ROWID table, then
|
||||||
|
** iCur must be the cursor of the PRIMARY KEY index.
|
||||||
**
|
**
|
||||||
** Return a register number which is the first in a block of
|
** Return a register number which is the first in a block of
|
||||||
** registers that holds the elements of the index key. The
|
** registers that holds the elements of the index key. The
|
||||||
@@ -696,7 +704,7 @@ void sqlite3GenerateRowIndexDelete(
|
|||||||
int sqlite3GenerateIndexKey(
|
int sqlite3GenerateIndexKey(
|
||||||
Parse *pParse, /* Parsing context */
|
Parse *pParse, /* Parsing context */
|
||||||
Index *pIdx, /* The index for which to generate a key */
|
Index *pIdx, /* The index for which to generate a key */
|
||||||
int iCur, /* Cursor number for the pIdx->pTable table */
|
int iDataCur, /* Cursor number from which to take column data */
|
||||||
int regOut, /* Put the new key into this register if not 0 */
|
int regOut, /* Put the new key into this register if not 0 */
|
||||||
int prefixOnly, /* Compute only a unique prefix of the key */
|
int prefixOnly, /* Compute only a unique prefix of the key */
|
||||||
int *piPartIdxLabel /* OUT: Jump to this label to skip partial index */
|
int *piPartIdxLabel /* OUT: Jump to this label to skip partial index */
|
||||||
@@ -711,7 +719,7 @@ int sqlite3GenerateIndexKey(
|
|||||||
if( piPartIdxLabel ){
|
if( piPartIdxLabel ){
|
||||||
if( pIdx->pPartIdxWhere ){
|
if( pIdx->pPartIdxWhere ){
|
||||||
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
|
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
|
||||||
pParse->iPartIdxTab = iCur;
|
pParse->iPartIdxTab = iDataCur;
|
||||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
||||||
SQLITE_JUMPIFNULL);
|
SQLITE_JUMPIFNULL);
|
||||||
}else{
|
}else{
|
||||||
@@ -725,9 +733,9 @@ int sqlite3GenerateIndexKey(
|
|||||||
i16 idx = pIdx->aiColumn[j];
|
i16 idx = pIdx->aiColumn[j];
|
||||||
if( pPk ) idx = sqlite3ColumnOfIndex(pPk, idx);
|
if( pPk ) idx = sqlite3ColumnOfIndex(pPk, idx);
|
||||||
if( idx<0 || idx==pTab->iPKey ){
|
if( idx<0 || idx==pTab->iPKey ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+j);
|
sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regBase+j);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j);
|
sqlite3VdbeAddOp3(v, OP_Column, iDataCur, idx, regBase+j);
|
||||||
sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[j], -1);
|
sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[j], -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
264
src/insert.c
264
src/insert.c
@@ -15,13 +15,13 @@
|
|||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code that will open table pTab for reading or writing
|
** Generate code that will
|
||||||
** on cursor iCur.
|
|
||||||
**
|
**
|
||||||
** Always acquire a table lock. Always do the open for rowid tables.
|
** (1) acquire a lock for table pTab then
|
||||||
** For WITHOUT ROWID tables, only do read opens, and then open the
|
** (2) open pTab as cursor iCur.
|
||||||
** PRIMARY KEY index, not the main table, since the main table doesn't
|
**
|
||||||
** exist.
|
** If pTab is a WITHOUT ROWID table, then it is the PRIMARY KEY index
|
||||||
|
** for that table that is actually opened.
|
||||||
*/
|
*/
|
||||||
void sqlite3OpenTable(
|
void sqlite3OpenTable(
|
||||||
Parse *p, /* Generate code into this VDBE */
|
Parse *p, /* Generate code into this VDBE */
|
||||||
@@ -38,7 +38,7 @@ void sqlite3OpenTable(
|
|||||||
if( HasRowid(pTab) ){
|
if( HasRowid(pTab) ){
|
||||||
sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol);
|
sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol);
|
||||||
VdbeComment((v, "%s", pTab->zName));
|
VdbeComment((v, "%s", pTab->zName));
|
||||||
}else if( opcode==OP_OpenRead ){
|
}else{
|
||||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||||
assert( pPk!=0 );
|
assert( pPk!=0 );
|
||||||
assert( pPk->tnum=pTab->tnum );
|
assert( pPk->tnum=pTab->tnum );
|
||||||
@@ -553,7 +553,8 @@ void sqlite3Insert(
|
|||||||
Index *pIdx; /* For looping over indices of the table */
|
Index *pIdx; /* For looping over indices of the table */
|
||||||
int nColumn; /* Number of columns in the data */
|
int nColumn; /* Number of columns in the data */
|
||||||
int nHidden = 0; /* Number of hidden columns if TABLE is virtual */
|
int nHidden = 0; /* Number of hidden columns if TABLE is virtual */
|
||||||
int baseCur = 0; /* VDBE Cursor number for pTab */
|
int iDataCur = 0; /* VDBE cursor that is the main data repository */
|
||||||
|
int iIdxCur = 0; /* First index cursor */
|
||||||
int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
||||||
int endOfLoop; /* Label for the end of the insertion loop */
|
int endOfLoop; /* Label for the end of the insertion loop */
|
||||||
int useTempTable = 0; /* Store SELECT results in intermediate table */
|
int useTempTable = 0; /* Store SELECT results in intermediate table */
|
||||||
@@ -818,9 +819,8 @@ void sqlite3Insert(
|
|||||||
/* If this is not a view, open the table and and all indices */
|
/* If this is not a view, open the table and and all indices */
|
||||||
if( !isView ){
|
if( !isView ){
|
||||||
int nIdx;
|
int nIdx;
|
||||||
|
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1,
|
||||||
baseCur = pParse->nTab - withoutRowid;
|
&iDataCur, &iIdxCur);
|
||||||
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, baseCur, -1, OP_OpenWrite);
|
|
||||||
aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
|
aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
|
||||||
if( aRegIdx==0 ){
|
if( aRegIdx==0 ){
|
||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
@@ -959,7 +959,7 @@ void sqlite3Insert(
|
|||||||
if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
|
if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
|
||||||
appendFlag = 1;
|
appendFlag = 1;
|
||||||
pOp->opcode = OP_NewRowid;
|
pOp->opcode = OP_NewRowid;
|
||||||
pOp->p1 = baseCur;
|
pOp->p1 = iDataCur;
|
||||||
pOp->p2 = regRowid;
|
pOp->p2 = regRowid;
|
||||||
pOp->p3 = regAutoinc;
|
pOp->p3 = regAutoinc;
|
||||||
}
|
}
|
||||||
@@ -971,7 +971,7 @@ void sqlite3Insert(
|
|||||||
int j1;
|
int j1;
|
||||||
if( !IsVirtual(pTab) ){
|
if( !IsVirtual(pTab) ){
|
||||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
|
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
|
||||||
sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
|
sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
|
||||||
sqlite3VdbeJumpHere(v, j1);
|
sqlite3VdbeJumpHere(v, j1);
|
||||||
}else{
|
}else{
|
||||||
j1 = sqlite3VdbeCurrentAddr(v);
|
j1 = sqlite3VdbeCurrentAddr(v);
|
||||||
@@ -982,7 +982,7 @@ void sqlite3Insert(
|
|||||||
}else if( IsVirtual(pTab) || withoutRowid ){
|
}else if( IsVirtual(pTab) || withoutRowid ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
|
sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
|
||||||
appendFlag = 1;
|
appendFlag = 1;
|
||||||
}
|
}
|
||||||
autoIncStep(pParse, regAutoinc, regRowid);
|
autoIncStep(pParse, regAutoinc, regRowid);
|
||||||
@@ -1039,13 +1039,12 @@ void sqlite3Insert(
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int isReplace; /* Set to true if constraints may cause a replace */
|
int isReplace; /* Set to true if constraints may cause a replace */
|
||||||
sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx,
|
sqlite3GenerateConstraintChecks(pParse, pTab, iDataCur, iIdxCur,
|
||||||
ipkColumn>=0, 0, onError, endOfLoop, &isReplace
|
regIns, aRegIdx, ipkColumn>=0, 0, onError, endOfLoop, &isReplace
|
||||||
);
|
);
|
||||||
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
|
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
|
||||||
sqlite3CompleteInsertion(
|
sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
|
||||||
pParse, pTab, baseCur, regIns, aRegIdx, 0, appendFlag, isReplace==0
|
regIns, aRegIdx, 0, appendFlag, isReplace==0);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1076,9 +1075,9 @@ void sqlite3Insert(
|
|||||||
|
|
||||||
if( !IsVirtual(pTab) && !isView ){
|
if( !IsVirtual(pTab) && !isView ){
|
||||||
/* Close all tables opened */
|
/* Close all tables opened */
|
||||||
if( !withoutRowid ) sqlite3VdbeAddOp1(v, OP_Close, baseCur);
|
if( iDataCur<iIdxCur ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
|
||||||
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
for(idx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
||||||
sqlite3VdbeAddOp1(v, OP_Close, idx+baseCur);
|
sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1123,42 +1122,6 @@ insert_cleanup:
|
|||||||
#undef tmask
|
#undef tmask
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
** If regFirst is a set of value for a table row in table order and pPk
|
|
||||||
** is the PRIMARY KEY index for that table, then return the index of the
|
|
||||||
** first register in a contiguous array of registers that are the primary
|
|
||||||
** key values for the table row.
|
|
||||||
**
|
|
||||||
** For the common cases where the PRIMARY KEY has only a single value or
|
|
||||||
** where a multi-value PRIMARY KEY is contiguous in table order, this
|
|
||||||
** routine simply returns a pointer into the regFirst array. But if there
|
|
||||||
** is a multi-value PRIMARY KEY with the values out-of-order, this routine
|
|
||||||
** has to generate code that will copy PRIMARY KEY values into newly
|
|
||||||
** allocated contiguous registers.
|
|
||||||
*/
|
|
||||||
static int sqlite3PrimaryKeyRegisters(Parse *pParse, Index *pPk, int regFirst){
|
|
||||||
int i;
|
|
||||||
int nKeyCol = pPk->nKeyCol;
|
|
||||||
int regPk;
|
|
||||||
assert( pParse->pVdbe!=0 );
|
|
||||||
if( nKeyCol==1 ){
|
|
||||||
return regFirst + pPk->aiColumn[0];
|
|
||||||
}
|
|
||||||
for(i=1; i<nKeyCol; i++){
|
|
||||||
if( pPk->aiColumn[i-1]+1!=pPk->aiColumn[i] ) break;
|
|
||||||
}
|
|
||||||
if( i==nKeyCol ){
|
|
||||||
return regFirst + pPk->aiColumn[0];
|
|
||||||
}
|
|
||||||
regPk = pParse->nMem+1;
|
|
||||||
pParse->nMem += nKeyCol;
|
|
||||||
for(i=0; i<nKeyCol; i++){
|
|
||||||
int x = pPk->aiColumn[i];
|
|
||||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, regFirst+x, regPk+i);
|
|
||||||
}
|
|
||||||
return regPk;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Locate the "principle btree" for a table. This is the table itself for
|
** Locate the "principle btree" for a table. This is the table itself for
|
||||||
** ordinary tables, but for WITHOUT ROWID tables, the principle btree is the
|
** ordinary tables, but for WITHOUT ROWID tables, the principle btree is the
|
||||||
@@ -1274,7 +1237,8 @@ void sqlite3PrincipleBtree(
|
|||||||
void sqlite3GenerateConstraintChecks(
|
void sqlite3GenerateConstraintChecks(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
Table *pTab, /* the table into which we are inserting */
|
Table *pTab, /* the table into which we are inserting */
|
||||||
int baseCur, /* A read/write cursor pointing at pTab */
|
int iDataCur, /* Cursor of the canonical data tree */
|
||||||
|
int iIdxCur, /* First index cursor */
|
||||||
int regRowid, /* First register in a range holding values to insert */
|
int regRowid, /* First register in a range holding values to insert */
|
||||||
int *aRegIdx, /* Register used by each index. 0 for unused indices */
|
int *aRegIdx, /* Register used by each index. 0 for unused indices */
|
||||||
int pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
|
int pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
|
||||||
@@ -1288,15 +1252,13 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
int nCol; /* Number of columns */
|
int nCol; /* Number of columns */
|
||||||
int onError; /* Conflict resolution strategy */
|
int onError; /* Conflict resolution strategy */
|
||||||
int j1; /* Addresss of jump instruction */
|
int j1; /* Addresss of jump instruction */
|
||||||
|
int ix; /* Index loop counter */
|
||||||
int regData; /* Register containing first data column */
|
int regData; /* Register containing first data column */
|
||||||
int iCur; /* Table cursor number */
|
|
||||||
Index *pIdx; /* Pointer to one of the indices */
|
Index *pIdx; /* Pointer to one of the indices */
|
||||||
Index *pPk = 0; /* The PRIMARY KEY index */
|
Index *pPk = 0; /* The PRIMARY KEY index */
|
||||||
sqlite3 *db; /* Database connection */
|
sqlite3 *db; /* Database connection */
|
||||||
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
||||||
int regOldPk; /* Previous rowid or PRIMARY KEY value */
|
int regOldPk; /* Previous rowid or PRIMARY KEY value */
|
||||||
int regNewPk = 0; /* New PRIMARY KEY value */
|
|
||||||
int pkCur = 0; /* Cursor used by the PRIMARY KEY */
|
|
||||||
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
||||||
|
|
||||||
regOldPk = (pkChng && isUpdate) ? pkChng : regRowid;
|
regOldPk = (pkChng && isUpdate) ? pkChng : regRowid;
|
||||||
@@ -1309,12 +1271,17 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
|
|
||||||
/* For WITHOUT ROWID tables, we'll need to know the Index and the cursor
|
/* For WITHOUT ROWID tables, we'll need to know the Index and the cursor
|
||||||
** number for the PRIMARY KEY index */
|
** number for the PRIMARY KEY index */
|
||||||
sqlite3PrincipleBtree(pTab, baseCur, &pPk, &pkCur);
|
if( HasRowid(pTab) ){
|
||||||
nPkField = pPk ? pPk->nKeyCol : 1;
|
pPk = 0;
|
||||||
|
nPkField = 1;
|
||||||
|
}else{
|
||||||
|
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||||
|
nPkField = pPk->nKeyCol;
|
||||||
|
}
|
||||||
|
|
||||||
/* Record that this module has started */
|
/* Record that this module has started */
|
||||||
VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
|
VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
|
||||||
baseCur, regRowid, pkChng, regOldPk, pkCur));
|
iDataCur, iIdxCur, regRowid, pkChng, regOldPk));
|
||||||
|
|
||||||
/* Test all NOT NULL constraints.
|
/* Test all NOT NULL constraints.
|
||||||
*/
|
*/
|
||||||
@@ -1409,7 +1376,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
if( isUpdate ){
|
if( isUpdate ){
|
||||||
sqlite3VdbeAddOp3(v, OP_Eq, regRowid, addrRowidOk, pkChng);
|
sqlite3VdbeAddOp3(v, OP_Eq, regRowid, addrRowidOk, pkChng);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, addrRowidOk, regRowid);
|
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regRowid);
|
||||||
switch( onError ){
|
switch( onError ){
|
||||||
default: {
|
default: {
|
||||||
onError = OE_Abort;
|
onError = OE_Abort;
|
||||||
@@ -1451,12 +1418,11 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
}
|
}
|
||||||
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
|
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
|
||||||
sqlite3MultiWrite(pParse);
|
sqlite3MultiWrite(pParse);
|
||||||
sqlite3GenerateRowDelete(
|
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
||||||
pParse, pTab, pTrigger, baseCur, regRowid, 0, 0, OE_Replace
|
regRowid, 1, 0, OE_Replace);
|
||||||
);
|
|
||||||
}else if( pTab->pIndex ){
|
}else if( pTab->pIndex ){
|
||||||
sqlite3MultiWrite(pParse);
|
sqlite3MultiWrite(pParse);
|
||||||
sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
|
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
|
||||||
}
|
}
|
||||||
seenReplace = 1;
|
seenReplace = 1;
|
||||||
break;
|
break;
|
||||||
@@ -1474,16 +1440,16 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
** index and making sure that duplicate entries do not already exist.
|
** index and making sure that duplicate entries do not already exist.
|
||||||
** Compute the revised record entries for indices as we go.
|
** Compute the revised record entries for indices as we go.
|
||||||
*/
|
*/
|
||||||
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
|
for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
|
||||||
int regIdx;
|
int regIdx;
|
||||||
int regR;
|
int regR;
|
||||||
int idxCur = baseCur+iCur+1;
|
int iThisCur = iIdxCur+ix;
|
||||||
int addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
int addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
||||||
|
|
||||||
if( aRegIdx[iCur]==0 ) continue; /* Skip indices that do not change */
|
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
||||||
|
|
||||||
if( pIdx->pPartIdxWhere ){
|
if( pIdx->pPartIdxWhere ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
|
||||||
pParse->ckBase = regData;
|
pParse->ckBase = regData;
|
||||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
|
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
|
||||||
SQLITE_JUMPIFNULL);
|
SQLITE_JUMPIFNULL);
|
||||||
@@ -1493,21 +1459,22 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
/* Create a key for accessing the index entry */
|
/* Create a key for accessing the index entry */
|
||||||
regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
|
regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
|
||||||
for(i=0; i<pIdx->nColumn; i++){
|
for(i=0; i<pIdx->nColumn; i++){
|
||||||
i16 idx = pIdx->aiColumn[i];
|
i16 iField = pIdx->aiColumn[i];
|
||||||
if( idx<0 || idx==pTab->iPKey ){
|
if( iField<0 || iField==pTab->iPKey ){
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
|
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i);
|
sqlite3VdbeAddOp2(v, OP_SCopy, regData+iField, regIdx+i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[iCur]);
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
|
||||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
|
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
|
||||||
|
VdbeComment((v, "for %s", pIdx->zName));
|
||||||
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
|
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
|
||||||
|
|
||||||
/* Find out what action to take in case there is an indexing conflict */
|
/* Find out what action to take in case there is an indexing conflict */
|
||||||
onError = pIdx->onError;
|
onError = pIdx->onError;
|
||||||
if( onError==OE_None ){
|
if( onError==OE_None ){
|
||||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nKeyCol+1);
|
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
||||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||||
continue; /* pIdx is not a UNIQUE index */
|
continue; /* pIdx is not a UNIQUE index */
|
||||||
}
|
}
|
||||||
@@ -1523,46 +1490,48 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
|
|
||||||
/* Check to see if the new index entry will be unique */
|
/* Check to see if the new index entry will be unique */
|
||||||
regR = sqlite3GetTempRange(pParse, nPkField);
|
regR = sqlite3GetTempRange(pParse, nPkField);
|
||||||
sqlite3VdbeAddOp4Int(v, OP_NoConflict, idxCur, addrUniqueOk,
|
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
|
||||||
regIdx, pIdx->nKeyCol);
|
regIdx, pIdx->nKeyCol);
|
||||||
#if 0
|
|
||||||
if( !isUpdate ){
|
|
||||||
/* A pre-existing row is always a conflict on an insert */
|
|
||||||
}else
|
|
||||||
#endif
|
|
||||||
if( HasRowid(pTab) ){
|
if( HasRowid(pTab) ){
|
||||||
/* Conflict only if the rowid of the existing index entry
|
/* Conflict only if the rowid of the existing index entry
|
||||||
** is different from old-rowid */
|
** is different from old-rowid */
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, idxCur, regR);
|
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
||||||
sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk);
|
sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk);
|
||||||
}else if( pIdx->autoIndex==2 ){
|
|
||||||
/* For PRIMARY KEY index on a WITHOUT ROWID table, conflict only
|
|
||||||
** if the PRIMARY KEY has changed. If the PRIMARY KEY is unchanged,
|
|
||||||
** then the matching entry is just the original row that is being
|
|
||||||
** modified. */
|
|
||||||
if( onError!=OE_Replace ){
|
|
||||||
int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
|
|
||||||
for(i=0; i<pPk->nKeyCol-1; i++){
|
|
||||||
sqlite3VdbeAddOp3(v, OP_Ne, regOldPk+pPk->aiColumn[i]+1,
|
|
||||||
addrPkConflict, regIdx+i);
|
|
||||||
}
|
|
||||||
sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i]+1,
|
|
||||||
addrUniqueOk, regIdx+i);
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
/* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
|
/* Extract the PRIMARY KEY from the end of the index entry and
|
||||||
** PRIMARY KEY value of the match is different from the old PRIMARY KEY
|
** store it in register regR..regR+nPk-1 */
|
||||||
** value from before the update. */
|
for(i=0; i<pPk->nKeyCol; i++){
|
||||||
int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol*2;
|
int x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
|
||||||
assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
|
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
|
||||||
for(i=0; i<pPk->nKeyCol-1; i++){
|
VdbeComment((v, "%s.%s", pTab->zName,
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i);
|
pTab->aCol[pPk->aiColumn[i]].zName));
|
||||||
sqlite3VdbeAddOp3(v, OP_Ne,
|
}
|
||||||
regOldPk+pPk->aiColumn[i], addrConflict, regR+i);
|
if( pIdx->autoIndex==2 ){
|
||||||
|
/* For a PRIMARY KEY index on a WITHOUT ROWID table, always conflict
|
||||||
|
** on an INSERT. On an UPDATE, only conflict if the PRIMARY KEY
|
||||||
|
** has changed. */
|
||||||
|
if( isUpdate ){
|
||||||
|
int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
|
||||||
|
for(i=0; i<pPk->nKeyCol-1; i++){
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Ne, regOldPk+pPk->aiColumn[i]+1,
|
||||||
|
addrPkConflict, regIdx+i);
|
||||||
|
}
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i]+1,
|
||||||
|
addrUniqueOk, regIdx+i);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
/* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
|
||||||
|
** PRIMARY KEY value of the match is different from the old PRIMARY KEY
|
||||||
|
** value from before the update. */
|
||||||
|
int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
|
||||||
|
assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
|
||||||
|
for(i=0; i<pPk->nKeyCol-1; i++){
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Ne,
|
||||||
|
regOldPk+pPk->aiColumn[i], addrConflict, regR+i);
|
||||||
|
}
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Eq,
|
||||||
|
regOldPk+pPk->aiColumn[i], addrUniqueOk, regR+i);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i);
|
|
||||||
sqlite3VdbeAddOp3(v, OP_Eq,
|
|
||||||
regOldPk+pPk->aiColumn[i], addrUniqueOk, regR+i);
|
|
||||||
}
|
}
|
||||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
||||||
|
|
||||||
@@ -1607,19 +1576,14 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
if( db->flags&SQLITE_RecTriggers ){
|
if( db->flags&SQLITE_RecTriggers ){
|
||||||
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
||||||
}
|
}
|
||||||
if( pIdx==pPk ){
|
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
||||||
/*sqlite3VdbeAddOp3(v, OP_IdxDelete, pkCur, regIdx, pIdx->nColumn);*/
|
regR, nPkField, 0, OE_Replace);
|
||||||
sqlite3VdbeAddOp1(v, OP_Delete, pkCur);
|
|
||||||
}else{
|
|
||||||
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, baseCur,
|
|
||||||
regR, nPkField, 0, OE_Replace);
|
|
||||||
}
|
|
||||||
seenReplace = 1;
|
seenReplace = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||||
sqlite3ReleaseTempReg(pParse, regR);
|
sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pbMayReplace ){
|
if( pbMayReplace ){
|
||||||
@@ -1640,7 +1604,8 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
void sqlite3CompleteInsertion(
|
void sqlite3CompleteInsertion(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
Table *pTab, /* the table into which we are inserting */
|
Table *pTab, /* the table into which we are inserting */
|
||||||
int baseCur, /* Index of a read/write cursor pointing at pTab */
|
int iDataCur, /* Cursor of the canonical data source */
|
||||||
|
int iIdxCur, /* First index cursor */
|
||||||
int regRowid, /* Range of content */
|
int regRowid, /* Range of content */
|
||||||
int *aRegIdx, /* Register used by each index. 0 for unused indices */
|
int *aRegIdx, /* Register used by each index. 0 for unused indices */
|
||||||
int isUpdate, /* True for UPDATE, False for INSERT */
|
int isUpdate, /* True for UPDATE, False for INSERT */
|
||||||
@@ -1662,7 +1627,7 @@ void sqlite3CompleteInsertion(
|
|||||||
if( pIdx->pPartIdxWhere ){
|
if( pIdx->pPartIdxWhere ){
|
||||||
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
|
||||||
if( useSeekResult ){
|
if( useSeekResult ){
|
||||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||||
}
|
}
|
||||||
@@ -1685,7 +1650,7 @@ void sqlite3CompleteInsertion(
|
|||||||
if( useSeekResult ){
|
if( useSeekResult ){
|
||||||
pik_flags |= OPFLAG_USESEEKRESULT;
|
pik_flags |= OPFLAG_USESEEKRESULT;
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
|
sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regRowid);
|
||||||
if( !pParse->nested ){
|
if( !pParse->nested ){
|
||||||
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
||||||
}
|
}
|
||||||
@@ -1693,43 +1658,64 @@ void sqlite3CompleteInsertion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code that will open cursors for a table and for all
|
** Allocate cursors for the pTab table and all its indices and generate
|
||||||
** indices of that table. The "baseCur" parameter is the cursor number used
|
** code to open and initialized those cursors.
|
||||||
** for the table. Indices are opened on subsequent cursors.
|
|
||||||
**
|
**
|
||||||
** Return the number of indices on the table.
|
** The cursor for the object that contains the complete data (normally
|
||||||
|
** the table itself, but the PRIMARY KEY index in the case of a WITHOUT
|
||||||
|
** ROWID table) is returned in *piDataCur. The first index cursor is
|
||||||
|
** returned in *piIdxCur. The number of indices is returned.
|
||||||
|
**
|
||||||
|
** Use iBase as the first cursor (either the *piDataCur for rowid tables
|
||||||
|
** or the first index for WITHOUT ROWID tables) if it is non-negative.
|
||||||
|
** If iBase is negative, then allocate the next available cursor.
|
||||||
|
**
|
||||||
|
** For a rowid table, *piDataCur will be exactly one less than *piIdxCur.
|
||||||
|
** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range
|
||||||
|
** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the
|
||||||
|
** pTab->pIndex list.
|
||||||
*/
|
*/
|
||||||
int sqlite3OpenTableAndIndices(
|
int sqlite3OpenTableAndIndices(
|
||||||
Parse *pParse, /* Parsing context */
|
Parse *pParse, /* Parsing context */
|
||||||
Table *pTab, /* Table to be opened */
|
Table *pTab, /* Table to be opened */
|
||||||
int baseCur, /* Cursor number assigned to the table */
|
int op, /* OP_OpenRead or OP_OpenWrite */
|
||||||
int pkCur, /* Cursor number for the primary key */
|
int iBase, /* Use this for the table cursor, if there is one */
|
||||||
int op /* OP_OpenRead or OP_OpenWrite */
|
int *piDataCur, /* Write the database source cursor number here */
|
||||||
|
int *piIdxCur /* Write the first index cursor number here */
|
||||||
){
|
){
|
||||||
int i;
|
int i;
|
||||||
int iDb;
|
int iDb;
|
||||||
Index *pIdx;
|
Index *pIdx;
|
||||||
Vdbe *v;
|
Vdbe *v;
|
||||||
|
|
||||||
if( IsVirtual(pTab) ) return 0;
|
assert( op==OP_OpenRead || op==OP_OpenWrite );
|
||||||
|
if( IsVirtual(pTab) ){
|
||||||
|
*piDataCur = 0;
|
||||||
|
*piIdxCur = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
if( pkCur<0 ){
|
if( iBase<0 ) iBase = pParse->nTab;
|
||||||
sqlite3OpenTable(pParse, baseCur, iDb, pTab, op);
|
if( HasRowid(pTab) ){
|
||||||
|
*piDataCur = iBase++;
|
||||||
|
sqlite3OpenTable(pParse, *piDataCur, iDb, pTab, op);
|
||||||
}else{
|
}else{
|
||||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
|
||||||
}
|
}
|
||||||
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
*piIdxCur = iBase;
|
||||||
|
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||||
int iCur = (pkCur>=0 && pIdx->autoIndex==2) ? pkCur : i+baseCur;
|
int iIdxCur = iBase++;
|
||||||
assert( pIdx->pSchema==pTab->pSchema );
|
assert( pIdx->pSchema==pTab->pSchema );
|
||||||
sqlite3VdbeAddOp4(v, op, iCur, pIdx->tnum, iDb,
|
if( pIdx->autoIndex==2 && !HasRowid(pTab) ) *piDataCur = iIdxCur;
|
||||||
|
sqlite3VdbeAddOp4(v, op, iIdxCur, pIdx->tnum, iDb,
|
||||||
(char*)pKey, P4_KEYINFO_HANDOFF);
|
(char*)pKey, P4_KEYINFO_HANDOFF);
|
||||||
VdbeComment((v, "%s", pIdx->zName));
|
VdbeComment((v, "%s", pIdx->zName));
|
||||||
}
|
}
|
||||||
if( pParse->nTab<=i+baseCur ) pParse->nTab = i+baseCur;
|
if( iBase>pParse->nTab ) pParse->nTab = iBase;
|
||||||
return i-1;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
17
src/pragma.c
17
src/pragma.c
@@ -1877,30 +1877,31 @@ void sqlite3Pragma(
|
|||||||
Table *pTab = sqliteHashData(x);
|
Table *pTab = sqliteHashData(x);
|
||||||
Index *pIdx, *pPk;
|
Index *pIdx, *pPk;
|
||||||
int loopTop;
|
int loopTop;
|
||||||
int pkCur;
|
int iDataCur, iIdxCur;
|
||||||
|
|
||||||
if( pTab->pIndex==0 ) continue;
|
if( pTab->pIndex==0 ) continue;
|
||||||
sqlite3PrincipleBtree(pTab, 1, &pPk, &pkCur);
|
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
||||||
pkCur = (pPk==0) ? -1 : 1;
|
|
||||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
|
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
|
||||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||||
sqlite3VdbeJumpHere(v, addr);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
sqlite3ExprCacheClear(pParse);
|
sqlite3ExprCacheClear(pParse);
|
||||||
sqlite3OpenTableAndIndices(pParse, pTab, 1, pkCur, OP_OpenRead);
|
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead,
|
||||||
|
1, &iDataCur, &iIdxCur);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
|
||||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
|
||||||
}
|
}
|
||||||
pParse->nMem = MAX(pParse->nMem, 8+j);
|
pParse->nMem = MAX(pParse->nMem, 8+j);
|
||||||
sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
|
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0);
|
||||||
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
|
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
|
||||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||||
int jmp2, jmp3, jmp4;
|
int jmp2, jmp3, jmp4;
|
||||||
int r1;
|
int r1;
|
||||||
if( pPk==pIdx ) continue;
|
if( pPk==pIdx ) continue;
|
||||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 0, 0, &jmp3);
|
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3);
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
|
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
|
||||||
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, j+2, 0, r1, pIdx->nKeyCol+1);
|
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1,
|
||||||
|
pIdx->nKeyCol+1);
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
||||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
|
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
|
||||||
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
||||||
@@ -1926,7 +1927,7 @@ void sqlite3Pragma(
|
|||||||
addr = sqlite3VdbeCurrentAddr(v);
|
addr = sqlite3VdbeCurrentAddr(v);
|
||||||
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2);
|
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2);
|
||||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Count, j+2, 3);
|
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
|
||||||
sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3);
|
sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3);
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
||||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
|
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
|
||||||
|
@@ -2919,14 +2919,14 @@ int sqlite3ExprCanBeNull(const Expr*);
|
|||||||
void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
|
void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
|
||||||
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
|
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
|
||||||
int sqlite3IsRowid(const char*);
|
int sqlite3IsRowid(const char*);
|
||||||
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,i16,u8,u8);
|
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8);
|
||||||
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
|
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
|
||||||
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);
|
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);
|
||||||
void sqlite3PrincipleBtree(Table*,int,Index**,int*);
|
void sqlite3PrincipleBtree(Table*,int,Index**,int*);
|
||||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
|
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,int,
|
||||||
int*,int,int,int,int,int*);
|
int*,int,int,int,int,int*);
|
||||||
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
|
void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
|
||||||
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int);
|
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int*, int*);
|
||||||
void sqlite3BeginWriteOperation(Parse*, int, int);
|
void sqlite3BeginWriteOperation(Parse*, int, int);
|
||||||
void sqlite3MultiWrite(Parse*);
|
void sqlite3MultiWrite(Parse*);
|
||||||
void sqlite3MayAbort(Parse*);
|
void sqlite3MayAbort(Parse*);
|
||||||
|
14
src/update.c
14
src/update.c
@@ -109,7 +109,6 @@ void sqlite3Update(
|
|||||||
** an expression for the i-th column of the table.
|
** an expression for the i-th column of the table.
|
||||||
** aXRef[i]==-1 if the i-th column is not changed. */
|
** aXRef[i]==-1 if the i-th column is not changed. */
|
||||||
int chngRowid; /* True if the record number is being changed */
|
int chngRowid; /* True if the record number is being changed */
|
||||||
int chngPk; /* The PRIMARY KEY of a WITHOUT ROWID table changed */
|
|
||||||
Expr *pRowidExpr = 0; /* Expression defining the new record number */
|
Expr *pRowidExpr = 0; /* Expression defining the new record number */
|
||||||
int openAll = 0; /* True if all indices need to be opened */
|
int openAll = 0; /* True if all indices need to be opened */
|
||||||
AuthContext sContext; /* The authorization context */
|
AuthContext sContext; /* The authorization context */
|
||||||
@@ -202,7 +201,7 @@ void sqlite3Update(
|
|||||||
** column to be updated, make sure we have authorization to change
|
** column to be updated, make sure we have authorization to change
|
||||||
** that column.
|
** that column.
|
||||||
*/
|
*/
|
||||||
chngPk = chngRowid = 0;
|
chngRowid = 0;
|
||||||
for(i=0; i<pChanges->nExpr; i++){
|
for(i=0; i<pChanges->nExpr; i++){
|
||||||
if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
|
if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
|
||||||
goto update_cleanup;
|
goto update_cleanup;
|
||||||
@@ -212,8 +211,6 @@ void sqlite3Update(
|
|||||||
if( j==pTab->iPKey ){
|
if( j==pTab->iPKey ){
|
||||||
chngRowid = 1;
|
chngRowid = 1;
|
||||||
pRowidExpr = pChanges->a[i].pExpr;
|
pRowidExpr = pChanges->a[i].pExpr;
|
||||||
}else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
|
|
||||||
chngPk = 1;
|
|
||||||
}
|
}
|
||||||
aXRef[j] = i;
|
aXRef[j] = i;
|
||||||
break;
|
break;
|
||||||
@@ -526,7 +523,7 @@ void sqlite3Update(
|
|||||||
int j1; /* Address of jump instruction */
|
int j1; /* Address of jump instruction */
|
||||||
|
|
||||||
/* Do constraint checks. */
|
/* Do constraint checks. */
|
||||||
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
|
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, iCur+1, regNewRowid,
|
||||||
aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0);
|
aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0);
|
||||||
|
|
||||||
/* Do FK constraint checks. */
|
/* Do FK constraint checks. */
|
||||||
@@ -536,10 +533,10 @@ void sqlite3Update(
|
|||||||
|
|
||||||
/* Delete the index entries associated with the current record. */
|
/* Delete the index entries associated with the current record. */
|
||||||
if( pPk ){
|
if( pPk ){
|
||||||
/*j1 = sqlite3VdbeAddOp3(v, OP_NotFound, pkCur, */
|
j1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, pkCur, 0, regOldRowid, 1);
|
||||||
}else{
|
}else{
|
||||||
j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
|
j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
|
||||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
|
sqlite3GenerateRowIndexDelete(pParse, pTab, pkCur, iCur+1, aRegIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If changing the record number, delete the old record. */
|
/* If changing the record number, delete the old record. */
|
||||||
@@ -553,7 +550,8 @@ void sqlite3Update(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the new index entries and the new record. */
|
/* Insert the new index entries and the new record. */
|
||||||
sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, 0, 0);
|
sqlite3CompleteInsertion(pParse, pTab, iCur, iCur+1,
|
||||||
|
regNewRowid, aRegIdx, 1, 0, 0);
|
||||||
|
|
||||||
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
||||||
** handle rows (possibly in other tables) that refer via a foreign key
|
** handle rows (possibly in other tables) that refer via a foreign key
|
||||||
|
@@ -1119,7 +1119,7 @@ case OP_Copy: {
|
|||||||
** during the lifetime of the copy. Use OP_Copy to make a complete
|
** during the lifetime of the copy. Use OP_Copy to make a complete
|
||||||
** copy.
|
** copy.
|
||||||
*/
|
*/
|
||||||
case OP_SCopy: { /* in1, out2 */
|
case OP_SCopy: { /* out2 */
|
||||||
pIn1 = &aMem[pOp->p1];
|
pIn1 = &aMem[pOp->p1];
|
||||||
pOut = &aMem[pOp->p2];
|
pOut = &aMem[pOp->p2];
|
||||||
assert( pOut!=pIn1 );
|
assert( pOut!=pIn1 );
|
||||||
@@ -1127,7 +1127,6 @@ case OP_SCopy: { /* in1, out2 */
|
|||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
|
if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
|
||||||
#endif
|
#endif
|
||||||
REGISTER_TRACE(pOp->p2, pOut);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1133,7 +1133,7 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
|
|||||||
char *zP4;
|
char *zP4;
|
||||||
char zPtr[50];
|
char zPtr[50];
|
||||||
char zCom[100];
|
char zCom[100];
|
||||||
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-4s %.2X %s\n";
|
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
|
||||||
if( pOut==0 ) pOut = stdout;
|
if( pOut==0 ) pOut = stdout;
|
||||||
zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
|
zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
|
||||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||||
|
@@ -46,7 +46,6 @@ do_execsql_test without_rowid1-1.12 {
|
|||||||
SELECT *, '|' FROM t1 ORDER BY +b, d;
|
SELECT *, '|' FROM t1 ORDER BY +b, d;
|
||||||
} {dynamic juliet flipper command | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |}
|
} {dynamic juliet flipper command | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |}
|
||||||
|
|
||||||
if 0 {
|
|
||||||
# Trying to insert a duplicate PRIMARY KEY fails.
|
# Trying to insert a duplicate PRIMARY KEY fails.
|
||||||
#
|
#
|
||||||
do_test without_rowid1-1.21 {
|
do_test without_rowid1-1.21 {
|
||||||
@@ -61,6 +60,5 @@ do_execsql_test without_rowid1-1.22 {
|
|||||||
REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard');
|
REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard');
|
||||||
SELECT *, '|' FROM t1 ORDER BY c, a;
|
SELECT *, '|' FROM t1 ORDER BY c, a;
|
||||||
} {}
|
} {}
|
||||||
}
|
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
Reference in New Issue
Block a user