📄 vdbeaux.c
字号:
static char *displayP3(Op *pOp, char *zTemp, int nTemp){ char *zP3; assert( nTemp>=20 ); switch( pOp->p3type ){ case P3_KEYINFO: { int i, j; KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3; sprintf(zTemp, "keyinfo(%d", pKeyInfo->nField); i = strlen(zTemp); for(j=0; j<pKeyInfo->nField; j++){ CollSeq *pColl = pKeyInfo->aColl[j]; if( pColl ){ int n = strlen(pColl->zName); if( i+n>nTemp-6 ){ strcpy(&zTemp[i],",..."); break; } zTemp[i++] = ','; if( pKeyInfo->aSortOrder && pKeyInfo->aSortOrder[j] ){ zTemp[i++] = '-'; } strcpy(&zTemp[i], pColl->zName); i += n; }else if( i+4<nTemp-6 ){ strcpy(&zTemp[i],",nil"); i += 4; } } zTemp[i++] = ')'; zTemp[i] = 0; assert( i<nTemp ); zP3 = zTemp; break; } case P3_COLLSEQ: { CollSeq *pColl = (CollSeq*)pOp->p3; sprintf(zTemp, "collseq(%.20s)", pColl->zName); zP3 = zTemp; break; } case P3_FUNCDEF: { FuncDef *pDef = (FuncDef*)pOp->p3; char zNum[30]; sprintf(zTemp, "%.*s", nTemp, pDef->zName); sprintf(zNum,"(%d)", pDef->nArg); if( strlen(zTemp)+strlen(zNum)+1<=nTemp ){ strcat(zTemp, zNum); } zP3 = zTemp; break; } default: { zP3 = pOp->p3; if( zP3==0 || pOp->opcode==OP_Noop ){ zP3 = ""; } } } return zP3;}#endif#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)/*** Print a single opcode. This routine is used for debugging only.*/void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ char *zP3; char zPtr[50]; static const char *zFormat1 = "%4d %-13s %4d %4d %s\n"; if( pOut==0 ) pOut = stdout; zP3 = displayP3(pOp, zPtr, sizeof(zPtr)); fprintf(pOut, zFormat1, pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3); fflush(pOut);}#endif/*** Release an array of N Mem elements*/static void releaseMemArray(Mem *p, int N){ if( p ){ while( N-->0 ){ sqlite3VdbeMemRelease(p++); } }}#ifndef SQLITE_OMIT_EXPLAIN/*** Give a listing of the program in the virtual machine.**** The interface is the same as sqlite3VdbeExec(). But instead of** running the code, it invokes the callback once for each instruction.** This feature is used to implement "EXPLAIN".*/int sqlite3VdbeList( Vdbe *p /* The VDBE */){ sqlite3 *db = p->db; int i; int rc = SQLITE_OK; assert( p->explain ); if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE; assert( db->magic==SQLITE_MAGIC_BUSY ); assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY ); /* Even though this opcode does not put dynamic strings onto the ** the stack, they may become dynamic if the user calls ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. */ if( p->pTos==&p->aStack[4] ){ releaseMemArray(p->aStack, 5); } p->resOnStack = 0; i = p->pc++; if( i>=p->nOp ){ p->rc = SQLITE_OK; rc = SQLITE_DONE; }else if( db->flags & SQLITE_Interrupt ){ db->flags &= ~SQLITE_Interrupt; p->rc = SQLITE_INTERRUPT; rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0); }else{ Op *pOp = &p->aOp[i]; Mem *pMem = p->aStack; pMem->flags = MEM_Int; pMem->type = SQLITE_INTEGER; pMem->i = i; /* Program counter */ pMem++; pMem->flags = MEM_Static|MEM_Str|MEM_Term; pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */ pMem->n = strlen(pMem->z); pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; pMem++; pMem->flags = MEM_Int; pMem->i = pOp->p1; /* P1 */ pMem->type = SQLITE_INTEGER; pMem++; pMem->flags = MEM_Int; pMem->i = pOp->p2; /* P2 */ pMem->type = SQLITE_INTEGER; pMem++; pMem->flags = MEM_Short|MEM_Str|MEM_Term; /* P3 */ pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort)); pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; p->nResColumn = 5; p->pTos = pMem; p->rc = SQLITE_OK; p->resOnStack = 1; rc = SQLITE_ROW; } return rc;}#endif /* SQLITE_OMIT_EXPLAIN *//*** Print the SQL that was used to generate a VDBE program.*/void sqlite3VdbePrintSql(Vdbe *p){#ifdef SQLITE_DEBUG int nOp = p->nOp; VdbeOp *pOp; if( nOp<1 ) return; pOp = &p->aOp[nOp-1]; if( pOp->opcode==OP_Noop && pOp->p3!=0 ){ const char *z = pOp->p3; while( isspace(*(u8*)z) ) z++; printf("SQL: [%s]\n", z); }#endif}/*** Prepare a virtual machine for execution. This involves things such** as allocating stack space and initializing the program counter.** After the VDBE has be prepped, it can be executed by one or more** calls to sqlite3VdbeExec(). **** This is the only way to move a VDBE from VDBE_MAGIC_INIT to** VDBE_MAGIC_RUN.*/void sqlite3VdbeMakeReady( Vdbe *p, /* The VDBE */ int nVar, /* Number of '?' see in the SQL statement */ int nMem, /* Number of memory cells to allocate */ int nCursor, /* Number of cursors to allocate */ int nAgg, /* Number of aggregate contexts required */ int isExplain /* True if the EXPLAIN keywords is present */){ int n; assert( p!=0 ); assert( p->magic==VDBE_MAGIC_INIT ); /* There should be at least one opcode. */ assert( p->nOp>0 ); /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. This * is because the call to resizeOpArray() below may shrink the * p->aOp[] array to save memory if called when in VDBE_MAGIC_RUN * state. */ p->magic = VDBE_MAGIC_RUN; /* No instruction ever pushes more than a single element onto the ** stack. And the stack never grows on successive executions of the ** same loop. So the total number of instructions is an upper bound ** on the maximum stack depth required. (Added later:) The ** resolveP2Values() call computes a tighter upper bound on the ** stack size. ** ** Allocation all the stack space we will ever need. */ if( p->aStack==0 ){ int nArg; /* Maximum number of args passed to a user function. */ int nStack; /* Maximum number of stack entries required */ resolveP2Values(p, &nArg, &nStack); resizeOpArray(p, p->nOp); assert( nVar>=0 ); assert( nStack<p->nOp ); nStack = isExplain ? 10 : nStack; p->aStack = sqliteMalloc( nStack*sizeof(p->aStack[0]) /* aStack */ + nArg*sizeof(Mem*) /* apArg */ + nVar*sizeof(Mem) /* aVar */ + nVar*sizeof(char*) /* azVar */ + nMem*sizeof(Mem) /* aMem */ + nCursor*sizeof(Cursor*) /* apCsr */ + nAgg*sizeof(Agg) /* Aggregate contexts */ ); if( !sqlite3_malloc_failed ){ p->aMem = &p->aStack[nStack]; p->nMem = nMem; p->aVar = &p->aMem[nMem]; p->nVar = nVar; p->okVar = 0; p->apArg = (Mem**)&p->aVar[nVar]; p->azVar = (char**)&p->apArg[nArg]; p->apCsr = (Cursor**)&p->azVar[nVar]; if( nAgg>0 ){ p->nAgg = nAgg; p->apAgg = (Agg*)&p->apCsr[nCursor]; } p->nCursor = nCursor; for(n=0; n<nVar; n++){ p->aVar[n].flags = MEM_Null; } } } p->pAgg = p->apAgg; for(n=0; n<p->nMem; n++){ p->aMem[n].flags = MEM_Null; }#ifdef SQLITE_DEBUG if( (p->db->flags & SQLITE_VdbeListing)!=0 || sqlite3OsFileExists("vdbe_explain") ){ int i; printf("VDBE Program Listing:\n"); sqlite3VdbePrintSql(p); for(i=0; i<p->nOp; i++){ sqlite3VdbePrintOp(stdout, i, &p->aOp[i]); } } if( sqlite3OsFileExists("vdbe_trace") ){ p->trace = stdout; }#endif p->pTos = &p->aStack[-1]; p->pc = -1; p->rc = SQLITE_OK; p->uniqueCnt = 0; p->returnDepth = 0; p->errorAction = OE_Abort; p->popStack = 0; p->explain |= isExplain; p->magic = VDBE_MAGIC_RUN; p->nChange = 0;#ifdef VDBE_PROFILE { int i; for(i=0; i<p->nOp; i++){ p->aOp[i].cnt = 0; p->aOp[i].cycles = 0; } }#endif}/*** Remove any elements that remain on the sorter for the VDBE given.*/void sqlite3VdbeSorterReset(Vdbe *p){ while( p->pSort ){ Sorter *pSorter = p->pSort; p->pSort = pSorter->pNext; sqliteFree(pSorter->zKey); sqlite3VdbeMemRelease(&pSorter->data); sqliteFree(pSorter); } p->pSortTail = 0;}/*** Free all resources allociated with AggElem pElem, an element of** aggregate pAgg.*/static void freeAggElem(AggElem *pElem, Agg *pAgg){ int i; for(i=0; i<pAgg->nMem; i++){ Mem *pMem = &pElem->aMem[i]; if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){ sqlite3_context ctx; ctx.pFunc = pAgg->apFunc[i]; ctx.s.flags = MEM_Null; ctx.pAgg = pMem->z; ctx.cnt = pMem->i; ctx.isError = 0; (*ctx.pFunc->xFinalize)(&ctx); pMem->z = ctx.pAgg; if( pMem->z!=0 && pMem->z!=pMem->zShort ){ sqliteFree(pMem->z); } sqlite3VdbeMemRelease(&ctx.s); }else{ sqlite3VdbeMemRelease(pMem); } } sqliteFree(pElem);}/*** Reset an Agg structure. Delete all its contents.**** For installable aggregate functions, if the step function has been** called, make sure the finalizer function has also been called. The** finalizer might need to free memory that was allocated as part of its** private context. If the finalizer has not been called yet, call it** now.**** If db is NULL, then this is being called from sqliteVdbeReset(). In** this case clean up all references to the temp-table used for** aggregates (if it was ever opened).**** If db is not NULL, then this is being called from with an OP_AggReset** opcode. Open the temp-table, if it has not already been opened and** delete the contents of the table used for aggregate information, ready** for the next round of aggregate processing.*/int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){ int rc = 0; BtCursor *pCsr; if( !pAgg ) return SQLITE_OK; pCsr = pAgg->pCsr; assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0) || sqlite3_malloc_failed ); /* If pCsr is not NULL, then the table used for aggregate information ** is open. Loop through it and free the AggElem* structure pointed at ** by each entry. If the finalizer has not been called for an AggElem, ** do that too. Finally, clear the btree table itself. */ if( pCsr ){ int res; assert( pAgg->pBtree ); assert( pAgg->nTab>0 ); rc=sqlite3BtreeFirst(pCsr, &res); while( res==0 && rc==SQLITE_OK ){ AggElem *pElem; rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem); if( rc!=SQLITE_OK ){ return rc; } assert( pAgg->apFunc!=0 ); freeAggElem(pElem, pAgg); rc=sqlite3BtreeNext(pCsr, &res); } if( rc!=SQLITE_OK ){ return rc; } sqlite3BtreeCloseCursor(pCsr); sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab); }else{ /* The cursor may not be open because the aggregator was never used, ** or it could be that it was used but there was no GROUP BY clause. */ if( pAgg->pCurrent ){ freeAggElem(pAgg->pCurrent, pAgg); } } /* If db is not NULL and we have not yet and we have not yet opened ** the temporary btree then do so and create the table to store aggregate ** information. ** ** If db is NULL, then close the temporary btree if it is open. */ if( db ){ if( !pAgg->pBtree ){ assert( pAgg->nTab==0 );#ifndef SQLITE_OMIT_MEMORYDB rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree);#else rc = sqlite3BtreeFactory(db, 0, 0, TEMP_PAGES, &pAgg->pBtree);#endif if( rc!=SQLITE_OK ) return rc; sqlite3BtreeBeginTrans(pAgg->pBtree, 1); rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0); if( rc!=SQLITE_OK ) return rc; } assert( pAgg->nTab!=0 ); rc = sqlite3BtreeCursor(pAgg->pBtree, pAgg->nTab, 1, sqlite3VdbeRecordCompare, pKeyInfo, &pAgg->pCsr); if( rc!=SQLITE_OK ) return rc; }else{ if( pAgg->pBtree ){ sqlite3BtreeClose(pAgg->pBtree); pAgg->pBtree = 0; pAgg->nTab = 0; } pAgg->pCsr = 0; } if( pAgg->apFunc ){ sqliteFree(pAgg->apFunc); pAgg->apFunc = 0; } pAgg->pCurrent = 0; pAgg->nMem = 0; pAgg->searching = 0; return SQLITE_OK;}/*** Delete a keylist*/void sqlite3VdbeKeylistFree(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.*/void sqlite3VdbeFreeCursor(Cursor *pCx){ if( pCx==0 ){ return; } if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); } sqliteFree(pCx->pData); sqliteFree(pCx->aType); sqliteFree(pCx);}/*** Close all cursors*/static void closeAllCursors(Vdbe *p){ int i; if( p->apCsr==0 ) return; for(i=0; i<p->nCursor; i++){ sqlite3VdbeFreeCursor(p->apCsr[i]); p->apCsr[i] = 0; }}/*** Clean up the VM after execution.**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -