?? vdbeaux.c
字號:
break;
}
case P3_MEM: {
sqlite3ValueFree((sqlite3_value*)p3);
break;
}
}
}
}
/*
** Change N opcodes starting at addr to No-ops.
*/
void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
VdbeOp *pOp = &p->aOp[addr];
while( N-- ){
freeP3(pOp->p3type, pOp->p3);
memset(pOp, 0, sizeof(pOp[0]));
pOp->opcode = OP_Noop;
pOp++;
}
}
/*
** Change the value of the P3 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
** static array using sqlite3VdbeAddOpList but we want to make a
** few minor changes to the program.
**
** If n>=0 then the P3 operand is dynamic, meaning that a copy of
** the string is made into memory obtained from sqliteMalloc().
** A value of n==0 means copy bytes of zP3 up to and including the
** first null byte. If n>0 then copy n+1 bytes of zP3.
**
** If n==P3_KEYINFO it means that zP3 is a pointer to a KeyInfo structure.
** A copy is made of the KeyInfo structure into memory obtained from
** sqliteMalloc, to be freed when the Vdbe is finalized.
** n==P3_KEYINFO_HANDOFF indicates that zP3 points to a KeyInfo structure
** stored in memory that the caller has obtained from sqliteMalloc. The
** caller should not free the allocation, it will be freed when the Vdbe is
** finalized.
**
** Other values of n (P3_STATIC, P3_COLLSEQ etc.) indicate that zP3 points
** to a string or structure that is guaranteed to exist for the lifetime of
** the Vdbe. In these cases we can just copy the pointer.
**
** If addr<0 then change P3 on the most recently inserted instruction.
*/
void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
Op *pOp;
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){
if (n != P3_KEYINFO) {
freeP3(n, (void*)*(char**)&zP3);
}
return;
}
if( addr<0 || addr>=p->nOp ){
addr = p->nOp - 1;
if( addr<0 ) return;
}
pOp = &p->aOp[addr];
freeP3(pOp->p3type, pOp->p3);
pOp->p3 = 0;
if( zP3==0 ){
pOp->p3 = 0;
pOp->p3type = P3_NOTUSED;
}else if( n==P3_KEYINFO ){
KeyInfo *pKeyInfo;
int nField, nByte;
nField = ((KeyInfo*)zP3)->nField;
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
pKeyInfo = sqliteMallocRaw( nByte );
pOp->p3 = (char*)pKeyInfo;
if( pKeyInfo ){
unsigned char *aSortOrder;
memcpy(pKeyInfo, zP3, nByte);
aSortOrder = pKeyInfo->aSortOrder;
if( aSortOrder ){
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
}
pOp->p3type = P3_KEYINFO;
}else{
pOp->p3type = P3_NOTUSED;
}
}else if( n==P3_KEYINFO_HANDOFF ){
pOp->p3 = (char*)zP3;
pOp->p3type = P3_KEYINFO;
}else if( n<0 ){
pOp->p3 = (char*)zP3;
pOp->p3type = n;
}else{
if( n==0 ) n = strlen(zP3);
pOp->p3 = sqliteStrNDup(zP3, n);
pOp->p3type = P3_DYNAMIC;
}
}
#ifndef NDEBUG
/*
** Replace the P3 field of the most recently coded instruction with
** comment text.
*/
void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
va_list ap;
assert( p->nOp>0 );
assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0
|| sqlite3MallocFailed() );
va_start(ap, zFormat);
sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
va_end(ap);
}
#endif
/*
** Return the opcode for a given address.
*/
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
assert( p->magic==VDBE_MAGIC_INIT );
assert( addr>=0 && addr<p->nOp );
return &p->aOp[addr];
}
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|| defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Compute a string that describes the P3 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
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;
sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
zP3 = zTemp;
break;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
case P3_VTAB: {
sqlite3_vtab *pVtab = (sqlite3_vtab*)pOp->p3;
sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
zP3 = zTemp;
break;
}
#endif
default: {
zP3 = pOp->p3;
if( zP3==0 || pOp->opcode==OP_Noop ){
zP3 = "";
}
}
}
assert( zP3!=0 );
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;
do{
i = p->pc++;
}while( i<p->nOp && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
if( i>=p->nOp ){
p->rc = SQLITE_OK;
rc = SQLITE_DONE;
}else if( db->u1.isInterrupted ){
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 */
assert( pMem->z!=0 );
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_Ephem|MEM_Str|MEM_Term; /* P3 */
pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort));
assert( pMem->z!=0 );
pMem->n = strlen(pMem->z);
pMem->type = SQLITE_TEXT;
pMem->enc = SQLITE_UTF8;
p->nResColumn = 5 - 2*(p->explain-1);
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 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 );
if( isExplain ){
nStack = 10;
}
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 */
);
if( !sqlite3MallocFailed() ){
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];
p->nCursor = nCursor;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
}
}
}
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++){
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -