/ Check-in [78fb8838]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Make sure registers are cleared properly prior to being used to store the result of an OP_Column operator.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | micro-optimizations
Files: files | file ages | folders
SHA1: 78fb8838d80b229418c347c63579989432e1af7d
User & Date: drh 2014-09-16 20:05:21
Context
2014-09-16
21:54
Continuing cleanup of memory register memory allocation handling. check-in: 2598aedc user: drh tags: micro-optimizations
20:05
Make sure registers are cleared properly prior to being used to store the result of an OP_Column operator. check-in: 78fb8838 user: drh tags: micro-optimizations
18:22
Simplification of the OP_Column logic for the case of rows with overflow. check-in: f7367803 user: drh tags: micro-optimizations
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

2433
2434
2435
2436
2437
2438
2439

2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
  /* Extract the content for the p2+1-th column.  Control can only
  ** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are
  ** all valid.
  */
  assert( p2<pC->nHdrParsed );
  assert( rc==SQLITE_OK );
  assert( sqlite3VdbeCheckMemInvariants(pDest) );

  if( pC->szRow>=aOffset[p2+1] ){
    /* This is the common case where the desired content fits on the original
    ** page - where the content is not on an overflow page */
    VdbeMemReleaseExtern(pDest);
    sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
  }else{
    /* This branch happens only when content is on overflow pages */
    t = aType[p2];
    if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
          && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
     || (len = sqlite3VdbeSerialTypeLen(t))==0







>



<







2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443

2444
2445
2446
2447
2448
2449
2450
  /* Extract the content for the p2+1-th column.  Control can only
  ** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are
  ** all valid.
  */
  assert( p2<pC->nHdrParsed );
  assert( rc==SQLITE_OK );
  assert( sqlite3VdbeCheckMemInvariants(pDest) );
  VdbeMemReleaseExtern(pDest);
  if( pC->szRow>=aOffset[p2+1] ){
    /* This is the common case where the desired content fits on the original
    ** page - where the content is not on an overflow page */

    sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
  }else{
    /* This branch happens only when content is on overflow pages */
    t = aType[p2];
    if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
          && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
     || (len = sqlite3VdbeSerialTypeLen(t))==0

Changes to src/vdbeaux.c.

3302
3303
3304
3305
3306
3307
3308

3309
3310
3311
3312
3313
3314
3315
    const void *v1, *v2;
    int n1, n2;
    Mem c1;
    Mem c2;
    c1.db = c2.db = pMem1->db;
    c1.flags = c2.flags = 0;
    c1.zMalloc = c2.zMalloc = 0;

    sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
    sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
    v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
    n1 = v1==0 ? 0 : c1.n;
    v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
    n2 = v2==0 ? 0 : c2.n;
    rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);







>







3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
    const void *v1, *v2;
    int n1, n2;
    Mem c1;
    Mem c2;
    c1.db = c2.db = pMem1->db;
    c1.flags = c2.flags = 0;
    c1.zMalloc = c2.zMalloc = 0;
    c1.xDel = c2.xDel = 0;
    sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
    sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
    v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
    n1 = v1==0 ? 0 : c1.n;
    v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
    n2 = v2==0 ? 0 : c2.n;
    rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);

Changes to src/vdbemem.c.

306
307
308
309
310
311
312
313
314
315




316
317
318
319
320
321
322
...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360


361
362
363
364
365
366
367
...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
...
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
...
902
903
904
905
906
907
908

909
910
911
912
913
914
915
...
918
919
920
921
922
923
924


925
926
927
928
929
930
931
932
933
934
935
936
937

938
939
940
941
942
943
944
    memcpy(pMem, &t, sizeof(t));
    rc = ctx.isError;
  }
  return rc;
}

/*
** If the memory cell contains a string value that must be freed by
** invoking an external callback, free it now. Calling this function
** does not free any Mem.zMalloc buffer.




**
** The VdbeMemReleaseExtern() macro invokes this routine if only if there
** is work for this routine to do.
*/
void sqlite3VdbeMemReleaseExternal(Mem *p){
  assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
  if( p->flags&MEM_Agg ){
................................................................................
}

/*
** Release memory held by the Mem p, both external memory cleared
** by p->xDel and memory in p->zMalloc.
**
** This is a helper routine invoked by sqlite3VdbeMemRelease() in
** the uncommon case when there really is memory in p that is
** need of freeing.
*/
static SQLITE_NOINLINE void vdbeMemRelease(Mem *p){
  if( VdbeMemDynamic(p) ){
    sqlite3VdbeMemReleaseExternal(p);
  }
  if( p->zMalloc ){
    sqlite3DbFree(p->db, p->zMalloc);
    p->zMalloc = 0;
  }
  p->z = 0;
}

/*
** Release any memory held by the Mem. This may leave the Mem in an
** inconsistent state, for example with (Mem.z==0) and
** (Mem.flags==MEM_Str).


*/
void sqlite3VdbeMemRelease(Mem *p){
  assert( sqlite3VdbeCheckMemInvariants(p) );
  if( VdbeMemDynamic(p) || p->zMalloc ){
    vdbeMemRelease(p);
  }else{
    p->z = 0;
................................................................................
** and flags gets srcType (either MEM_Ephem or MEM_Static).
*/
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
  assert( (pFrom->flags & MEM_RowSet)==0 );
  assert( pTo->db==pFrom->db );
  VdbeMemReleaseExtern(pTo);
  memcpy(pTo, pFrom, MEMCELLSIZE);
  pTo->xDel = 0;
  if( (pFrom->flags&MEM_Static)==0 ){
    pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
    assert( srcType==MEM_Ephem || srcType==MEM_Static );
    pTo->flags |= srcType;
  }
}

................................................................................
  int rc = SQLITE_OK;

  assert( pTo->db==pFrom->db );
  assert( (pFrom->flags & MEM_RowSet)==0 );
  VdbeMemReleaseExtern(pTo);
  memcpy(pTo, pFrom, MEMCELLSIZE);
  pTo->flags &= ~MEM_Dyn;
  pTo->xDel = 0;

  if( pTo->flags&(MEM_Str|MEM_Blob) ){
    if( 0==(pFrom->flags&MEM_Static) ){
      pTo->flags |= MEM_Ephem;
      rc = sqlite3VdbeMemMakeWriteable(pTo);
    }
  }
................................................................................
  Mem *pMem         /* OUT: Return data in this Mem structure. */
){
  char *zData;        /* Data from the btree layer */
  u32 available = 0;  /* Number of bytes available on the local btree page */
  int rc = SQLITE_OK; /* Return code */

  assert( sqlite3BtreeCursorIsValid(pCur) );


  /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() 
  ** that both the BtShared and database handle mutexes are held. */
  assert( (pMem->flags & MEM_RowSet)==0 );
  if( key ){
    zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
  }else{
................................................................................
  assert( zData!=0 );

  if( offset+amt<=available ){
    sqlite3VdbeMemRelease(pMem);
    pMem->z = &zData[offset];
    pMem->flags = MEM_Blob|MEM_Ephem;
    pMem->n = (int)amt;


  }else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
    if( key ){
      rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
    }else{
      rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
    }
    if( rc==SQLITE_OK ){
      pMem->z[amt] = 0;
      pMem->z[amt+1] = 0;
      pMem->flags = MEM_Blob|MEM_Term;
      pMem->n = (int)amt;
    }else{
      sqlite3VdbeMemRelease(pMem);

    }
  }

  return rc;
}

/*







|
|
|
>
>
>
>







 







|
|













|
|
|
>
>







 







|







 







|







 







>







 







>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
>







306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
...
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
...
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
...
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
    memcpy(pMem, &t, sizeof(t));
    rc = ctx.isError;
  }
  return rc;
}

/*
** If the memory cell contains a value that must be freed by
** invoking an external callback, then free it now. 
**
** This routine does NOT do any of the following:
**    (1)  Set the Mem.flags field to a rational value.
**    (2)  Free memory held by Mem.zMalloc
** The caller is expected to take care of setting Mem.flags appropriately.
**
** The VdbeMemReleaseExtern() macro invokes this routine if only if there
** is work for this routine to do.
*/
void sqlite3VdbeMemReleaseExternal(Mem *p){
  assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
  if( p->flags&MEM_Agg ){
................................................................................
}

/*
** Release memory held by the Mem p, both external memory cleared
** by p->xDel and memory in p->zMalloc.
**
** This is a helper routine invoked by sqlite3VdbeMemRelease() in
** the uncommon case when there really is memory in p that needs
** to be freeing.
*/
static SQLITE_NOINLINE void vdbeMemRelease(Mem *p){
  if( VdbeMemDynamic(p) ){
    sqlite3VdbeMemReleaseExternal(p);
  }
  if( p->zMalloc ){
    sqlite3DbFree(p->db, p->zMalloc);
    p->zMalloc = 0;
  }
  p->z = 0;
}

/*
** Release any memory held by the Mem. This may leave the Mem.flags in an
** inconsistent state, for example with (Mem.z==0) and (Mem.flags==MEM_Str).
**
** This routine releases both the Mem.xDel space and the Mem.zMalloc space.
** Use sqlite3VdbeMemReleaseExternal() to release just the Mem.xDel space.
*/
void sqlite3VdbeMemRelease(Mem *p){
  assert( sqlite3VdbeCheckMemInvariants(p) );
  if( VdbeMemDynamic(p) || p->zMalloc ){
    vdbeMemRelease(p);
  }else{
    p->z = 0;
................................................................................
** and flags gets srcType (either MEM_Ephem or MEM_Static).
*/
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
  assert( (pFrom->flags & MEM_RowSet)==0 );
  assert( pTo->db==pFrom->db );
  VdbeMemReleaseExtern(pTo);
  memcpy(pTo, pFrom, MEMCELLSIZE);
  assert( pTo->xDel==0 );
  if( (pFrom->flags&MEM_Static)==0 ){
    pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
    assert( srcType==MEM_Ephem || srcType==MEM_Static );
    pTo->flags |= srcType;
  }
}

................................................................................
  int rc = SQLITE_OK;

  assert( pTo->db==pFrom->db );
  assert( (pFrom->flags & MEM_RowSet)==0 );
  VdbeMemReleaseExtern(pTo);
  memcpy(pTo, pFrom, MEMCELLSIZE);
  pTo->flags &= ~MEM_Dyn;
  assert( pTo->xDel==0 );

  if( pTo->flags&(MEM_Str|MEM_Blob) ){
    if( 0==(pFrom->flags&MEM_Static) ){
      pTo->flags |= MEM_Ephem;
      rc = sqlite3VdbeMemMakeWriteable(pTo);
    }
  }
................................................................................
  Mem *pMem         /* OUT: Return data in this Mem structure. */
){
  char *zData;        /* Data from the btree layer */
  u32 available = 0;  /* Number of bytes available on the local btree page */
  int rc = SQLITE_OK; /* Return code */

  assert( sqlite3BtreeCursorIsValid(pCur) );
  assert( pMem->xDel==0 );

  /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() 
  ** that both the BtShared and database handle mutexes are held. */
  assert( (pMem->flags & MEM_RowSet)==0 );
  if( key ){
    zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
  }else{
................................................................................
  assert( zData!=0 );

  if( offset+amt<=available ){
    sqlite3VdbeMemRelease(pMem);
    pMem->z = &zData[offset];
    pMem->flags = MEM_Blob|MEM_Ephem;
    pMem->n = (int)amt;
  }else{
    pMem->flags = MEM_Null;
    if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
      if( key ){
        rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
      }else{
        rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
      }
      if( rc==SQLITE_OK ){
        pMem->z[amt] = 0;
        pMem->z[amt+1] = 0;
        pMem->flags = MEM_Blob|MEM_Term;
        pMem->n = (int)amt;
      }else{
        sqlite3VdbeMemRelease(pMem);
      }
    }
  }

  return rc;
}

/*