📄 vdbeaux.c
字号:
/*** 2003 September 6**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.***************************************************************************** This file contains code used for creating, destroying, and populating** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior** to version 2.8.7, all this code was combined into the vdbe.c source file.** But that file was getting too big so this subroutines were split out.*/#include "sqliteInt.h"#include "os.h"#include <ctype.h>#include "vdbeInt.h"/*** When debugging the code generator in a symbolic debugger, one can** set the sqlite3_vdbe_addop_trace to 1 and all opcodes will be printed** as they are added to the instruction stream.*/#ifndef NDEBUGint sqlite3_vdbe_addop_trace = 0;#endif/*** Create a new virtual database engine.*/Vdbe *sqlite3VdbeCreate(sqlite3 *db){ Vdbe *p; p = sqliteMalloc( sizeof(Vdbe) ); if( p==0 ) return 0; p->db = db; if( db->pVdbe ){ db->pVdbe->pPrev = p; } p->pNext = db->pVdbe; p->pPrev = 0; db->pVdbe = p; p->magic = VDBE_MAGIC_INIT; return p;}/*** Turn tracing on or off*/void sqlite3VdbeTrace(Vdbe *p, FILE *trace){ p->trace = trace;}/*** Resize the Vdbe.aOp array so that it contains at least N** elements.*/static void resizeOpArray(Vdbe *p, int N){ if( p->nOpAlloc<N ){ int oldSize = p->nOpAlloc; p->nOpAlloc = N+100; p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); if( p->aOp ){ memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); } }}/*** Add a new instruction to the list of instructions current in the** VDBE. Return the address of the new instruction.**** Parameters:**** p Pointer to the VDBE**** op The opcode for this instruction**** p1, p2 First two of the three possible operands.**** Use the sqlite3VdbeResolveLabel() function to fix an address and** the sqlite3VdbeChangeP3() function to change the value of the P3** operand.*/int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ int i; VdbeOp *pOp; i = p->nOp; p->nOp++; assert( p->magic==VDBE_MAGIC_INIT ); resizeOpArray(p, i+1); if( p->aOp==0 ){ return 0; } pOp = &p->aOp[i]; pOp->opcode = op; pOp->p1 = p1; pOp->p2 = p2; pOp->p3 = 0; pOp->p3type = P3_NOTUSED;#ifdef SQLITE_DEBUG if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);#endif return i;}/*** Add an opcode that includes the p3 value.*/int sqlite3VdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3,int p3type){ int addr = sqlite3VdbeAddOp(p, op, p1, p2); sqlite3VdbeChangeP3(p, addr, zP3, p3type); return addr;}/*** Create a new symbolic label for an instruction that has yet to be** coded. The symbolic label is really just a negative number. The** label can be used as the P2 value of an operation. Later, when** the label is resolved to a specific address, the VDBE will scan** through its operation list and change all values of P2 which match** the label into the resolved address.**** The VDBE knows that a P2 value is a label because labels are** always negative and P2 values are suppose to be non-negative.** Hence, a negative P2 value is a label that has yet to be resolved.**** Zero is returned if a malloc() fails.*/int sqlite3VdbeMakeLabel(Vdbe *p){ int i; i = p->nLabel++; assert( p->magic==VDBE_MAGIC_INIT ); if( i>=p->nLabelAlloc ){ p->nLabelAlloc = p->nLabelAlloc*2 + 10; p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); } if( p->aLabel ){ p->aLabel[i] = -1; } return -1-i;}/*** Resolve label "x" to be the address of the next instruction to** be inserted. The parameter "x" must have been obtained from** a prior call to sqlite3VdbeMakeLabel().*/void sqlite3VdbeResolveLabel(Vdbe *p, int x){ int j = -1-x; assert( p->magic==VDBE_MAGIC_INIT ); assert( j>=0 && j<p->nLabel ); if( p->aLabel ){ p->aLabel[j] = p->nOp; }}/*** Loop through the program looking for P2 values that are negative.** Each such value is a label. Resolve the label by setting the P2** value to its correct non-zero value.**** This routine is called once after all opcodes have been inserted.*/static void resolveP2Values(Vdbe *p){ int i; Op *pOp; int *aLabel = p->aLabel; if( aLabel==0 ) return; for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ if( pOp->p2>=0 ) continue; assert( -1-pOp->p2<p->nLabel ); pOp->p2 = aLabel[-1-pOp->p2]; } sqliteFree(p->aLabel); p->aLabel = 0;}/*** Return the address of the next instruction to be inserted.*/int sqlite3VdbeCurrentAddr(Vdbe *p){ assert( p->magic==VDBE_MAGIC_INIT ); return p->nOp;}/*** Add a whole list of operations to the operation stack. Return the** address of the first operation added.*/int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ int addr; assert( p->magic==VDBE_MAGIC_INIT ); resizeOpArray(p, p->nOp + nOp); if( p->aOp==0 ){ return 0; } addr = p->nOp; if( nOp>0 ){ int i; VdbeOpList const *pIn = aOp; for(i=0; i<nOp; i++, pIn++){ int p2 = pIn->p2; VdbeOp *pOut = &p->aOp[i+addr]; pOut->opcode = pIn->opcode; pOut->p1 = pIn->p1; pOut->p2 = p2<0 ? addr + ADDR(p2) : p2; pOut->p3 = pIn->p3; pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;#ifdef SQLITE_DEBUG if( sqlite3_vdbe_addop_trace ){ sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); }#endif } p->nOp += nOp; } return addr;}/*** Change the value of the P1 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.*/void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ assert( p->magic==VDBE_MAGIC_INIT ); if( p && addr>=0 && p->nOp>addr && p->aOp ){ p->aOp[addr].p1 = val; }}/*** Change the value of the P2 operand for a specific instruction.** This routine is useful for setting a jump destination.*/void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ assert( val>=0 ); assert( p->magic==VDBE_MAGIC_INIT ); if( p && addr>=0 && p->nOp>addr && p->aOp ){ p->aOp[addr].p2 = val; }}/*** 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_STATIC it means that zP3 is a pointer to a constant static** string and we can just copy the pointer. n==P3_POINTER means zP3 is** a pointer to some object other than a string. n==P3_COLLSEQ and** n==P3_KEYINFO mean that zP3 is a pointer to a CollSeq or KeyInfo** structure. A copy is made of KeyInfo structures into memory obtained** from sqliteMalloc.**** 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->magic==VDBE_MAGIC_INIT ); if( p==0 || p->aOp==0 ) return; if( addr<0 || addr>=p->nOp ){ addr = p->nOp - 1; if( addr<0 ) return; } pOp = &p->aOp[addr]; if( pOp->p3 && pOp->p3type==P3_DYNAMIC ){ sqliteFree(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]); pKeyInfo = sqliteMallocRaw( nByte ); pOp->p3 = (char*)pKeyInfo; if( pKeyInfo ){ memcpy(pKeyInfo, zP3, nByte); 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 ); va_start(ap, zFormat); sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC); va_end(ap);}#endif/*** If the P3 operand to the specified instruction appears** to be a quoted string token, then this procedure removes ** the quotes.**** The quoting operator can be either a grave ascent (ASCII 0x27)** or a double quote character (ASCII 0x22). Two quotes in a row** resolve to be a single actual quote character within the string.*/void sqlite3VdbeDequoteP3(Vdbe *p, int addr){ Op *pOp; assert( p->magic==VDBE_MAGIC_INIT ); if( p->aOp==0 ) return; if( addr<0 || addr>=p->nOp ){ addr = p->nOp - 1; if( addr<0 ) return; } pOp = &p->aOp[addr]; if( pOp->p3==0 || pOp->p3[0]==0 ) return; if( pOp->p3type==P3_STATIC ){ pOp->p3 = sqliteStrDup(pOp->p3); pOp->p3type = P3_DYNAMIC; } assert( pOp->p3type==P3_DYNAMIC ); sqlite3Dequote(pOp->p3);}/*** Search the current program starting at instruction addr for the given** opcode and P2 value. Return the address plus 1 if found and 0 if not** found.*/int sqlite3VdbeFindOp(Vdbe *p, int addr, int op, int p2){ int i; assert( p->magic==VDBE_MAGIC_INIT ); for(i=addr; i<p->nOp; i++){ if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1; } return 0;}/*** 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_POINTER: { sprintf(zTemp, "ptr(%#x)", (int)pOp->p3); zP3 = zTemp; break; } 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -