1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-16 23:02:26 +03:00

Free up the MEM_Frame bit in Mem.flags object. Store VdbeFrame objects

as MEM_Blob with a special Mem.xDel pointer instead.

FossilOrigin-Name: 62db5fd47660bbc4fcf2c6d4a6c5a3077f12c6442a128d22b66b789a0409ef32
This commit is contained in:
drh
2018-08-29 18:47:22 +00:00
parent c0d2117f1c
commit 72f56ef95d
6 changed files with 70 additions and 25 deletions

View File

@@ -6050,7 +6050,7 @@ case OP_Program: { /* jump */
** of the current program, and the memory required at runtime to execute
** the trigger program. If this trigger has been fired before, then pRt
** is already allocated. Otherwise, it must be initialized. */
if( (pRt->flags&MEM_Frame)==0 ){
if( (pRt->flags&MEM_Blob)==0 ){
/* SubProgram.nMem is set to the number of memory cells used by the
** program stored in SubProgram.aOp. As well as these, one memory
** cell is required for each cursor used by the program. Set local
@@ -6068,8 +6068,10 @@ case OP_Program: { /* jump */
goto no_mem;
}
sqlite3VdbeMemRelease(pRt);
pRt->flags = MEM_Frame;
pRt->u.pFrame = pFrame;
pRt->flags = MEM_Blob|MEM_Dyn;
pRt->z = (char*)pFrame;
pRt->n = nByte;
pRt->xDel = sqlite3VdbeFrameMemDel;
pFrame->v = p;
pFrame->nChildMem = nMem;
@@ -6085,6 +6087,9 @@ case OP_Program: { /* jump */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
pFrame->anExec = p->anExec;
#endif
#ifdef SQLITE_DEBUG
pFrame->iFrameMagic = SQLITE_FRAME_MAGIC;
#endif
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
@@ -6092,7 +6097,8 @@ case OP_Program: { /* jump */
pMem->db = db;
}
}else{
pFrame = pRt->u.pFrame;
pFrame = (VdbeFrame*)pRt->z;
assert( pRt->xDel==sqlite3VdbeFrameMemDel );
assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem
|| (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
assert( pProgram->nCsr==pFrame->nChildCsr );

View File

@@ -169,6 +169,9 @@ struct VdbeFrame {
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
AuxData *pAuxData; /* Linked list of auxdata allocations */
#if SQLITE_DEBUG
u32 iFrameMagic; /* magic number for sanity checking */
#endif
int nCursor; /* Number of entries in apCsr */
int pc; /* Program Counter in parent (calling) frame */
int nOp; /* Size of aOp array */
@@ -179,6 +182,13 @@ struct VdbeFrame {
int nDbChange; /* Value of db->nChange */
};
/* Magic number for sanity checking on VdbeFrame objects */
#define SQLITE_FRAME_MAGIC 0x879fb71e
/*
** Return a pointer to the array of registers allocated for use
** by a VdbeFrame.
*/
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
/*
@@ -194,7 +204,6 @@ struct sqlite3_value {
const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
FuncDef *pDef; /* Used only when flags==MEM_Agg */
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
} u;
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
@@ -239,7 +248,7 @@ struct sqlite3_value {
#define MEM_Blob 0x0010 /* Value is a BLOB */
#define MEM_AffMask 0x001f /* Mask of affinity bits */
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
/* Available 0x0040 */
#define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
#define MEM_TypeMask 0xc1ff /* Mask of type bits */
@@ -266,7 +275,7 @@ struct sqlite3_value {
** that needs to be deallocated to avoid a leak.
*/
#define VdbeMemDynamic(X) \
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet))!=0)
/*
** Clear any existing type flags from a Mem and replace them with f
@@ -500,7 +509,11 @@ const char *sqlite3OpcodeName(int);
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
int sqlite3VdbeCloseStatement(Vdbe *, int);
void sqlite3VdbeFrameDelete(VdbeFrame*);
#ifdef SQLITE_DEBUG
int sqlite3VdbeFrameIsValid(VdbeFrame*);
#endif
void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */
void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */
int sqlite3VdbeFrameRestore(VdbeFrame *);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);

View File

@@ -1661,9 +1661,9 @@ static void releaseMemArray(Mem *p, int N){
*/
testcase( p->flags & MEM_Agg );
testcase( p->flags & MEM_Dyn );
testcase( p->flags & MEM_Frame );
testcase( p->xDel==sqlite3VdbeFrameMemDel );
testcase( p->flags & MEM_RowSet );
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet) ){
sqlite3VdbeMemRelease(p);
}else if( p->szMalloc ){
sqlite3DbFreeNN(db, p->zMalloc);
@@ -1675,6 +1675,35 @@ static void releaseMemArray(Mem *p, int N){
}
}
#ifdef SQLITE_DEBUG
/*
** Verify that pFrame is a valid VdbeFrame pointer. Return true if it is
** and false if something is wrong.
**
** This routine is intended for use inside of assert() statements only.
*/
int sqlite3VdbeFrameIsValid(VdbeFrame *pFrame){
if( pFrame->iFrameMagic!=SQLITE_FRAME_MAGIC ) return 0;
return 1;
}
#endif
/*
** This is a destructor on a Mem object (which is really an sqlite3_value)
** that deletes the Frame object that is attached to it as a blob.
**
** This routine does not delete the Frame right away. It merely adds the
** frame to a list of frames to be deleted when the Vdbe halts.
*/
void sqlite3VdbeFrameMemDel(void *pArg){
VdbeFrame *pFrame = (VdbeFrame*)pArg;
assert( sqlite3VdbeFrameIsValid(pFrame) );
pFrame->pParent = pFrame->v->pDelFrame;
pFrame->v->pDelFrame = pFrame;
}
/*
** Delete a VdbeFrame object and its contents. VdbeFrame objects are
** allocated by the OP_Program opcode in sqlite3VdbeExec().
@@ -1683,6 +1712,7 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){
int i;
Mem *aMem = VdbeFrameMem(p);
VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem];
assert( sqlite3VdbeFrameIsValid(p) );
for(i=0; i<p->nChildCsr; i++){
sqlite3VdbeFreeCursor(p->v, apCsr[i]);
}

View File

@@ -43,7 +43,7 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
if( p->flags & MEM_Null ){
/* Cannot be both MEM_Null and some other type */
assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
|MEM_RowSet|MEM_Frame|MEM_Agg))==0 );
|MEM_RowSet|MEM_Agg))==0 );
/* If MEM_Null is set, then either the value is a pure NULL (the usual
** case) or it is a pointer set using sqlite3_bind_pointer() or
@@ -467,10 +467,6 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){
p->xDel((void *)p->z);
}else if( p->flags&MEM_RowSet ){
sqlite3RowSetClear(p->u.pRowSet);
}else if( p->flags&MEM_Frame ){
VdbeFrame *pFrame = p->u.pFrame;
pFrame->pParent = pFrame->v->pDelFrame;
pFrame->v->pDelFrame = pFrame;
}
p->flags = MEM_Null;
}