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

📄 vdbeaux.c

📁 sqlite数据库源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*** 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 "sqlite_vm" 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 sqlite_vdbe_addop_trace to 1 and all opcodes will be printed** as they are added to the instruction stream.*/#ifndef NDEBUGint sqlite_vdbe_addop_trace = 0;#endif/*** Create a new virtual database engine.*/Vdbe *sqliteVdbeCreate(sqlite *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 sqliteVdbeTrace(Vdbe *p, FILE *trace){  p->trace = trace;}/*** 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 sqliteVdbeResolveLabel() function to fix an address and** the sqliteVdbeChangeP3() function to change the value of the P3** operand.*/int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){  int i;  VdbeOp *pOp;  i = p->nOp;  p->nOp++;  assert( p->magic==VDBE_MAGIC_INIT );  if( i>=p->nOpAlloc ){    int oldSize = p->nOpAlloc;    Op *aNew;    p->nOpAlloc = p->nOpAlloc*2 + 100;    aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));    if( aNew==0 ){      p->nOpAlloc = oldSize;      return 0;    }    p->aOp = aNew;    memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));  }  pOp = &p->aOp[i];  pOp->opcode = op;  pOp->p1 = p1;  if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){    p2 = p->aLabel[-1-p2];  }  pOp->p2 = p2;  pOp->p3 = 0;  pOp->p3type = P3_NOTUSED;#ifndef NDEBUG  if( sqlite_vdbe_addop_trace ) sqliteVdbePrintOp(0, i, &p->aOp[i]);#endif  return i;}/*** Add an opcode that includes the p3 value.*/int sqliteVdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3, int p3type){  int addr = sqliteVdbeAddOp(p, op, p1, p2);  sqliteVdbeChangeP3(p, addr, zP3, p3type);  return addr;}/*** Add multiple opcodes.  The list is terminated by an opcode of 0.*/int sqliteVdbeCode(Vdbe *p, ...){  int addr;  va_list ap;  int opcode, p1, p2;  va_start(ap, p);  addr = p->nOp;  while( (opcode = va_arg(ap,int))!=0 ){    p1 = va_arg(ap,int);    p2 = va_arg(ap,int);    sqliteVdbeAddOp(p, opcode, p1, p2);  }  va_end(ap);  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.*/int sqliteVdbeMakeLabel(Vdbe *p){  int i;  i = p->nLabel++;  assert( p->magic==VDBE_MAGIC_INIT );  if( i>=p->nLabelAlloc ){    int *aNew;    p->nLabelAlloc = p->nLabelAlloc*2 + 10;    aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));    if( aNew==0 ){      sqliteFree(p->aLabel);    }    p->aLabel = aNew;  }  if( p->aLabel==0 ){    p->nLabel = 0;    p->nLabelAlloc = 0;    return 0;  }  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 sqliteVdbeMakeLabel().*/void sqliteVdbeResolveLabel(Vdbe *p, int x){  int j;  assert( p->magic==VDBE_MAGIC_INIT );  if( x<0 && (-x)<=p->nLabel && p->aOp ){    if( p->aLabel[-1-x]==p->nOp ) return;    assert( p->aLabel[-1-x]<0 );    p->aLabel[-1-x] = p->nOp;    for(j=0; j<p->nOp; j++){      if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp;    }  }}/*** Return the address of the next instruction to be inserted.*/int sqliteVdbeCurrentAddr(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 sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){  int addr;  assert( p->magic==VDBE_MAGIC_INIT );  if( p->nOp + nOp >= p->nOpAlloc ){    int oldSize = p->nOpAlloc;    Op *aNew;    p->nOpAlloc = p->nOpAlloc*2 + nOp + 10;    aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));    if( aNew==0 ){      p->nOpAlloc = oldSize;      return 0;    }    p->aOp = aNew;    memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));  }  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;#ifndef NDEBUG      if( sqlite_vdbe_addop_trace ){        sqliteVdbePrintOp(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 sqliteVdbeAddOpList but we want to make a** few minor changes to the program.*/void sqliteVdbeChangeP1(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 sqliteVdbeChangeP2(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 sqliteVdbeAddOpList 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.**** If addr<0 then change P3 on the most recently inserted instruction.*/void sqliteVdbeChangeP3(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<0 ){    pOp->p3 = (char*)zP3;    pOp->p3type = n;  }else{    sqliteSetNString(&pOp->p3, zP3, n, 0);    pOp->p3type = P3_DYNAMIC;  }}/*** 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 sqliteVdbeDequoteP3(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_POINTER ) return;  if( pOp->p3type!=P3_DYNAMIC ){    pOp->p3 = sqliteStrDup(pOp->p3);    pOp->p3type = P3_DYNAMIC;  }  sqliteDequote(pOp->p3);}/*** On the P3 argument of the given instruction, change all** strings of whitespace characters into a single space and** delete leading and trailing whitespace.*/void sqliteVdbeCompressSpace(Vdbe *p, int addr){  unsigned char *z;  int i, j;  Op *pOp;  assert( p->magic==VDBE_MAGIC_INIT );  if( p->aOp==0 || addr<0 || addr>=p->nOp ) return;  pOp = &p->aOp[addr];  if( pOp->p3type==P3_POINTER ){    return;  }  if( pOp->p3type!=P3_DYNAMIC ){    pOp->p3 = sqliteStrDup(pOp->p3);    pOp->p3type = P3_DYNAMIC;  }  z = (unsigned char*)pOp->p3;  if( z==0 ) return;  i = j = 0;  while( isspace(z[i]) ){ i++; }  while( z[i] ){    if( isspace(z[i]) ){      z[j++] = ' ';      while( isspace(z[++i]) ){}    }else{      z[j++] = z[i++];    }  }  while( j>0 && isspace(z[j-1]) ){ j--; }  z[j] = 0;}/*** Search for the current program for the given opcode and P2** value.  Return the address plus 1 if found and 0 if not found.*/int sqliteVdbeFindOp(Vdbe *p, int op, int p2){  int i;  assert( p->magic==VDBE_MAGIC_INIT );  for(i=0; 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 *sqliteVdbeGetOp(Vdbe *p, int addr){  assert( p->magic==VDBE_MAGIC_INIT );  assert( addr>=0 && addr<p->nOp );  return &p->aOp[addr];}/*** The following group or routines are employed by installable functions** to return their results.**** The sqlite_set_result_string() routine can be used to return a string** value or to return a NULL.  To return a NULL, pass in NULL for zResult.** A copy is made of the string before this routine returns so it is safe** to pass in an ephemeral string.**** sqlite_set_result_error() works like sqlite_set_result_string() except** that it signals a fatal error.  The string argument, if any, is the** error message.  If the argument is NULL a generic substitute error message** is used.**** The sqlite_set_result_int() and sqlite_set_result_double() set the return** value of the user function to an integer or a double.**** These routines are defined here in vdbe.c because they depend on knowing** the internals of the sqlite_func structure which is only defined in ** this source file.*/char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){  assert( !p->isStep );  if( p->s.flags & MEM_Dyn ){    sqliteFree(p->s.z);  }  if( zResult==0 ){    p->s.flags = MEM_Null;    n = 0;    p->s.z = 0;    p->s.n = 0;  }else{    if( n<0 ) n = strlen(zResult);    if( n<NBFS-1 ){      memcpy(p->s.zShort, zResult, n);      p->s.zShort[n] = 0;      p->s.flags = MEM_Str | MEM_Short;      p->s.z = p->s.zShort;    }else{      p->s.z = sqliteMallocRaw( n+1 );      if( p->s.z ){        memcpy(p->s.z, zResult, n);        p->s.z[n] = 0;      }      p->s.flags = MEM_Str | MEM_Dyn;    }    p->s.n = n+1;  }  return p->s.z;}void sqlite_set_result_int(sqlite_func *p, int iResult){  assert( !p->isStep );  if( p->s.flags & MEM_Dyn ){    sqliteFree(p->s.z);  }  p->s.i = iResult;  p->s.flags = MEM_Int;}void sqlite_set_result_double(sqlite_func *p, double rResult){  assert( !p->isStep );  if( p->s.flags & MEM_Dyn ){    sqliteFree(p->s.z);  }  p->s.r = rResult;  p->s.flags = MEM_Real;}void sqlite_set_result_error(sqlite_func *p, const char *zMsg, int n){  assert( !p->isStep );  sqlite_set_result_string(p, zMsg, n);  p->isError = 1;}/*** Extract the user data from a sqlite_func structure and return a** pointer to it.*/void *sqlite_user_data(sqlite_func *p){  assert( p && p->pFunc );  return p->pFunc->pUserData;}/*** Allocate or return the aggregate context for a user function.  A new** context is allocated on the first call.  Subsequent calls return the** same context that was returned on prior calls.**** This routine is defined here in vdbe.c because it depends on knowing** the internals of the sqlite_func structure which is only defined in** this source file.*/void *sqlite_aggregate_context(sqlite_func *p, int nByte){  assert( p && p->pFunc && p->pFunc->xStep );  if( p->pAgg==0 ){    if( nByte<=NBFS ){      p->pAgg = (void*)p->s.z;      memset(p->pAgg, 0, nByte);    }else{      p->pAgg = sqliteMalloc( nByte );    }  }  return p->pAgg;}/*** Return the number of times the Step function of a aggregate has been ** called.**** This routine is defined here in vdbe.c because it depends on knowing** the internals of the sqlite_func structure which is only defined in** this source file.*/int sqlite_aggregate_count(sqlite_func *p){  assert( p && p->pFunc && p->pFunc->xStep );  return p->cnt;}#if !defined(NDEBUG) || defined(VDBE_PROFILE)/*** Print a single opcode.  This routine is used for debugging only.*/void sqliteVdbePrintOp(FILE *pOut, int pc, Op *pOp){  char *zP3;  char zPtr[40];  if( pOp->p3type==P3_POINTER ){    sprintf(zPtr, "ptr(%#lx)", (long)pOp->p3);    zP3 = zPtr;  }else{    zP3 = pOp->p3;  }  if( pOut==0 ) pOut = stdout;  fprintf(pOut,"%4d %-12s %4d %4d %s\n",      pc, sqliteOpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : "");  fflush(pOut);}#endif/*** Give a listing of the program in the virtual machine.**** The interface is the same as sqliteVdbeExec().  But instead of** running the code, it invokes the callback once for each instruction.** This feature is used to implement "EXPLAIN".

⌨️ 快捷键说明

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