📄 vdbe.c
字号:
sqliteFree(pAgg->apFunc); pAgg->apFunc = 0; pAgg->pCurrent = 0; pAgg->pSearch = 0; pAgg->nMem = 0;}/*** Insert a new aggregate element and make it the element that** has focus.**** Return 0 on success and 1 if memory is exhausted.*/static int AggInsert(Agg *p, char *zKey, int nKey){ AggElem *pElem, *pOld; int i; pElem = sqliteMalloc( sizeof(AggElem) + nKey + (p->nMem-1)*sizeof(pElem->aMem[0]) ); if( pElem==0 ) return 1; pElem->zKey = (char*)&pElem->aMem[p->nMem]; memcpy(pElem->zKey, zKey, nKey); pElem->nKey = nKey; pOld = sqliteHashInsert(&p->hash, pElem->zKey, pElem->nKey, pElem); if( pOld!=0 ){ assert( pOld==pElem ); /* Malloc failed on insert */ sqliteFree(pOld); return 0; } for(i=0; i<p->nMem; i++){ pElem->aMem[i].s.flags = STK_Null; } p->pCurrent = pElem; return 0;}/*** Get the AggElem currently in focus*/#define AggInFocus(P) ((P).pCurrent ? (P).pCurrent : _AggInFocus(&(P)))static AggElem *_AggInFocus(Agg *p){ HashElem *pElem = sqliteHashFirst(&p->hash); if( pElem==0 ){ AggInsert(p,"",1); pElem = sqliteHashFirst(&p->hash); } return pElem ? sqliteHashData(pElem) : 0;}/*** Convert the given stack entity into a string if it isn't one** already.*/#define Stringify(P,I) if((aStack[I].flags & STK_Str)==0){hardStringify(P,I);}static int hardStringify(Vdbe *p, int i){ Stack *pStack = &p->aStack[i]; int fg = pStack->flags; if( fg & STK_Real ){ sprintf(pStack->z,"%.15g",pStack->r); }else if( fg & STK_Int ){ sprintf(pStack->z,"%d",pStack->i); }else{ pStack->z[0] = 0; } p->zStack[i] = pStack->z; pStack->n = strlen(pStack->z)+1; pStack->flags = STK_Str; return 0;}/*** Convert the given stack entity into a string that has been obtained** from sqliteMalloc(). This is different from Stringify() above in that** Stringify() will use the NBFS bytes of static string space if the string** will fit but this routine always mallocs for space.** Return non-zero if we run out of memory.*/#define Dynamicify(P,I) ((aStack[I].flags & STK_Dyn)==0 ? hardDynamicify(P,I):0)static int hardDynamicify(Vdbe *p, int i){ Stack *pStack = &p->aStack[i]; int fg = pStack->flags; char *z; if( (fg & STK_Str)==0 ){ hardStringify(p, i); } assert( (fg & STK_Dyn)==0 ); z = sqliteMallocRaw( pStack->n ); if( z==0 ) return 1; memcpy(z, p->zStack[i], pStack->n); p->zStack[i] = z; pStack->flags |= STK_Dyn; return 0;}/*** An ephemeral string value (signified by the STK_Ephem flag) contains** a pointer to a dynamically allocated string where some other entity** is responsible for deallocating that string. Because the stack entry** does not control the string, it might be deleted without the stack** entry knowing it.**** This routine converts an ephemeral string into a dynamically allocated** string that the stack entry itself controls. In other words, it** converts an STK_Ephem string into an STK_Dyn string.*/#define Deephemeralize(P,I) \ if( ((P)->aStack[I].flags&STK_Ephem)!=0 && hardDeephem(P,I) ){ goto no_mem;}static int hardDeephem(Vdbe *p, int i){ Stack *pStack = &p->aStack[i]; char **pzStack = &p->zStack[i]; char *z; assert( (pStack->flags & STK_Ephem)!=0 ); z = sqliteMallocRaw( pStack->n ); if( z==0 ) return 1; memcpy(z, *pzStack, pStack->n); *pzStack = z; pStack->flags &= ~STK_Ephem; pStack->flags |= STK_Dyn; return 0;}/*** Release the memory associated with the given stack level*/#define Release(P,I) if((P)->aStack[I].flags&STK_Dyn){ hardRelease(P,I); }static void hardRelease(Vdbe *p, int i){ sqliteFree(p->zStack[i]); p->zStack[i] = 0; p->aStack[i].flags &= ~(STK_Str|STK_Dyn|STK_Static|STK_Ephem);}/*** Return TRUE if zNum is a 32-bit signed integer and write** the value of the integer into *pNum. If zNum is not an integer** or is an integer that is too large to be expressed with just 32** bits, then return false.**** Under Linux (RedHat 7.2) this routine is much faster than atoi()** for converting strings into integers.*/static int toInt(const char *zNum, int *pNum){ int v = 0; int neg; int i, c; if( *zNum=='-' ){ neg = 1; zNum++; }else if( *zNum=='+' ){ neg = 0; zNum++; }else{ neg = 0; } for(i=0; (c=zNum[i])>='0' && c<='9'; i++){ v = v*10 + c - '0'; } *pNum = neg ? -v : v; return c==0 && i>0 && (i<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0));}/*** Convert the given stack entity into a integer if it isn't one** already.**** Any prior string or real representation is invalidated. ** NULLs are converted into 0.*/#define Integerify(P,I) \ if(((P)->aStack[(I)].flags&STK_Int)==0){ hardIntegerify(P,I); }static void hardIntegerify(Vdbe *p, int i){ if( p->aStack[i].flags & STK_Real ){ p->aStack[i].i = (int)p->aStack[i].r; Release(p, i); }else if( p->aStack[i].flags & STK_Str ){ toInt(p->zStack[i], &p->aStack[i].i); Release(p, i); }else{ p->aStack[i].i = 0; } p->aStack[i].flags = STK_Int;}/*** Get a valid Real representation for the given stack element.**** Any prior string or integer representation is retained.** NULLs are converted into 0.0.*/#define Realify(P,I) \ if(((P)->aStack[(I)].flags&STK_Real)==0){ hardRealify(P,I); }static void hardRealify(Vdbe *p, int i){ if( p->aStack[i].flags & STK_Str ){ p->aStack[i].r = atof(p->zStack[i]); }else if( p->aStack[i].flags & STK_Int ){ p->aStack[i].r = p->aStack[i].i; }else{ p->aStack[i].r = 0.0; } p->aStack[i].flags |= STK_Real;}/*** Pop the stack N times. Free any memory associated with the** popped stack elements.*/static void PopStack(Vdbe *p, int N){ assert( N>=0 ); if( p->zStack==0 ) return; assert( p->aStack || sqlite_malloc_failed ); if( p->aStack==0 ) return; while( N-- > 0 ){ if( p->aStack[p->tos].flags & STK_Dyn ){ sqliteFree(p->zStack[p->tos]); } p->aStack[p->tos].flags = 0; p->zStack[p->tos] = 0; p->tos--; }}/*** Here is a macro to handle the common case of popping the stack** once. This macro only works from within the sqliteVdbeExec()** function.*/#define POPSTACK \ assert(p->tos>=0); \ if( aStack[p->tos].flags & STK_Dyn ) sqliteFree(zStack[p->tos]); \ p->tos--;/*** Delete a keylist*/static void KeylistFree(Keylist *p){ while( p ){ Keylist *pNext = p->pNext; sqliteFree(p); p = pNext; }}/*** Close a cursor and release all the resources that cursor happens** to hold.*/static void cleanupCursor(Cursor *pCx){ if( pCx->pCursor ){ sqliteBtreeCloseCursor(pCx->pCursor); } if( pCx->pBt ){ sqliteBtreeClose(pCx->pBt); } sqliteFree(pCx->pData); memset(pCx, 0, sizeof(Cursor));}/*** Close all cursors*/static void closeAllCursors(Vdbe *p){ int i; for(i=0; i<p->nCursor; i++){ cleanupCursor(&p->aCsr[i]); } sqliteFree(p->aCsr); p->aCsr = 0; p->nCursor = 0;}/*** Remove any elements that remain on the sorter for the VDBE given.*/static void SorterReset(Vdbe *p){ while( p->pSort ){ Sorter *pSorter = p->pSort; p->pSort = pSorter->pNext; sqliteFree(pSorter->zKey); sqliteFree(pSorter->pData); sqliteFree(pSorter); }}/*** Clean up the VM after execution.**** This routine will automatically close any cursors, lists, and/or** sorters that were left open.*/static void Cleanup(Vdbe *p){ int i; PopStack(p, p->tos+1); closeAllCursors(p); if( p->aMem ){ for(i=0; i<p->nMem; i++){ if( p->aMem[i].s.flags & STK_Dyn ){ sqliteFree(p->aMem[i].z); } } } sqliteFree(p->aMem); p->aMem = 0; p->nMem = 0; if( p->pList ){ KeylistFree(p->pList); p->pList = 0; } SorterReset(p); if( p->pFile ){ if( p->pFile!=stdin ) fclose(p->pFile); p->pFile = 0; } if( p->azField ){ sqliteFree(p->azField); p->azField = 0; } p->nField = 0; if( p->zLine ){ sqliteFree(p->zLine); p->zLine = 0; } p->nLineAlloc = 0; AggReset(&p->agg); if( p->aSet ){ for(i=0; i<p->nSet; i++){ sqliteHashClear(&p->aSet[i].hash); } } sqliteFree(p->aSet); p->aSet = 0; p->nSet = 0; if( p->keylistStack ){ int ii; for(ii = 0; ii < p->keylistStackDepth; ii++){ KeylistFree(p->keylistStack[ii]); } sqliteFree(p->keylistStack); p->keylistStackDepth = 0; p->keylistStack = 0; } sqliteFree(p->zErrMsg); p->zErrMsg = 0; p->magic = VDBE_MAGIC_DEAD;}/*** Delete an entire VDBE.*/void sqliteVdbeDelete(Vdbe *p){ int i; if( p==0 ) return; Cleanup(p); if( p->pPrev ){ p->pPrev->pNext = p->pNext; }else{ assert( p->db->pVdbe==p ); p->db->pVdbe = p->pNext; } if( p->pNext ){ p->pNext->pPrev = p->pPrev; } p->pPrev = p->pNext = 0; if( p->nOpAlloc==0 ){ p->aOp = 0; p->nOp = 0; } for(i=0; i<p->nOp; i++){ if( p->aOp[i].p3type==P3_DYNAMIC ){ sqliteFree(p->aOp[i].p3); } } sqliteFree(p->aOp); sqliteFree(p->aLabel); sqliteFree(p->aStack); sqliteFree(p);}/*** Give a listing of the program in the virtual machine.**** The interface is the same as sqliteVdbeExec(). But instead of** running the code, it invokes the callback once for each instruction.** This feature is used to implement "EXPLAIN".*/int sqliteVdbeList( Vdbe *p /* The VDBE */){ sqlite *db = p->db; int i; static char *azColumnNames[] = { "addr", "opcode", "p1", "p2", "p3", "int", "text", "int", "int", "text", 0 }; assert( p->popStack==0 ); assert( p->explain ); p->azColName = azColumnNames; p->azResColumn = p->zStack; for(i=0; i<5; i++) p->zStack[i] = p->aStack[i].z; p->rc = SQLITE_OK; for(i=p->pc; p->rc==SQLITE_OK && i<p->nOp; i++){ if( db->flags & SQLITE_Interrupt ){ db->flags &= ~SQLITE_Interrupt; if( db->magic!=SQLITE_MAGIC_BUSY ){ p->rc = SQLITE_MISUSE; }else{ p->rc = SQLITE_INTERRUPT; } sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), 0); break; } sprintf(p->zStack[0],"%d",i); sprintf(p->zStack[2],"%d", p->aOp[i].p1); sprintf(p->zStack[3],"%d", p->aOp[i].p2); if( p->aOp[i].p3type==P3_POINTER ){ sprintf(p->aStack[4].z, "ptr(%#x)", (int)p->aOp[i].p3); p->zStack[4] = p->aStack[4].z; }else{ p->zStack[4] = p->aOp[i].p3; } p->zStack[1] = sqliteOpcodeNames[p->aOp[i].opcode]; if( p->xCallback==0 ){ p->pc = i+1; p->azResColumn = p->zStack; p->nResColumn = 5; return SQLITE_ROW; } if( sqliteSafetyOff(db) ){ p->rc = SQLITE_MISUSE; break; } if( p->xCallback(p->pCbArg, 5, p->zStack, p->azColName) ){ p->rc = SQLITE_ABORT; } if( sqliteSafetyOn(db) ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -