📄 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.*/#ifdef SQLITE_DEBUGint 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;}/*** Remember the SQL string for a prepared statement.*/void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){ if( p==0 ) return; assert( p->zSql==0 ); p->zSql = sqlite3StrNDup(z, n);}/*** Return the SQL associated with a prepared statement*/const char *sqlite3VdbeGetSql(Vdbe *p){ return p->zSql;}/*** Swap all content between two VDBE structures.*/void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ Vdbe tmp, *pTmp; char *zTmp; int nTmp; tmp = *pA; *pA = *pB; *pB = tmp; pTmp = pA->pNext; pA->pNext = pB->pNext; pB->pNext = pTmp; pTmp = pA->pPrev; pA->pPrev = pB->pPrev; pB->pPrev = pTmp; zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; nTmp = pA->nSql; pA->nSql = pB->nSql; pB->nSql = nTmp;}#ifdef SQLITE_DEBUG/*** Turn tracing on or off*/void sqlite3VdbeTrace(Vdbe *p, FILE *trace){ p->trace = trace;}#endif/*** Resize the Vdbe.aOp array so that it contains at least N** elements. If the Vdbe is in VDBE_MAGIC_RUN state, then** the Vdbe.aOp array will be sized to contain exactly N** elements. Vdbe.nOpAlloc is set to reflect the new size of** the array.**** If an out-of-memory error occurs while resizing the array,** Vdbe.aOp and Vdbe.nOpAlloc remain unchanged (this is so that** any opcodes already allocated can be correctly deallocated** along with the rest of the Vdbe).*/static void resizeOpArray(Vdbe *p, int N){ int runMode = p->magic==VDBE_MAGIC_RUN; if( runMode || p->nOpAlloc<N ){ VdbeOp *pNew; int nNew = N + 100*(!runMode); int oldSize = p->nOpAlloc; pNew = sqliteRealloc(p->aOp, nNew*sizeof(Op)); if( pNew ){ p->nOpAlloc = nNew; p->aOp = pNew; if( nNew>oldSize ){ memset(&p->aOp[oldSize], 0, (nNew-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; assert( p->magic==VDBE_MAGIC_INIT ); if( p->nOpAlloc<=i ){ resizeOpArray(p, i+1); if( sqlite3MallocFailed() ){ return 0; } } p->nOp++; pOp = &p->aOp[i]; pOp->opcode = op; pOp->p1 = p1; pOp->p2 = p2; pOp->p3 = 0; pOp->p3type = P3_NOTUSED; p->expired = 0;#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 = sqliteReallocOrFree(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; }}/*** Return non-zero if opcode 'op' is guarenteed not to push more values** onto the VDBE stack than it pops off.*/static int opcodeNoPush(u8 op){ /* The 10 NOPUSH_MASK_n constants are defined in the automatically ** generated header file opcodes.h. Each is a 16-bit bitmask, one ** bit corresponding to each opcode implemented by the virtual ** machine in vdbe.c. The bit is true if the word "no-push" appears ** in a comment on the same line as the "case OP_XXX:" in ** sqlite3VdbeExec() in vdbe.c. ** ** If the bit is true, then the corresponding opcode is guarenteed not ** to grow the stack when it is executed. Otherwise, it may grow the ** stack by at most one entry. ** ** NOPUSH_MASK_0 corresponds to opcodes 0 to 15. NOPUSH_MASK_1 contains ** one bit for opcodes 16 to 31, and so on. ** ** 16-bit bitmasks (rather than 32-bit) are specified in opcodes.h ** because the file is generated by an awk program. Awk manipulates ** all numbers as floating-point and we don't want to risk a rounding ** error if someone builds with an awk that uses (for example) 32-bit ** IEEE floats. */ static const u32 masks[5] = { NOPUSH_MASK_0 + (((unsigned)NOPUSH_MASK_1)<<16), NOPUSH_MASK_2 + (((unsigned)NOPUSH_MASK_3)<<16), NOPUSH_MASK_4 + (((unsigned)NOPUSH_MASK_5)<<16), NOPUSH_MASK_6 + (((unsigned)NOPUSH_MASK_7)<<16), NOPUSH_MASK_8 + (((unsigned)NOPUSH_MASK_9)<<16) }; assert( op<32*5 ); return (masks[op>>5] & (1<<(op&0x1F)));}#ifndef NDEBUGint sqlite3VdbeOpcodeNoPush(u8 op){ return opcodeNoPush(op);}#endif/*** 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.**** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.**** The integer *pMaxStack is set to the maximum number of vdbe stack** entries that static analysis reveals this program might need.**** This routine also does the following optimization: It scans for** Halt instructions where P1==SQLITE_CONSTRAINT or P2==OE_Abort or for** IdxInsert instructions where P2!=0. If no such instruction is** found, then every Statement instruction is changed to a Noop. In** this way, we avoid creating the statement journal file unnecessarily.*/static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){ int i; int nMaxArgs = 0; int nMaxStack = p->nOp; Op *pOp; int *aLabel = p->aLabel; int doesStatementRollback = 0; int hasStatementBegin = 0; for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ u8 opcode = pOp->opcode; if( opcode==OP_Function || opcode==OP_AggStep #ifndef SQLITE_OMIT_VIRTUALTABLE || opcode==OP_VUpdate#endif ){ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; } if( opcode==OP_Halt ){ if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ doesStatementRollback = 1; } }else if( opcode==OP_Statement ){ hasStatementBegin = 1;#ifndef SQLITE_OMIT_VIRTUALTABLE }else if( opcode==OP_VUpdate || opcode==OP_VRename ){ doesStatementRollback = 1; }else if( opcode==OP_VFilter ){ int n; assert( p->nOp - i >= 3 ); assert( pOp[-2].opcode==OP_Integer ); n = pOp[-2].p1; if( n>nMaxArgs ) nMaxArgs = n;#endif } if( opcodeNoPush(opcode) ){ nMaxStack--; } if( pOp->p2>=0 ) continue; assert( -1-pOp->p2<p->nLabel ); pOp->p2 = aLabel[-1-pOp->p2]; } sqliteFree(p->aLabel); p->aLabel = 0; *pMaxFuncArgs = nMaxArgs; *pMaxStack = nMaxStack; /* If we never rollback a statement transaction, then statement ** transactions are not needed. So change every OP_Statement ** opcode into an OP_Noop. This avoid a call to sqlite3OsOpenExclusive() ** which can be expensive on some platforms. */ if( hasStatementBegin && !doesStatementRollback ){ for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ if( pOp->opcode==OP_Statement ){ pOp->opcode = OP_Noop; } } }}/*** 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( sqlite3MallocFailed() ){ 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==0 || 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==0 || p->magic==VDBE_MAGIC_INIT ); if( p && addr>=0 && p->nOp>addr && p->aOp ){ p->aOp[addr].p2 = val; }}/*** Change the P2 operand of instruction addr so that it points to** the address of the next instruction to be coded.*/void sqlite3VdbeJumpHere(Vdbe *p, int addr){ sqlite3VdbeChangeP2(p, addr, p->nOp);}/*** If the input FuncDef structure is ephemeral, then free it. If** the FuncDef is not ephermal, then do nothing.*/static void freeEphemeralFunction(FuncDef *pDef){ if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){ sqliteFree(pDef); }}/*** Delete a P3 value if necessary.*/static void freeP3(int p3type, void *p3){ if( p3 ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -