📄 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.**** $Id: vdbeaux.c,v 1.409 2008/08/20 22:06:48 drh Exp $*/#include "sqliteInt.h"#include <ctype.h>#include "vdbeInt.h"/*** When debugging the code generator in a symbolic debugger, one can** set the sqlite3VdbeAddopTrace to 1 and all opcodes will be printed** as they are added to the instruction stream.*/#ifdef SQLITE_DEBUGint sqlite3VdbeAddopTrace = 0;#endif/*** Create a new virtual database engine.*/Vdbe *sqlite3VdbeCreate(sqlite3 *db){ Vdbe *p; p = sqlite3DbMallocZero(db, 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 = sqlite3DbStrNDup(p->db, z, n);}/*** Return the SQL associated with a prepared statement*/const char *sqlite3_sql(sqlite3_stmt *pStmt){ return ((Vdbe *)pStmt)->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 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){ VdbeOp *pNew; pNew = sqlite3DbRealloc(p->db, p->aOp, N*sizeof(Op)); if( pNew ){ p->nOpAlloc = N; p->aOp = pNew; }}/*** 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, p3 Operands**** Use the sqlite3VdbeResolveLabel() function to fix an address and** the sqlite3VdbeChangeP4() function to change the value of the P4** operand.*/int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ int i; VdbeOp *pOp; i = p->nOp; assert( p->magic==VDBE_MAGIC_INIT ); if( p->nOpAlloc<=i ){ resizeOpArray(p, p->nOpAlloc ? p->nOpAlloc*2 : 1024/sizeof(Op)); if( p->db->mallocFailed ){ return 0; } } p->nOp++; pOp = &p->aOp[i]; pOp->opcode = op; pOp->p5 = 0; pOp->p1 = p1; pOp->p2 = p2; pOp->p3 = p3; pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; p->expired = 0;#ifdef SQLITE_DEBUG pOp->zComment = 0; if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);#endif#ifdef VDBE_PROFILE pOp->cycles = 0; pOp->cnt = 0;#endif return i;}int sqlite3VdbeAddOp0(Vdbe *p, int op){ return sqlite3VdbeAddOp3(p, op, 0, 0, 0);}int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){ return sqlite3VdbeAddOp3(p, op, p1, 0, 0);}int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){ return sqlite3VdbeAddOp3(p, op, p1, p2, 0);}/*** Add an opcode that includes the p4 value as a pointer.*/int sqlite3VdbeAddOp4( Vdbe *p, /* Add the opcode to this VM */ int op, /* The new opcode */ int p1, /* The P1 operand */ int p2, /* The P2 operand */ int p3, /* The P3 operand */ const char *zP4, /* The P4 operand */ int p4type /* P4 operand type */){ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); sqlite3VdbeChangeP4(p, addr, zP4, p4type); 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 = sqlite3DbReallocOrFree(p->db, 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** on jump instructions. 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.**** This routine also does the following optimization: It scans for** instructions that might cause a statement rollback. Such instructions** are:**** * OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort.** * OP_Destroy** * OP_VUpdate** * OP_VRename**** 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 i; int nMaxArgs = 0; 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 ){ if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;#ifndef SQLITE_OMIT_VIRTUALTABLE }else if( opcode==OP_VUpdate ){ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;#endif } if( opcode==OP_Halt ){ if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ doesStatementRollback = 1; } }else if( opcode==OP_Statement ){ hasStatementBegin = 1; }else if( opcode==OP_Destroy ){ doesStatementRollback = 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[-1].opcode==OP_Integer ); n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n;#endif } if( sqlite3VdbeOpcodeHasProperty(opcode, OPFLG_JUMP) && pOp->p2<0 ){ assert( -1-pOp->p2<p->nLabel ); pOp->p2 = aLabel[-1-pOp->p2]; } } sqlite3DbFree(p->db, p->aLabel); p->aLabel = 0; *pMaxFuncArgs = nMaxArgs; /* 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 ); if( p->nOp + nOp > p->nOpAlloc ){ resizeOpArray(p, p->nOpAlloc ? p->nOpAlloc*2 : 1024/sizeof(Op)); assert( p->nOp+nOp<=p->nOpAlloc || p->db->mallocFailed ); } if( p->db->mallocFailed ){ 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; if( p2<0 && sqlite3VdbeOpcodeHasProperty(pOut->opcode, OPFLG_JUMP) ){ pOut->p2 = addr + ADDR(p2); }else{ pOut->p2 = p2; } pOut->p3 = pIn->p3; pOut->p4type = P4_NOTUSED; pOut->p4.p = 0; pOut->p5 = 0;#ifdef SQLITE_DEBUG pOut->zComment = 0; if( sqlite3VdbeAddopTrace ){ 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( p==0 || 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.*/void sqlite3VdbeChangeP3(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].p3 = val; }}/*** Change the value of the P5 operand for the most recently** added operation.*/void sqlite3VdbeChangeP5(Vdbe *p, u8 val){ assert( p==0 || p->magic==VDBE_MAGIC_INIT ); if( p && p->aOp ){ assert( p->nOp>0 ); p->aOp[p->nOp-1].p5 = 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(sqlite3 *db, FuncDef *pDef){ if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){ sqlite3DbFree(db, pDef); }}/*** Delete a P4 value if necessary.*/static void freeP4(sqlite3 *db, int p4type, void *p4){ if( p4 ){ switch( p4type ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -