]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Combine the rowid and WITHOUT ROWID paths for DELETE into a single path.
authordrh <drh@noemail.net>
Sat, 16 Nov 2013 22:48:52 +0000 (22:48 +0000)
committerdrh <drh@noemail.net>
Sat, 16 Nov 2013 22:48:52 +0000 (22:48 +0000)
FossilOrigin-Name: c4734b881a64a9d21d03a14e901785797577fbd8

manifest
manifest.uuid
src/delete.c

index 6c93f9afcbb84f91fbdd0f3efe88f660535e6501..dd8429d5685b3e12e73d435f7ed4d51c2dee8b18 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\sone-pass\soptimization\sis\snow\sworking\sfor\sDELETE\son\sWITHOUT\sROWID\stables.
-D 2013-11-16T20:45:01.087
+C Combine\sthe\srowid\sand\sWITHOUT\sROWID\spaths\sfor\sDELETE\sinto\sa\ssingle\spath.
+D 2013-11-16T22:48:52.173
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -174,7 +174,7 @@ F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
 F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
-F src/delete.c 35750d35fe9f174ccb98bae0d6627dcf83a7965a
+F src/delete.c 1bcc9d7f2e48cf9043a44bdbd333c38c2ef6676a
 F src/expr.c 1a295d8b0a2ba08919ad9300ebf7b67988ff4030
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 78364daed38e26269c53ddb94c515bceac1063c6
@@ -1140,7 +1140,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 8f479a72758ab6fedb171ada612b1963143c32fa
-R b6e41a6a6d551dfa6da0e7b0e42124eb
+P e4d220a381388f900a95d1b656a82f14c837f92e
+R d0df7aac2a46f76fbd08b30c4f269d2a
 U drh
-Z f0edfafd89abfe9d193a6a7758aa54ff
+Z 2d947a1a8ff0ceb82e3a6fad03406bbd
index 1a4b2e14897c8e080202a76e2bb1bdbf665c164b..e3dbc372846baa24bc588d1b40477ac2813b0f7d 100644 (file)
@@ -1 +1 @@
-e4d220a381388f900a95d1b656a82f14c837f92e
\ No newline at end of file
+c4734b881a64a9d21d03a14e901785797577fbd8
\ No newline at end of file
index 30b415aa351665bfe1e17f8786e95ca48f97a6d1..35010a483a7275073e8333490730c7e7c7b37354 100644 (file)
@@ -227,7 +227,6 @@ void sqlite3DeleteFrom(
   Vdbe *v;               /* The virtual database engine */
   Table *pTab;           /* The table from which records will be deleted */
   const char *zDb;       /* Name of database holding pTab */
-  int end, addr = 0;     /* A couple addresses of generated code */
   int i;                 /* Loop counter */
   WhereInfo *pWInfo;     /* Information about the WHERE clause */
   Index *pIdx;           /* For looping over indices of the table */
@@ -244,7 +243,18 @@ void sqlite3DeleteFrom(
   int okOnePass;         /* True for one-pass algorithm without the FIFO */
   int aiCurOnePass[2];   /* The write cursors opened by WHERE_ONEPASS */
   u8 *aToOpen = 0;       /* Open cursor iTabCur+j if aToOpen[j] is true */
-
+  Index *pPk;            /* The PRIMARY KEY index on the table */
+  int iPk;               /* First of nPk registerss holding PRIMARY KEY value */
+  i16 nPk = 1;           /* Number of components of the PRIMARY KEY */
+  int iKey;              /* Memory cell holding row key of to be deleted */
+  i16 nKey;              /* Number of memory cells of row key */
+  int iEphCur = 0;       /* Ephemeral table holding all primary key values */
+  int iRowSet = 0;       /* Register for rowset of rows to delete */
+  int addrBypass = 0;    /* Address of jump over the delete logic */
+  int addrLoop = 0;      /* Top of the delete loop */
+  int addrDelete = 0;    /* Jump directly to the delete logic */
+  int addrEphOpen = 0;   /* Instruction to open the Ephermeral table */
 #ifndef SQLITE_OMIT_TRIGGER
   int isView;                  /* True if attempting to delete from a view */
   Trigger *pTrigger;           /* List of table triggers, if required */
@@ -369,146 +379,121 @@ void sqlite3DeleteFrom(
     }
   }else
 #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
-  if( !HasRowid(pTab) ){
-    /* There is a WHERE clause on a WITHOUT ROWID table.  
+  {
+    if( HasRowid(pTab) ){
+      /* For a rowid table, initialize the RowSet to an empty set */
+      pPk = 0;
+      nPk = 1;
+      iRowSet = ++pParse->nMem;
+      sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
+    }else{
+      /* For a WITHOUT ROWID table, create an ephermeral table used to
+      ** hold all primary keys for rows to be deleted. */
+      pPk = sqlite3PrimaryKeyIndex(pTab);
+      assert( pPk!=0 );
+      nPk = pPk->nKeyCol;
+      iPk = pParse->nMem+1;
+      pParse->nMem += nPk;
+      iEphCur = pParse->nTab++;
+      addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk);
+      sqlite3VdbeSetP4KeyInfo(pParse, pPk);
+    }
+  
+    /* Construct a query to find the rowid or primary key for every row
+    ** to be deleted, based on the WHERE clause.
     */
-    Index *pPk;      /* The PRIMARY KEY index on the table */
-    int iPk;         /* First of nPk memory cells holding PRIMARY KEY value */
-    int iEph;        /* Ephemeral table holding all primary key values */
-    int iKey;        /* Key value inserting into iEph */
-    i16 nPk;         /* Number of components of the PRIMARY KEY */
-
-    pPk = sqlite3PrimaryKeyIndex(pTab);
-    assert( pPk!=0 );
-    nPk = pPk->nKeyCol;
-    iPk = pParse->nMem+1;
-    pParse->nMem += nPk;
-    iKey = ++pParse->nMem;
-    iEph = pParse->nTab++;
-
-    addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
-    sqlite3VdbeSetP4KeyInfo(pParse, pPk);
     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, 
                                WHERE_ONEPASS_DESIRED, iTabCur+1);
     if( pWInfo==0 ) goto delete_from_cleanup;
     okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
-    for(i=0; i<nPk; i++){
-      sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i],iPk+i);
-    }
+  
+    /* Keep track of the number of rows to be deleted */
     if( db->flags & SQLITE_CountRows ){
       sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
     }
-    if( okOnePass ){
-      aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
-      if( aToOpen==0 ) goto delete_from_cleanup;
-      memset(aToOpen, 1, nIdx+1);
-      aToOpen[nIdx+1] = 0;
-      if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
-      if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
-      sqlite3VdbeChangeToNoop(v, addr);
-      addr = sqlite3VdbeAddOp0(v, OP_Goto);
+  
+    /* Extract the rowid or primary key for the current row */
+    if( pPk ){
+      for(i=0; i<nPk; i++){
+        sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
+                                        pPk->aiColumn[i], iPk+i);
+      }
+      iKey = iPk;
+      nKey = nPk;
     }else{
-      sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
-                        sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, iKey);
-    }
-    sqlite3WhereEnd(pWInfo);
-    if( okOnePass ){
-      sqlite3VdbeAddOp0(v, OP_Halt);
-      sqlite3VdbeJumpHere(v, addr);
-    }
-
-    /* Open cursors for all indices of the table.
-    */
-    sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
-                               &iDataCur, &iIdxCur);
-
-    /* Loop over the primary keys to be deleted. */
-    if( !okOnePass ){
-      addr = sqlite3VdbeAddOp1(v, OP_Rewind, iEph);
-      sqlite3VdbeAddOp2(v, OP_RowKey, iEph, iPk);
-    }
-
-    /* Delete the row */
-    sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
-                             iPk, nPk*okOnePass, 1, OE_Default, okOnePass);
-
-    /* End of the delete loop */
-    if( !okOnePass ){
-      sqlite3VdbeAddOp2(v, OP_Next, iEph, addr+1);
-      sqlite3VdbeJumpHere(v, addr);
-    }
-
-    /* Close the cursors open on the table and its indexes. */
-    assert( iDataCur>=iIdxCur );
-    for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
-      sqlite3VdbeAddOp1(v, OP_Close, iIdxCur+i);
-    }
-  }else{
-    /* There is a WHERE clause on a rowid table.  Run a loop that extracts
-    ** all rowids to be deleted into a RowSet.
-    */
-    int iRowSet = ++pParse->nMem;   /* Register for rowset of rows to delete */
-    int regRowid;                   /* Actual register containing rowids */
-
-    /* Collect rowids of every row to be deleted.
-    */
-    sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
-    pWInfo = sqlite3WhereBegin(
-        pParse, pTabList, pWhere, 0, 0,
-        WHERE_DUPLICATES_OK|WHERE_ONEPASS_DESIRED, iTabCur+1
-    );
-    if( pWInfo==0 ) goto delete_from_cleanup;
-    okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
-    if( db->flags & SQLITE_CountRows ){
-      sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
+      iKey = pParse->nMem + 1;
+      iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0);
+      if( iKey>pParse->nMem ) pParse->nMem = iKey;
     }
-    regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur,
-                                        pParse->nMem+1, 0);
-    if( regRowid>pParse->nMem ) pParse->nMem = regRowid;
+  
     if( okOnePass ){
+      /* For ONEPASS, no need to store the rowid/primary-key.  There is only
+      ** one, so just keep it in its register(s) and fall through to the
+      ** delete code.
+      */
+      nKey = nPk; /* OP_Found will use an unpacked key */
       aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
       if( aToOpen==0 ) goto delete_from_cleanup;
       memset(aToOpen, 1, nIdx+1);
       aToOpen[nIdx+1] = 0;
       if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
       if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
-      addr = sqlite3VdbeAddOp0(v, OP_Goto);
+      if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen);
+      addrDelete = sqlite3VdbeAddOp0(v, OP_Goto); /* Jump to DELETE logic */
+    }else if( pPk ){
+      /* Construct a composite key for the row to be deleted and remember it */
+      iKey = ++pParse->nMem;
+      nKey = 0;   /* Zero tells OP_Found to use a composite key */
+      sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
+                        sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
+      sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
     }else{
-      sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
+      /* Get the rowid of the row to be deleted and remember it in the RowSet */
+      nKey = 1;  /* OP_Seek always uses a single rowid */
+      sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
     }
+  
+    /* End of the WHERE loop */
     sqlite3WhereEnd(pWInfo);
     if( okOnePass ){
-      sqlite3VdbeAddOp0(v, OP_Halt);
-      sqlite3VdbeJumpHere(v, addr);
+      /* Bypass the delete logic below if the WHERE loop found zero rows */
+      addrBypass = sqlite3VdbeAddOp0(v, OP_Goto);
+      sqlite3VdbeJumpHere(v, addrDelete);
     }
-
-    /* Delete every item whose key was written to the list during the
-    ** database scan.  We have to delete items after the scan is complete
-    ** because deleting an item can change the scan order.  */
-    end = sqlite3VdbeMakeLabel(v);
-
+  
     /* Unless this is a view, open cursors for the table we are 
     ** deleting from and all its indices. If this is a view, then the
     ** only effect this statement has is to fire the INSTEAD OF 
-    ** triggers.  */
+    ** triggers.
+    */
     if( !isView ){
       sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
                                  &iDataCur, &iIdxCur);
-      assert( iDataCur==iTabCur );
-      assert( iIdxCur==iDataCur+1 );
-    }
-
-    if( !okOnePass ){    
-      addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, regRowid);
+      assert( pPk || iDataCur==iTabCur );
+      assert( pPk || iIdxCur==iDataCur+1 );
     }
-
+  
+    /* Set up a loop over the rowids/primary-keys that were found in the
+    ** where-clause loop above.
+    */
+    if( okOnePass ){
+      /* Just one row.  Hence the top-of-loop is a no-op */
+      assert( nKey==nPk ); /* OP_Found will use an unpacked key */
+    }else if( pPk ){
+      addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur);
+      sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
+      assert( nKey==0 );  /* OP_Found will use a composite key */
+    }else{
+      addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
+      assert( nKey==1 );
+    }  
+  
     /* Delete the row */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
     if( IsVirtual(pTab) ){
       const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
       sqlite3VtabMakeWritable(pParse, pTab);
-      sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, regRowid, pVTab, P4_VTAB);
+      sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
       sqlite3VdbeChangeP5(v, OE_Abort);
       sqlite3MayAbort(pParse);
     }else
@@ -516,23 +501,28 @@ void sqlite3DeleteFrom(
     {
       int count = (pParse->nested==0);    /* True to count changes */
       sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
-                               regRowid, 1, count, OE_Default, okOnePass);
-    }
-
-    /* End of the delete loop */
-    if( !okOnePass ){
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
+                               iKey, nKey, count, OE_Default, okOnePass);
     }
-    sqlite3VdbeResolveLabel(v, end);
-
+  
+    /* End of the loop over all rowids/primary-keys. */
+    if( okOnePass ){
+      sqlite3VdbeJumpHere(v, addrBypass);
+    }else if( pPk ){
+      sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1);
+      sqlite3VdbeJumpHere(v, addrLoop);
+    }else{
+      sqlite3VdbeAddOp2(v, OP_Goto, 0, addrLoop);
+      sqlite3VdbeJumpHere(v, addrLoop);
+    }     
+  
     /* Close the cursors open on the table and its indexes. */
     if( !isView && !IsVirtual(pTab) ){
-      sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
+      if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
       for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
         sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
       }
     }
-  }
+  } /* End non-truncate path */
 
   /* Update the sqlite_sequence table by storing the content of the
   ** maximum rowid counter values recorded while inserting into