Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9612947

Browse files
author
drh
committed
Combine the rowid and WITHOUT ROWID paths for DELETE into a single path.
FossilOrigin-Name: c4734b881a64a9d21d03a14e901785797577fbd8
1 parent 156c791 commit 9612947

File tree

3 files changed

+115
-125
lines changed

3 files changed

+115
-125
lines changed

manifest

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
C The\sone-pass\soptimization\sis\snow\sworking\sfor\sDELETE\son\sWITHOUT\sROWID\stables.
2-
D 2013-11-16T20:45:01.087
1+
C Combine\sthe\srowid\sand\sWITHOUT\sROWID\spaths\sfor\sDELETE\sinto\sa\ssingle\spath.
2+
D 2013-11-16T22:48:52.173
33
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
44
F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
55
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -174,7 +174,7 @@ F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
174174
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
175175
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
176176
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
177-
F src/delete.c 35750d35fe9f174ccb98bae0d6627dcf83a7965a
177+
F src/delete.c 1bcc9d7f2e48cf9043a44bdbd333c38c2ef6676a
178178
F src/expr.c 1a295d8b0a2ba08919ad9300ebf7b67988ff4030
179179
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
180180
F src/fkey.c 78364daed38e26269c53ddb94c515bceac1063c6
@@ -1140,7 +1140,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
11401140
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
11411141
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
11421142
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
1143-
P 8f479a72758ab6fedb171ada612b1963143c32fa
1144-
R b6e41a6a6d551dfa6da0e7b0e42124eb
1143+
P e4d220a381388f900a95d1b656a82f14c837f92e
1144+
R d0df7aac2a46f76fbd08b30c4f269d2a
11451145
U drh
1146-
Z f0edfafd89abfe9d193a6a7758aa54ff
1146+
Z 2d947a1a8ff0ceb82e3a6fad03406bbd

manifest.uuid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
e4d220a381388f900a95d1b656a82f14c837f92e
1+
c4734b881a64a9d21d03a14e901785797577fbd8

src/delete.c

Lines changed: 108 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ void sqlite3DeleteFrom(
227227
Vdbe *v; /* The virtual database engine */
228228
Table *pTab; /* The table from which records will be deleted */
229229
const char *zDb; /* Name of database holding pTab */
230-
int end, addr = 0; /* A couple addresses of generated code */
231230
int i; /* Loop counter */
232231
WhereInfo *pWInfo; /* Information about the WHERE clause */
233232
Index *pIdx; /* For looping over indices of the table */
@@ -244,7 +243,18 @@ void sqlite3DeleteFrom(
244243
int okOnePass; /* True for one-pass algorithm without the FIFO */
245244
int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
246245
u8 *aToOpen = 0; /* Open cursor iTabCur+j if aToOpen[j] is true */
247-
246+
Index *pPk; /* The PRIMARY KEY index on the table */
247+
int iPk; /* First of nPk registerss holding PRIMARY KEY value */
248+
i16 nPk = 1; /* Number of components of the PRIMARY KEY */
249+
int iKey; /* Memory cell holding row key of to be deleted */
250+
i16 nKey; /* Number of memory cells of row key */
251+
int iEphCur = 0; /* Ephemeral table holding all primary key values */
252+
int iRowSet = 0; /* Register for rowset of rows to delete */
253+
int addrBypass = 0; /* Address of jump over the delete logic */
254+
int addrLoop = 0; /* Top of the delete loop */
255+
int addrDelete = 0; /* Jump directly to the delete logic */
256+
int addrEphOpen = 0; /* Instruction to open the Ephermeral table */
257+
248258
#ifndef SQLITE_OMIT_TRIGGER
249259
int isView; /* True if attempting to delete from a view */
250260
Trigger *pTrigger; /* List of table triggers, if required */
@@ -369,170 +379,150 @@ void sqlite3DeleteFrom(
369379
}
370380
}else
371381
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
372-
if( !HasRowid(pTab) ){
373-
/* There is a WHERE clause on a WITHOUT ROWID table.
382+
{
383+
if( HasRowid(pTab) ){
384+
/* For a rowid table, initialize the RowSet to an empty set */
385+
pPk = 0;
386+
nPk = 1;
387+
iRowSet = ++pParse->nMem;
388+
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
389+
}else{
390+
/* For a WITHOUT ROWID table, create an ephermeral table used to
391+
** hold all primary keys for rows to be deleted. */
392+
pPk = sqlite3PrimaryKeyIndex(pTab);
393+
assert( pPk!=0 );
394+
nPk = pPk->nKeyCol;
395+
iPk = pParse->nMem+1;
396+
pParse->nMem += nPk;
397+
iEphCur = pParse->nTab++;
398+
addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk);
399+
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
400+
}
401+
402+
/* Construct a query to find the rowid or primary key for every row
403+
** to be deleted, based on the WHERE clause.
374404
*/
375-
Index *pPk; /* The PRIMARY KEY index on the table */
376-
int iPk; /* First of nPk memory cells holding PRIMARY KEY value */
377-
int iEph; /* Ephemeral table holding all primary key values */
378-
int iKey; /* Key value inserting into iEph */
379-
i16 nPk; /* Number of components of the PRIMARY KEY */
380-
381-
pPk = sqlite3PrimaryKeyIndex(pTab);
382-
assert( pPk!=0 );
383-
nPk = pPk->nKeyCol;
384-
iPk = pParse->nMem+1;
385-
pParse->nMem += nPk;
386-
iKey = ++pParse->nMem;
387-
iEph = pParse->nTab++;
388-
389-
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
390-
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
391405
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,
392406
WHERE_ONEPASS_DESIRED, iTabCur+1);
393407
if( pWInfo==0 ) goto delete_from_cleanup;
394408
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
395-
for(i=0; i<nPk; i++){
396-
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i],iPk+i);
397-
}
409+
410+
/* Keep track of the number of rows to be deleted */
398411
if( db->flags & SQLITE_CountRows ){
399412
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
400413
}
401-
if( okOnePass ){
402-
aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
403-
if( aToOpen==0 ) goto delete_from_cleanup;
404-
memset(aToOpen, 1, nIdx+1);
405-
aToOpen[nIdx+1] = 0;
406-
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
407-
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
408-
sqlite3VdbeChangeToNoop(v, addr);
409-
addr = sqlite3VdbeAddOp0(v, OP_Goto);
414+
415+
/* Extract the rowid or primary key for the current row */
416+
if( pPk ){
417+
for(i=0; i<nPk; i++){
418+
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
419+
pPk->aiColumn[i], iPk+i);
420+
}
421+
iKey = iPk;
422+
nKey = nPk;
410423
}else{
411-
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
412-
sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
413-
sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, iKey);
414-
}
415-
sqlite3WhereEnd(pWInfo);
416-
if( okOnePass ){
417-
sqlite3VdbeAddOp0(v, OP_Halt);
418-
sqlite3VdbeJumpHere(v, addr);
419-
}
420-
421-
/* Open cursors for all indices of the table.
422-
*/
423-
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
424-
&iDataCur, &iIdxCur);
425-
426-
/* Loop over the primary keys to be deleted. */
427-
if( !okOnePass ){
428-
addr = sqlite3VdbeAddOp1(v, OP_Rewind, iEph);
429-
sqlite3VdbeAddOp2(v, OP_RowKey, iEph, iPk);
430-
}
431-
432-
/* Delete the row */
433-
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
434-
iPk, nPk*okOnePass, 1, OE_Default, okOnePass);
435-
436-
/* End of the delete loop */
437-
if( !okOnePass ){
438-
sqlite3VdbeAddOp2(v, OP_Next, iEph, addr+1);
439-
sqlite3VdbeJumpHere(v, addr);
440-
}
441-
442-
/* Close the cursors open on the table and its indexes. */
443-
assert( iDataCur>=iIdxCur );
444-
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
445-
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur+i);
446-
}
447-
}else{
448-
/* There is a WHERE clause on a rowid table. Run a loop that extracts
449-
** all rowids to be deleted into a RowSet.
450-
*/
451-
int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */
452-
int regRowid; /* Actual register containing rowids */
453-
454-
/* Collect rowids of every row to be deleted.
455-
*/
456-
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
457-
pWInfo = sqlite3WhereBegin(
458-
pParse, pTabList, pWhere, 0, 0,
459-
WHERE_DUPLICATES_OK|WHERE_ONEPASS_DESIRED, iTabCur+1
460-
);
461-
if( pWInfo==0 ) goto delete_from_cleanup;
462-
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
463-
if( db->flags & SQLITE_CountRows ){
464-
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
424+
iKey = pParse->nMem + 1;
425+
iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0);
426+
if( iKey>pParse->nMem ) pParse->nMem = iKey;
465427
}
466-
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur,
467-
pParse->nMem+1, 0);
468-
if( regRowid>pParse->nMem ) pParse->nMem = regRowid;
428+
469429
if( okOnePass ){
430+
/* For ONEPASS, no need to store the rowid/primary-key. There is only
431+
** one, so just keep it in its register(s) and fall through to the
432+
** delete code.
433+
*/
434+
nKey = nPk; /* OP_Found will use an unpacked key */
470435
aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
471436
if( aToOpen==0 ) goto delete_from_cleanup;
472437
memset(aToOpen, 1, nIdx+1);
473438
aToOpen[nIdx+1] = 0;
474439
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
475440
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
476-
addr = sqlite3VdbeAddOp0(v, OP_Goto);
441+
if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen);
442+
addrDelete = sqlite3VdbeAddOp0(v, OP_Goto); /* Jump to DELETE logic */
443+
}else if( pPk ){
444+
/* Construct a composite key for the row to be deleted and remember it */
445+
iKey = ++pParse->nMem;
446+
nKey = 0; /* Zero tells OP_Found to use a composite key */
447+
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
448+
sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
449+
sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
477450
}else{
478-
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
451+
/* Get the rowid of the row to be deleted and remember it in the RowSet */
452+
nKey = 1; /* OP_Seek always uses a single rowid */
453+
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
479454
}
455+
456+
/* End of the WHERE loop */
480457
sqlite3WhereEnd(pWInfo);
481458
if( okOnePass ){
482-
sqlite3VdbeAddOp0(v, OP_Halt);
483-
sqlite3VdbeJumpHere(v, addr);
459+
/* Bypass the delete logic below if the WHERE loop found zero rows */
460+
addrBypass = sqlite3VdbeAddOp0(v, OP_Goto);
461+
sqlite3VdbeJumpHere(v, addrDelete);
484462
}
485-
486-
/* Delete every item whose key was written to the list during the
487-
** database scan. We have to delete items after the scan is complete
488-
** because deleting an item can change the scan order. */
489-
end = sqlite3VdbeMakeLabel(v);
490-
463+
491464
/* Unless this is a view, open cursors for the table we are
492465
** deleting from and all its indices. If this is a view, then the
493466
** only effect this statement has is to fire the INSTEAD OF
494-
** triggers. */
467+
** triggers.
468+
*/
495469
if( !isView ){
496470
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
497471
&iDataCur, &iIdxCur);
498-
assert( iDataCur==iTabCur );
499-
assert( iIdxCur==iDataCur+1 );
500-
}
501-
502-
if( !okOnePass ){
503-
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, regRowid);
472+
assert( pPk || iDataCur==iTabCur );
473+
assert( pPk || iIdxCur==iDataCur+1 );
504474
}
505-
475+
476+
/* Set up a loop over the rowids/primary-keys that were found in the
477+
** where-clause loop above.
478+
*/
479+
if( okOnePass ){
480+
/* Just one row. Hence the top-of-loop is a no-op */
481+
assert( nKey==nPk ); /* OP_Found will use an unpacked key */
482+
}else if( pPk ){
483+
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur);
484+
sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
485+
assert( nKey==0 ); /* OP_Found will use a composite key */
486+
}else{
487+
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
488+
assert( nKey==1 );
489+
}
490+
506491
/* Delete the row */
507492
#ifndef SQLITE_OMIT_VIRTUALTABLE
508493
if( IsVirtual(pTab) ){
509494
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
510495
sqlite3VtabMakeWritable(pParse, pTab);
511-
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, regRowid, pVTab, P4_VTAB);
496+
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
512497
sqlite3VdbeChangeP5(v, OE_Abort);
513498
sqlite3MayAbort(pParse);
514499
}else
515500
#endif
516501
{
517502
int count = (pParse->nested==0); /* True to count changes */
518503
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
519-
regRowid, 1, count, OE_Default, okOnePass);
520-
}
521-
522-
/* End of the delete loop */
523-
if( !okOnePass ){
524-
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
504+
iKey, nKey, count, OE_Default, okOnePass);
525505
}
526-
sqlite3VdbeResolveLabel(v, end);
527-
506+
507+
/* End of the loop over all rowids/primary-keys. */
508+
if( okOnePass ){
509+
sqlite3VdbeJumpHere(v, addrBypass);
510+
}else if( pPk ){
511+
sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1);
512+
sqlite3VdbeJumpHere(v, addrLoop);
513+
}else{
514+
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrLoop);
515+
sqlite3VdbeJumpHere(v, addrLoop);
516+
}
517+
528518
/* Close the cursors open on the table and its indexes. */
529519
if( !isView && !IsVirtual(pTab) ){
530-
sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
520+
if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
531521
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
532522
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
533523
}
534524
}
535-
}
525+
} /* End non-truncate path */
536526

537527
/* Update the sqlite_sequence table by storing the content of the
538528
** maximum rowid counter values recorded while inserting into

0 commit comments

Comments
 (0)