⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vdbeaux.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*** 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. If the Vdbe is in VDBE_MAGIC_RUN state, then** the Vdbe.aOp array will be sized to contain exactly N ** elements.*/static void resizeOpArray(Vdbe *p, int N){  if( p->magic==VDBE_MAGIC_RUN ){    assert( N==p->nOp );    p->nOpAlloc = N;    p->aOp = sqliteRealloc(p->aOp, N*sizeof(Op));  }else 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;  }}/*** 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 + (NOPUSH_MASK_1<<16),    NOPUSH_MASK_2 + (NOPUSH_MASK_3<<16),    NOPUSH_MASK_4 + (NOPUSH_MASK_5<<16),    NOPUSH_MASK_6 + (NOPUSH_MASK_7<<16),    NOPUSH_MASK_8 + (NOPUSH_MASK_9<<16)  };  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 P1 argument ** to an OP_Function or P2 to an OP_AggFunc 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;    /* Todo: Maybe OP_AggFunc should change to use P1 in the same     * way as OP_Function.      */    if( opcode==OP_Function ){      if( pOp->p1>nMaxArgs ) nMaxArgs = pOp->p1;    }else if( opcode==OP_AggFunc ){      if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;    }else if( opcode==OP_Halt ){      if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){        doesStatementRollback = 1;      }    }else if( opcode==OP_IdxInsert ){      if( pOp->p2 ){        doesStatementRollback = 1;      }    }else if( opcode==OP_Statement ){      hasStatementBegin = 1;    }    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( 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_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->magic==VDBE_MAGIC_INIT );  if( p==0 || p->aOp==0 ){    if( n==P3_DYNAMIC || n==P3_KEYINFO_HANDOFF ){      sqliteFree((void*)zP3);    }    if( n==P3_MEM ){      sqlite3ValueFree((sqlite3_value *)zP3);    }    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.*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -