@@ -227,7 +227,6 @@ void sqlite3DeleteFrom(
227
227
Vdbe * v ; /* The virtual database engine */
228
228
Table * pTab ; /* The table from which records will be deleted */
229
229
const char * zDb ; /* Name of database holding pTab */
230
- int end , addr = 0 ; /* A couple addresses of generated code */
231
230
int i ; /* Loop counter */
232
231
WhereInfo * pWInfo ; /* Information about the WHERE clause */
233
232
Index * pIdx ; /* For looping over indices of the table */
@@ -244,7 +243,18 @@ void sqlite3DeleteFrom(
244
243
int okOnePass ; /* True for one-pass algorithm without the FIFO */
245
244
int aiCurOnePass [2 ]; /* The write cursors opened by WHERE_ONEPASS */
246
245
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
+
248
258
#ifndef SQLITE_OMIT_TRIGGER
249
259
int isView ; /* True if attempting to delete from a view */
250
260
Trigger * pTrigger ; /* List of table triggers, if required */
@@ -369,170 +379,150 @@ void sqlite3DeleteFrom(
369
379
}
370
380
}else
371
381
#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.
374
404
*/
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 );
391
405
pWInfo = sqlite3WhereBegin (pParse , pTabList , pWhere , 0 , 0 ,
392
406
WHERE_ONEPASS_DESIRED , iTabCur + 1 );
393
407
if ( pWInfo == 0 ) goto delete_from_cleanup ;
394
408
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 */
398
411
if ( db -> flags & SQLITE_CountRows ){
399
412
sqlite3VdbeAddOp2 (v , OP_AddImm , memCnt , 1 );
400
413
}
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 ;
410
423
}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 ;
465
427
}
466
- regRowid = sqlite3ExprCodeGetColumn (pParse , pTab , -1 , iTabCur ,
467
- pParse -> nMem + 1 , 0 );
468
- if ( regRowid > pParse -> nMem ) pParse -> nMem = regRowid ;
428
+
469
429
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 */
470
435
aToOpen = sqlite3DbMallocRaw (db , nIdx + 2 );
471
436
if ( aToOpen == 0 ) goto delete_from_cleanup ;
472
437
memset (aToOpen , 1 , nIdx + 1 );
473
438
aToOpen [nIdx + 1 ] = 0 ;
474
439
if ( aiCurOnePass [0 ]>=0 ) aToOpen [aiCurOnePass [0 ]- iTabCur ] = 0 ;
475
440
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 );
477
450
}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 );
479
454
}
455
+
456
+ /* End of the WHERE loop */
480
457
sqlite3WhereEnd (pWInfo );
481
458
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 );
484
462
}
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
+
491
464
/* Unless this is a view, open cursors for the table we are
492
465
** deleting from and all its indices. If this is a view, then the
493
466
** only effect this statement has is to fire the INSTEAD OF
494
- ** triggers. */
467
+ ** triggers.
468
+ */
495
469
if ( !isView ){
496
470
sqlite3OpenTableAndIndices (pParse , pTab , OP_OpenWrite , iTabCur , aToOpen ,
497
471
& 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 );
504
474
}
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
+
506
491
/* Delete the row */
507
492
#ifndef SQLITE_OMIT_VIRTUALTABLE
508
493
if ( IsVirtual (pTab ) ){
509
494
const char * pVTab = (const char * )sqlite3GetVTable (db , pTab );
510
495
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 );
512
497
sqlite3VdbeChangeP5 (v , OE_Abort );
513
498
sqlite3MayAbort (pParse );
514
499
}else
515
500
#endif
516
501
{
517
502
int count = (pParse -> nested == 0 ); /* True to count changes */
518
503
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 );
525
505
}
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
+
528
518
/* Close the cursors open on the table and its indexes. */
529
519
if ( !isView && !IsVirtual (pTab ) ){
530
- sqlite3VdbeAddOp1 (v , OP_Close , iDataCur );
520
+ if ( ! pPk ) sqlite3VdbeAddOp1 (v , OP_Close , iDataCur );
531
521
for (i = 0 , pIdx = pTab -> pIndex ; pIdx ; i ++ , pIdx = pIdx -> pNext ){
532
522
sqlite3VdbeAddOp1 (v , OP_Close , iIdxCur + i );
533
523
}
534
524
}
535
- }
525
+ } /* End non-truncate path */
536
526
537
527
/* Update the sqlite_sequence table by storing the content of the
538
528
** maximum rowid counter values recorded while inserting into
0 commit comments