/ Check-in [153deac8]
Login

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

Overview
Comment:Ensure that all auxiliary data registered by calls to sqlite3_set_auxdata() is destroyed when the VM is halted.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 153deac8faca3bcc95f6f37e500b659b39b3e872
User & Date: dan 2013-07-18 18:29:24
Context
2013-07-18
18:45
Improved documentation for sqlite3_set_auxdata(). Ticket [406d3b2ef91c]. check-in: 62465ecb user: drh tags: trunk
18:29
Ensure that all auxiliary data registered by calls to sqlite3_set_auxdata() is destroyed when the VM is halted. check-in: 153deac8 user: dan tags: trunk
18:28
Fix a typo in the previous commit. Closed-Leaf check-in: cd9096e6 user: dan tags: typo
14:50
Fix a 8-byte alignment problem in the query planner that might cause problems on sparc when compiled with -m32. check-in: 5dcffa67 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

  1416   1416       assert( memIsValid(pArg) );
  1417   1417       apVal[i] = pArg;
  1418   1418       Deephemeralize(pArg);
  1419   1419       sqlite3VdbeMemStoreType(pArg);
  1420   1420       REGISTER_TRACE(pOp->p2+i, pArg);
  1421   1421     }
  1422   1422   
  1423         -  assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
  1424         -  if( pOp->p4type==P4_FUNCDEF ){
  1425         -    ctx.pFunc = pOp->p4.pFunc;
  1426         -    ctx.pVdbeFunc = 0;
  1427         -  }else{
  1428         -    ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
  1429         -    ctx.pFunc = ctx.pVdbeFunc->pFunc;
  1430         -  }
  1431         -
         1423  +  assert( pOp->p4type==P4_FUNCDEF );
         1424  +  ctx.pFunc = pOp->p4.pFunc;
  1432   1425     ctx.s.flags = MEM_Null;
  1433   1426     ctx.s.db = db;
  1434   1427     ctx.s.xDel = 0;
  1435   1428     ctx.s.zMalloc = 0;
         1429  +  ctx.iOp = pc;
         1430  +  ctx.pVdbe = p;
  1436   1431   
  1437   1432     /* The output cell may already have a buffer allocated. Move
  1438   1433     ** the pointer to ctx.s so in case the user-function can use
  1439   1434     ** the already allocated buffer instead of allocating a new one.
  1440   1435     */
  1441   1436     sqlite3VdbeMemMove(&ctx.s, pOut);
  1442   1437     MemSetTypeFlag(&ctx.s, MEM_Null);
................................................................................
  1451   1446     db->lastRowid = lastRowid;
  1452   1447     (*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */
  1453   1448     lastRowid = db->lastRowid;
  1454   1449   
  1455   1450     /* If any auxiliary data functions have been called by this user function,
  1456   1451     ** immediately call the destructor for any non-static values.
  1457   1452     */
  1458         -  if( ctx.pVdbeFunc ){
  1459         -    sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1);
  1460         -    pOp->p4.pVdbeFunc = ctx.pVdbeFunc;
  1461         -    pOp->p4type = P4_VDBEFUNC;
  1462         -  }
         1453  +  sqlite3VdbeDeleteAuxData(p, pc, pOp->p1);
  1463   1454   
  1464   1455     if( db->mallocFailed ){
  1465   1456       /* Even though a malloc() has failed, the implementation of the
  1466   1457       ** user function may have called an sqlite3_result_XXX() function
  1467   1458       ** to return a value. The following call releases any resources
  1468   1459       ** associated with such a value.
  1469   1460       */

Changes to src/vdbe.h.

    26     26   */
    27     27   typedef struct Vdbe Vdbe;
    28     28   
    29     29   /*
    30     30   ** The names of the following types declared in vdbeInt.h are required
    31     31   ** for the VdbeOp definition.
    32     32   */
    33         -typedef struct VdbeFunc VdbeFunc;
    34     33   typedef struct Mem Mem;
    35     34   typedef struct SubProgram SubProgram;
    36     35   
    37     36   /*
    38     37   ** A single instruction of the virtual machine has an opcode
    39     38   ** and as many as three operands.  The instruction is recorded
    40     39   ** as an instance of the following structure:
................................................................................
    50     49     union {             /* fourth parameter */
    51     50       int i;                 /* Integer value if p4type==P4_INT32 */
    52     51       void *p;               /* Generic pointer */
    53     52       char *z;               /* Pointer to data for string (char array) types */
    54     53       i64 *pI64;             /* Used when p4type is P4_INT64 */
    55     54       double *pReal;         /* Used when p4type is P4_REAL */
    56     55       FuncDef *pFunc;        /* Used when p4type is P4_FUNCDEF */
    57         -    VdbeFunc *pVdbeFunc;   /* Used when p4type is P4_VDBEFUNC */
    58     56       CollSeq *pColl;        /* Used when p4type is P4_COLLSEQ */
    59     57       Mem *pMem;             /* Used when p4type is P4_MEM */
    60     58       VTable *pVtab;         /* Used when p4type is P4_VTAB */
    61     59       KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
    62     60       int *ai;               /* Used when p4type is P4_INTARRAY */
    63     61       SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
    64     62       int (*xAdvance)(BtCursor *, int *);
................................................................................
   104    102   */
   105    103   #define P4_NOTUSED    0   /* The P4 parameter is not used */
   106    104   #define P4_DYNAMIC  (-1)  /* Pointer to a string obtained from sqliteMalloc() */
   107    105   #define P4_STATIC   (-2)  /* Pointer to a static string */
   108    106   #define P4_COLLSEQ  (-4)  /* P4 is a pointer to a CollSeq structure */
   109    107   #define P4_FUNCDEF  (-5)  /* P4 is a pointer to a FuncDef structure */
   110    108   #define P4_KEYINFO  (-6)  /* P4 is a pointer to a KeyInfo structure */
   111         -#define P4_VDBEFUNC (-7)  /* P4 is a pointer to a VdbeFunc structure */
   112    109   #define P4_MEM      (-8)  /* P4 is a pointer to a Mem*    structure */
   113    110   #define P4_TRANSIENT  0   /* P4 is a pointer to a transient string */
   114    111   #define P4_VTAB     (-10) /* P4 is a pointer to an sqlite3_vtab structure */
   115    112   #define P4_MPRINTF  (-11) /* P4 is a string obtained from sqlite3_mprintf() */
   116    113   #define P4_REAL     (-12) /* P4 is a 64-bit floating point value */
   117    114   #define P4_INT64    (-13) /* P4 is a 64-bit signed integer */
   118    115   #define P4_INT32    (-14) /* P4 is a 32-bit signed integer */

Changes to src/vdbeInt.h.

    40     40   
    41     41   /* Opaque type used by code in vdbesort.c */
    42     42   typedef struct VdbeSorter VdbeSorter;
    43     43   
    44     44   /* Opaque type used by the explainer */
    45     45   typedef struct Explain Explain;
    46     46   
           47  +/* Elements of the linked list at Vdbe.pAuxData */
           48  +typedef struct AuxData AuxData;
           49  +
    47     50   /*
    48     51   ** A cursor is a pointer into a single BTree within a database file.
    49     52   ** The cursor can seek to a BTree entry with a particular key, or
    50     53   ** loop over all entries of the Btree.  You can also insert new BTree
    51     54   ** entries or retrieve the key or data from the entry that the cursor
    52     55   ** is currently pointing to.
    53     56   ** 
................................................................................
   226    229   ** Return true if a memory cell is not marked as invalid.  This macro
   227    230   ** is for use inside assert() statements only.
   228    231   */
   229    232   #ifdef SQLITE_DEBUG
   230    233   #define memIsValid(M)  ((M)->flags & MEM_Invalid)==0
   231    234   #endif
   232    235   
   233         -
   234         -/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
   235         -** additional information about auxiliary information bound to arguments
   236         -** of the function.  This is used to implement the sqlite3_get_auxdata()
   237         -** and sqlite3_set_auxdata() APIs.  The "auxdata" is some auxiliary data
   238         -** that can be associated with a constant argument to a function.  This
   239         -** allows functions such as "regexp" to compile their constant regular
   240         -** expression argument once and reused the compiled code for multiple
   241         -** invocations.
          236  +/*
          237  +** Each auxilliary data pointer stored by a user defined function 
          238  +** implementation calling sqlite3_set_auxdata() is stored in an instance
          239  +** of this structure. All such structures associated with a single VM
          240  +** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
          241  +** when the VM is halted (if not before).
   242    242   */
   243         -struct VdbeFunc {
   244         -  FuncDef *pFunc;               /* The definition of the function */
   245         -  int nAux;                     /* Number of entries allocated for apAux[] */
   246         -  struct AuxData {
   247         -    void *pAux;                   /* Aux data for the i-th argument */
   248         -    void (*xDelete)(void *);      /* Destructor for the aux data */
   249         -  } apAux[1];                   /* One slot for each function argument */
          243  +struct AuxData {
          244  +  int iOp;                        /* Instruction number of OP_Function opcode */
          245  +  int iArg;                       /* Index of function argument. */
          246  +  void *pAux;                     /* Aux data pointer */
          247  +  void (*xDelete)(void *);        /* Destructor for the aux data */
          248  +  AuxData *pNext;                 /* Next element in list */
   250    249   };
   251    250   
   252    251   /*
   253    252   ** The "context" argument for a installable function.  A pointer to an
   254    253   ** instance of this structure is the first argument to the routines used
   255    254   ** implement the SQL functions.
   256    255   **
................................................................................
   260    259   ** structure are known.
   261    260   **
   262    261   ** This structure is defined inside of vdbeInt.h because it uses substructures
   263    262   ** (Mem) which are only defined there.
   264    263   */
   265    264   struct sqlite3_context {
   266    265     FuncDef *pFunc;       /* Pointer to function information.  MUST BE FIRST */
   267         -  VdbeFunc *pVdbeFunc;  /* Auxilary data, if created. */
   268    266     Mem s;                /* The return value is stored here */
   269    267     Mem *pMem;            /* Memory cell used to store aggregate context */
   270    268     CollSeq *pColl;       /* Collating sequence */
   271    269     int isError;          /* Error code returned by the function. */
   272    270     int skipFlag;         /* Skip skip accumulator loading if true */
          271  +  int iOp;              /* Instruction number of OP_Function */
          272  +  Vdbe *pVdbe;          /* The VM that owns this context */
   273    273   };
   274    274   
   275    275   /*
   276    276   ** An Explain object accumulates indented output which is helpful
   277    277   ** in describing recursive data structures.
   278    278   */
   279    279   struct Explain {
................................................................................
   364    364     VdbeFrame *pFrame;      /* Parent frame */
   365    365     VdbeFrame *pDelFrame;   /* List of frame objects to free on VM reset */
   366    366     int nFrame;             /* Number of frames in pFrame list */
   367    367     u32 expmask;            /* Binding to these vars invalidates VM */
   368    368     SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
   369    369     int nOnceFlag;          /* Size of array aOnceFlag[] */
   370    370     u8 *aOnceFlag;          /* Flags for OP_Once */
          371  +  AuxData *pAuxData;      /* Linked list of auxdata allocations */
   371    372   };
   372    373   
   373    374   /*
   374    375   ** The following are allowed values for Vdbe.magic
   375    376   */
   376    377   #define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */
   377    378   #define VDBE_MAGIC_RUN      0xbdf20da3    /* VDBE is ready to execute */
................................................................................
   387    388   #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
   388    389   void sqlite3VdbePrintOp(FILE*, int, Op*);
   389    390   #endif
   390    391   u32 sqlite3VdbeSerialTypeLen(u32);
   391    392   u32 sqlite3VdbeSerialType(Mem*, int);
   392    393   u32 sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
   393    394   u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
   394         -void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
          395  +void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
   395    396   
   396    397   int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
   397    398   int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
   398    399   int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
   399    400   int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
   400    401   int sqlite3VdbeExec(Vdbe*);
   401    402   int sqlite3VdbeList(Vdbe*);

Changes to src/vdbeapi.c.

   580    580   }
   581    581   
   582    582   /*
   583    583   ** Return the auxilary data pointer, if any, for the iArg'th argument to
   584    584   ** the user-function defined by pCtx.
   585    585   */
   586    586   void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
   587         -  VdbeFunc *pVdbeFunc;
          587  +  AuxData *pAuxData;
   588    588   
   589    589     assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
   590         -  pVdbeFunc = pCtx->pVdbeFunc;
   591         -  if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){
   592         -    return 0;
          590  +  for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
          591  +    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
   593    592     }
   594         -  return pVdbeFunc->apAux[iArg].pAux;
          593  +
          594  +  return (pAuxData ? pAuxData->pAux : 0);
   595    595   }
   596    596   
   597    597   /*
   598    598   ** Set the auxilary data pointer and delete function, for the iArg'th
   599    599   ** argument to the user-function defined by pCtx. Any previous value is
   600    600   ** deleted by calling the delete function specified when it was set.
   601    601   */
   602    602   void sqlite3_set_auxdata(
   603    603     sqlite3_context *pCtx, 
   604    604     int iArg, 
   605    605     void *pAux, 
   606    606     void (*xDelete)(void*)
   607    607   ){
   608         -  struct AuxData *pAuxData;
   609         -  VdbeFunc *pVdbeFunc;
   610         -  if( iArg<0 ) goto failed;
          608  +  AuxData *pAuxData;
          609  +  Vdbe *pVdbe = pCtx->pVdbe;
   611    610   
   612    611     assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
   613         -  pVdbeFunc = pCtx->pVdbeFunc;
   614         -  if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
   615         -    int nAux = (pVdbeFunc ? pVdbeFunc->nAux : 0);
   616         -    int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
   617         -    pVdbeFunc = sqlite3DbRealloc(pCtx->s.db, pVdbeFunc, nMalloc);
   618         -    if( !pVdbeFunc ){
   619         -      goto failed;
   620         -    }
   621         -    pCtx->pVdbeFunc = pVdbeFunc;
   622         -    memset(&pVdbeFunc->apAux[nAux], 0, sizeof(struct AuxData)*(iArg+1-nAux));
   623         -    pVdbeFunc->nAux = iArg+1;
   624         -    pVdbeFunc->pFunc = pCtx->pFunc;
          612  +  if( iArg<0 ) goto failed;
          613  +
          614  +  for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
          615  +    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
   625    616     }
   626         -
   627         -  pAuxData = &pVdbeFunc->apAux[iArg];
   628         -  if( pAuxData->pAux && pAuxData->xDelete ){
          617  +  if( pAuxData==0 ){
          618  +    pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
          619  +    if( !pAuxData ) goto failed;
          620  +    pAuxData->iOp = pCtx->iOp;
          621  +    pAuxData->iArg = iArg;
          622  +    pAuxData->pNext = pVdbe->pAuxData;
          623  +    pVdbe->pAuxData = pAuxData;
          624  +  }else if( pAuxData->xDelete ){
   629    625       pAuxData->xDelete(pAuxData->pAux);
   630    626     }
          627  +
   631    628     pAuxData->pAux = pAux;
   632    629     pAuxData->xDelete = xDelete;
   633    630     return;
   634    631   
   635    632   failed:
   636    633     if( xDelete ){
   637    634       xDelete(pAux);

Changes to src/vdbeaux.c.

   608    608           sqlite3DbFree(db, p4);
   609    609           break;
   610    610         }
   611    611         case P4_MPRINTF: {
   612    612           if( db->pnBytesFreed==0 ) sqlite3_free(p4);
   613    613           break;
   614    614         }
   615         -      case P4_VDBEFUNC: {
   616         -        VdbeFunc *pVdbeFunc = (VdbeFunc *)p4;
   617         -        freeEphemeralFunction(db, pVdbeFunc->pFunc);
   618         -        if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
   619         -        sqlite3DbFree(db, pVdbeFunc);
   620         -        break;
   621         -      }
   622    615         case P4_FUNCDEF: {
   623    616           freeEphemeralFunction(db, (FuncDef*)p4);
   624    617           break;
   625    618         }
   626    619         case P4_MEM: {
   627    620           if( db->pnBytesFreed==0 ){
   628    621             sqlite3ValueFree((sqlite3_value*)p4);
................................................................................
  1644   1637       releaseMemArray(&p->aMem[1], p->nMem);
  1645   1638     }
  1646   1639     while( p->pDelFrame ){
  1647   1640       VdbeFrame *pDel = p->pDelFrame;
  1648   1641       p->pDelFrame = pDel->pParent;
  1649   1642       sqlite3VdbeFrameDelete(pDel);
  1650   1643     }
         1644  +
         1645  +  /* Delete any auxdata allocations made by the VM */
         1646  +  sqlite3VdbeDeleteAuxData(p, -1, 0);
         1647  +  assert( p->pAuxData==0 );
  1651   1648   }
  1652   1649   
  1653   1650   /*
  1654   1651   ** Clean up the VM after execution.
  1655   1652   **
  1656   1653   ** This routine will automatically close any cursors, lists, and/or
  1657   1654   ** sorters that were left open.  It also deletes the values of
................................................................................
  2442   2439       assert( (rc & p->db->errMask)==rc );
  2443   2440     }
  2444   2441     sqlite3VdbeDelete(p);
  2445   2442     return rc;
  2446   2443   }
  2447   2444   
  2448   2445   /*
  2449         -** Call the destructor for each auxdata entry in pVdbeFunc for which
  2450         -** the corresponding bit in mask is clear.  Auxdata entries beyond 31
  2451         -** are always destroyed.  To destroy all auxdata entries, call this
  2452         -** routine with mask==0.
         2446  +** If parameter iOp is less than zero, then invoke the destructor for
         2447  +** all auxiliary data pointers currently cached by the VM passed as
         2448  +** the first argument.
         2449  +**
         2450  +** Or, if iOp is greater than or equal to zero, then the destructor is
         2451  +** only invoked for those auxiliary data pointers created by the user 
         2452  +** function invoked by the OP_Function opcode at instruction iOp of 
         2453  +** VM pVdbe, and only then if:
         2454  +**
         2455  +**    * the associated function parameter is the 32nd or later (counting
         2456  +**      from left to right), or
         2457  +**
         2458  +**    * the corresponding bit in argument mask is clear (where the first
         2459  +**      function parameter corrsponds to bit 0 etc.).
  2453   2460   */
  2454         -void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
  2455         -  int i;
  2456         -  for(i=0; i<pVdbeFunc->nAux; i++){
  2457         -    struct AuxData *pAux = &pVdbeFunc->apAux[i];
  2458         -    if( (i>31 || !(mask&(((u32)1)<<i))) && pAux->pAux ){
         2461  +void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
         2462  +  AuxData **pp = &pVdbe->pAuxData;
         2463  +  while( *pp ){
         2464  +    AuxData *pAux = *pp;
         2465  +    if( (iOp<0)
         2466  +     || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & ((u32)1<<pAux->iArg))))
         2467  +    ){
  2459   2468         if( pAux->xDelete ){
  2460   2469           pAux->xDelete(pAux->pAux);
  2461   2470         }
  2462         -      pAux->pAux = 0;
         2471  +      *pp = pAux->pNext;
         2472  +      sqlite3DbFree(pVdbe->db, pAux);
         2473  +    }else{
         2474  +      pp= &pAux->pNext;
  2463   2475       }
  2464   2476     }
  2465   2477   }
  2466   2478   
  2467   2479   /*
  2468   2480   ** Free all memory associated with the Vdbe passed as the second argument,
  2469   2481   ** except for object itself, which is preserved.

Changes to test/func.test.

   677    677     sqlite3_bind_text $STMT 1 hello\000 -1
   678    678     set res [list]
   679    679     while { "SQLITE_ROW"==[sqlite3_step $STMT] } {
   680    680       lappend res [sqlite3_column_text $STMT 0]
   681    681     }
   682    682     lappend res [sqlite3_finalize $STMT]
   683    683   } {{0 0} {1 0} SQLITE_OK}
          684  +
          685  +# Test that auxiliary data is discarded when a statement is reset.
          686  +do_execsql_test 13.8.1 {
          687  +  SELECT test_auxdata('constant') FROM t4;
          688  +} {0 1}
          689  +do_execsql_test 13.8.2 {
          690  +  SELECT test_auxdata('constant') FROM t4;
          691  +} {0 1}
          692  +db cache flush
          693  +do_execsql_test 13.8.3 {
          694  +  SELECT test_auxdata('constant') FROM t4;
          695  +} {0 1}
          696  +set V "one"
          697  +do_execsql_test 13.8.4 {
          698  +  SELECT test_auxdata($V), $V FROM t4;
          699  +} {0 one 1 one}
          700  +set V "two"
          701  +do_execsql_test 13.8.5 {
          702  +  SELECT test_auxdata($V), $V FROM t4;
          703  +} {0 two 1 two}
          704  +db cache flush
          705  +set V "three"
          706  +do_execsql_test 2.3 {
          707  +  SELECT test_auxdata($V), $V FROM t4;
          708  +} {0 three 1 three}
          709  +
   684    710   
   685    711   # Make sure that a function with a very long name is rejected
   686    712   do_test func-14.1 {
   687    713     catch {
   688    714       db function [string repeat X 254] {return "hello"}
   689    715     } 
   690    716   } {0}