]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Further performance tweaks to OP_Column.
authordrh <drh@noemail.net>
Wed, 20 Nov 2013 19:28:03 +0000 (19:28 +0000)
committerdrh <drh@noemail.net>
Wed, 20 Nov 2013 19:28:03 +0000 (19:28 +0000)
FossilOrigin-Name: 0e3f5df695216a27602a53eed5d25231b055adc8

manifest
manifest.uuid
src/vdbe.c
test/analyze9.test

index 91be839db04e345a960b62e47c8163ff7e7fa928..a7de779afd5d4f8ab0f0312ae429536be3213738 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Refactoring\sthe\sOP_Column\sopcode\sfor\simproved\sperformance\sand\nmaintainability.
-D 2013-11-20T17:25:55.912
+C Further\sperformance\stweaks\sto\sOP_Column.
+D 2013-11-20T19:28:03.982
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -280,7 +280,7 @@ F src/update.c c05a0ee658f1a149e0960dfd110f3b8bd846bcb0
 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
 F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
-F src/vdbe.c d4b8a9067a163f18535324c76bafdddff6b93491
+F src/vdbe.c 1a6e2c9413fca3b2d00c49e85a861e0adc8b6c6a
 F src/vdbe.h c06f0813f853566457ce9cfb1a4a4bc39a5da644
 F src/vdbeInt.h fbae1c449049a1a26ebbdf44e1beb08344072b72
 F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
@@ -313,7 +313,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
 F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c
 F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
 F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
-F test/analyze9.test 1b9b7e9a096d1536f03d9ad7b72f638ef5669347
+F test/analyze9.test 339e87723cd4dc158dc5e9095acd8df9e87faf79
 F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
 F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
@@ -1140,10 +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 5562cd343d8f69242e06a51a7f1aef7ee7d78eec
-R 71521f10a62f5e2d15e34378a9a872cf
-T *branch * OP_Column-refactor
-T *sym-OP_Column-refactor *
-T -sym-trunk *
+P 7c914e3997d2b28164a2fa7eb4398262b6ddb4b2
+R 72749b37eba95a49879e9308fdcd90bb
 U drh
-Z 41c0df82986aff89d8eb065b326b79ba
+Z 441207295dddfadd80f4cc85b77f0a53
index 6e355397de05f3fa68f01640d868889700c734cb..458e461e6b4c9132fd00976520a8934f2cff2a42 100644 (file)
@@ -1 +1 @@
-7c914e3997d2b28164a2fa7eb4398262b6ddb4b2
\ No newline at end of file
+0e3f5df695216a27602a53eed5d25231b055adc8
\ No newline at end of file
index 874645f1898d1756d527110ede549d57b9e49bc2..f3832ab34f723420b75783ea2b1895bcee03a0e2 100644 (file)
@@ -2255,13 +2255,11 @@ case OP_NotNull: {            /* same as TK_NOTNULL, jump, in1 */
 */
 case OP_Column: {
   i64 payloadSize64; /* Number of bytes in the record */
-  int p1;            /* P1 value of the opcode */
   int p2;            /* column number to retrieve */
   VdbeCursor *pC;    /* The VDBE cursor */
   BtCursor *pCrsr;   /* The BTree cursor */
   u32 *aType;        /* aType[i] holds the numeric type of the i-th column */
   u32 *aOffset;      /* aOffset[i] is offset to start of data for i-th column */
-  int nField;        /* number of fields in the record */
   int len;           /* The length of the serialized data for the column */
   int i;             /* Loop counter */
   Mem *pDest;        /* Where to write the extracted value */
@@ -2275,17 +2273,14 @@ case OP_Column: {
   u32 t;             /* A type code from the record header */
   Mem *pReg;         /* PseudoTable input register */
 
-  p1 = pOp->p1;
-  assert( p1<p->nCursor );
   p2 = pOp->p2;
-  sMem.zMalloc = 0;
   assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
   pDest = &aMem[pOp->p3];
   memAboutToChange(p, pDest);
-  pC = p->apCsr[p1];
+  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+  pC = p->apCsr[pOp->p1];
   assert( pC!=0 );
-  nField = pC->nField;
-  assert( p2<nField );
+  assert( p2<pC->nField );
   aType = pC->aType;
   aOffset = pC->aOffset;
 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -2293,27 +2288,31 @@ case OP_Column: {
 #endif
   pCrsr = pC->pCursor;
   assert( pCrsr!=0 || pC->pseudoTableReg>0 );
+  assert( pC->pseudoTableReg==0 || pC->nullRow );
 
   /* If the cursor cache is stale, bring it up-to-date */
   rc = sqlite3VdbeCursorMoveto(pC);
   if( rc ) goto abort_due_to_error;
   if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
-    if( pCrsr==0 ){
-      assert( pC->pseudoTableReg>0 );
-      pReg = &aMem[pC->pseudoTableReg];
-      if( pC->multiPseudo ){
-        sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
-        Deephemeralize(pDest);
+    if( pC->nullRow ){
+      if( pCrsr==0 ){
+        assert( pC->pseudoTableReg>0 );
+        pReg = &aMem[pC->pseudoTableReg];
+        if( pC->multiPseudo ){
+          sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
+          Deephemeralize(pDest);
+          goto op_column_out;
+        }
+        assert( pReg->flags & MEM_Blob );
+        assert( memIsValid(pReg) );
+        pC->payloadSize = pC->szRow = avail = pReg->n;
+        pC->aRow = (u8*)pReg->z;
+      }else{
+        MemSetTypeFlag(pDest, MEM_Null);
         goto op_column_out;
       }
-      assert( pReg->flags & MEM_Blob );
-      assert( memIsValid(pReg) );
-      pC->payloadSize = pC->szRow = avail = pReg->n;
-      pC->aRow = (u8*)pReg->z;
-    }else if( pC->nullRow ){
-      MemSetTypeFlag(pDest, MEM_Null);
-      goto op_column_out;
     }else{
+      assert( pCrsr );
       if( pC->isIndex ){
         assert( sqlite3BtreeCursorIsValid(pCrsr) );
         VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
@@ -2361,65 +2360,85 @@ case OP_Column: {
     */
     if( offset > 98307 || offset > pC->payloadSize ){
       rc = SQLITE_CORRUPT_BKPT;
-      goto op_column_out;
+      goto op_column_error;
     }
   }
 
   /* Make sure at least the first p2+1 entries of the header have been
   ** parsed and valid information is in aOffset[] and aType[].
   */
-  if( pC->nHdrParsed<=p2 && pC->iHdrOffset<aOffset[0] ){
-    /* Make sure zData points to enough of the record to cover the header. */
-    if( pC->aRow==0 ){
-      memset(&sMem, 0, sizeof(sMem));
-      rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex,&sMem);
-      if( rc!=SQLITE_OK ){
-        goto op_column_out;
-      }
-      zData = (u8*)sMem.z;
-    }else{
-      zData = pC->aRow;
-    }
-
-    /* Fill in aType[i] and aOffset[i] values through the p2-th field. */
-    i = pC->nHdrParsed;
-    offset = aOffset[i];
-    zHdr = zData + pC->iHdrOffset;
-    zEndHdr = zData + pC->aOffset[0];
-    for(; i<=p2 && zHdr<zEndHdr; i++){
-      if( zHdr[0]<0x80 ){
-        t = zHdr[0];
-        zHdr++;
+  if( pC->nHdrParsed<=p2 ){
+    /* If there is more header available for parsing, try to extract 
+    ** additional fields up through the p2-th field 
+    */
+    if( pC->iHdrOffset<aOffset[0] ){
+      /* Make sure zData points to enough of the record to cover the header. */
+      if( pC->aRow==0 ){
+        memset(&sMem, 0, sizeof(sMem));
+        rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex,
+                                     &sMem);
+        if( rc!=SQLITE_OK ){
+          goto op_column_error;
+        }
+        zData = (u8*)sMem.z;
       }else{
-        zHdr += sqlite3GetVarint32(zHdr, &t);
+        zData = pC->aRow;
       }
-      aType[i] = t;
-      szField = sqlite3VdbeSerialTypeLen(t);
-      offset += szField;
-      if( offset<szField ){  /* True if offset overflows */
-        zHdr = &zEndHdr[1];  /* Forces SQLITE_CORRUPT return below */
-        break;
+  
+      /* Fill in aType[i] and aOffset[i] values through the p2-th field. */
+      i = pC->nHdrParsed;
+      offset = aOffset[i];
+      zHdr = zData + pC->iHdrOffset;
+      zEndHdr = zData + aOffset[0];
+      assert( i<=p2 && zHdr<zEndHdr );
+      do{
+        if( zHdr[0]<0x80 ){
+          t = zHdr[0];
+          zHdr++;
+        }else{
+          zHdr += sqlite3GetVarint32(zHdr, &t);
+        }
+        aType[i] = t;
+        szField = sqlite3VdbeSerialTypeLen(t);
+        offset += szField;
+        if( offset<szField ){  /* True if offset overflows */
+          zHdr = &zEndHdr[1];  /* Forces SQLITE_CORRUPT return below */
+          break;
+        }
+        i++;
+        aOffset[i] = offset;
+      }while( i<=p2 && zHdr<zEndHdr );
+      pC->nHdrParsed = i;
+      pC->iHdrOffset = (u32)(zHdr - zData);
+      if( pC->aRow==0 ){
+        sqlite3VdbeMemRelease(&sMem);
+        sMem.flags = MEM_Null;
+      }
+  
+      /* If we have read more header data than was contained in the header,
+      ** or if the end of the last field appears to be past the end of the
+      ** record, or if the end of the last field appears to be before the end
+      ** of the record (when all fields present), then we must be dealing 
+      ** with a corrupt database.
+      */
+      if( (zHdr > zEndHdr)
+       || (offset > pC->payloadSize)
+       || (zHdr==zEndHdr && offset!=pC->payloadSize)
+      ){
+        rc = SQLITE_CORRUPT_BKPT;
+        goto op_column_error;
       }
-      aOffset[i+1] = offset;
-    }
-    pC->nHdrParsed = i;
-    pC->iHdrOffset = (u32)(zHdr - zData);
-    if( pC->aRow==0 ){
-      sqlite3VdbeMemRelease(&sMem);
-      sMem.flags = MEM_Null;
     }
 
-    /* If we have read more header data than was contained in the header,
-    ** or if the end of the last field appears to be past the end of the
-    ** record, or if the end of the last field appears to be before the end
-    ** of the record (when all fields present), then we must be dealing 
-    ** with a corrupt database.
-    */
-    if( (zHdr > zEndHdr)
-     || (offset > pC->payloadSize)
-     || (zHdr==zEndHdr && offset!=pC->payloadSize)
-    ){
-      rc = SQLITE_CORRUPT_BKPT;
+    /* If after nHdrParsed is still not up to p2, that means that the record
+    ** has fewer than p2 columns.  So the result will be either the default
+    ** value or a NULL. */
+    if( pC->nHdrParsed<=p2 ){
+      if( pOp->p4type==P4_MEM ){
+        sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
+      }else{
+        MemSetTypeFlag(pDest, MEM_Null);
+      }
       goto op_column_out;
     }
   }
@@ -2430,64 +2449,56 @@ case OP_Column: {
   ** request.  In this case, set the value NULL or to P4 if P4 is
   ** a pointer to a Mem object.
   */
-  if( p2<pC->nHdrParsed ){
-    assert( rc==SQLITE_OK );
-    if( pC->szRow>=aOffset[p2+1] ){
-      /* This is the common case where the whole row fits on a single page */
-      VdbeMemRelease(pDest);
-      sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
+  assert( p2<pC->nHdrParsed );
+  assert( rc==SQLITE_OK );
+  if( pC->szRow>=aOffset[p2+1] ){
+    /* This is the common case where the whole row fits on a single page */
+    VdbeMemRelease(pDest);
+    sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
+  }else{
+    /* This branch happens only when the row overflows onto multiple pages */
+    t = aType[p2];
+    if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
+     && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
+    ){
+      /* Content is irrelevant for the typeof() function and for
+      ** the length(X) function if X is a blob.  So we might as well use
+      ** bogus content rather than reading content from disk.  NULL works
+      ** for text and blob and whatever is in the payloadSize64 variable
+      ** will work for everything else. */
+      zData = t<12 ? (u8*)&payloadSize64 : 0;
+      sMem.zMalloc = 0;
     }else{
-      /* This branch happens only when the row overflows onto multiple pages */
-      t = aType[p2];
-      if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
-       && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
-      ){
-        /* Content is irrelevant for the typeof() function and for
-        ** the length(X) function if X is a blob.  So we might as well use
-        ** bogus content rather than reading content from disk.  NULL works
-        ** for text and blob and whatever is in the payloadSize64 variable
-        ** will work for everything else. */
-        zData = t<12 ? (u8*)&payloadSize64 : 0;
-      }else{
-        len = sqlite3VdbeSerialTypeLen(t);
-        memset(&sMem, 0, sizeof(sMem));
-        sqlite3VdbeMemMove(&sMem, pDest);
-        rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len,  pC->isIndex,
-                                     &sMem);
-        if( rc!=SQLITE_OK ){
-          goto op_column_out;
-        }
-        zData = (u8*)sMem.z;
+      len = sqlite3VdbeSerialTypeLen(t);
+      memset(&sMem, 0, sizeof(sMem));
+      sqlite3VdbeMemMove(&sMem, pDest);
+      rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len,  pC->isIndex,
+                                   &sMem);
+      if( rc!=SQLITE_OK ){
+        goto op_column_error;
       }
-      sqlite3VdbeSerialGet(zData, t, pDest);
+      zData = (u8*)sMem.z;
     }
-    pDest->enc = encoding;
-  }else{
-    if( pOp->p4type==P4_MEM ){
-      sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
-    }else{
-      MemSetTypeFlag(pDest, MEM_Null);
+    sqlite3VdbeSerialGet(zData, t, pDest);
+    /* If we dynamically allocated space to hold the data (in the
+    ** sqlite3VdbeMemFromBtree() call above) then transfer control of that
+    ** dynamically allocated space over to the pDest structure.
+    ** This prevents a memory copy. */
+    if( sMem.zMalloc ){
+      assert( sMem.z==sMem.zMalloc );
+      assert( !(pDest->flags & MEM_Dyn) );
+      assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
+      pDest->flags &= ~(MEM_Ephem|MEM_Static);
+      pDest->flags |= MEM_Term;
+      pDest->z = sMem.z;
+      pDest->zMalloc = sMem.zMalloc;
     }
   }
-
-  /* If we dynamically allocated space to hold the data (in the
-  ** sqlite3VdbeMemFromBtree() call above) then transfer control of that
-  ** dynamically allocated space over to the pDest structure.
-  ** This prevents a memory copy.
-  */
-  if( sMem.zMalloc ){
-    assert( sMem.z==sMem.zMalloc );
-    assert( !(pDest->flags & MEM_Dyn) );
-    assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
-    pDest->flags &= ~(MEM_Ephem|MEM_Static);
-    pDest->flags |= MEM_Term;
-    pDest->z = sMem.z;
-    pDest->zMalloc = sMem.zMalloc;
-  }
-
-  rc = sqlite3VdbeMemMakeWriteable(pDest);
+  pDest->enc = encoding;
 
 op_column_out:
+  rc = sqlite3VdbeMemMakeWriteable(pDest);
+op_column_error:
   UPDATE_MAX_BLOBSIZE(pDest);
   REGISTER_TRACE(pOp->p3, pDest);
   break;
index aaf0ba3bb002197d6ce1a595d37562bdfd76c725..0fce55ac4b6ccfc9ce6a6ebcfe5005d1895d7286 100644 (file)
@@ -805,8 +805,9 @@ do_test 16.1 {
     ANALYZE;
   }
   set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
+  puts -nonewline " (nByte=$nByte nByte2=$nByte2)"
 
-  expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1050}
+  expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1100}
 } {1}
 
 #-------------------------------------------------------------------------