?? vdbe.c
字號(hào):
__inline__ unsigned long long int hwtime(void){ unsigned long long int x; __asm__("rdtsc\n\t" "mov %%edx, %%ecx\n\t" :"=A" (x)); return x;}#endif/*** The CHECK_FOR_INTERRUPT macro defined here looks to see if the** sqlite_interrupt() routine has been called. If it has been, then** processing of the VDBE program is interrupted.**** This macro added to every instruction that does a jump in order to** implement a loop. This test used to be on every single instruction,** but that meant we more testing that we needed. By only testing the** flag on jump instructions, we get a (small) speed improvement.*/#define CHECK_FOR_INTERRUPT \ if( db->flags & SQLITE_Interrupt ) goto abort_due_to_interrupt;/*** Execute as much of a VDBE program as we can then return.**** sqliteVdbeMakeReady() must be called before this routine in order to** close the program with a final OP_Halt and to set up the callbacks** and the error message pointer.**** Whenever a row or result data is available, this routine will either** invoke the result callback (if there is one) or return with** SQLITE_ROW.**** If an attempt is made to open a locked database, then this routine** will either invoke the busy callback (if there is one) or it will** return SQLITE_BUSY.**** If an error occurs, an error message is written to memory obtained** from sqliteMalloc() and p->zErrMsg is made to point to that memory.** The error code is stored in p->rc and this routine returns SQLITE_ERROR.**** If the callback ever returns non-zero, then the program exits** immediately. There will be no error message but the p->rc field is** set to SQLITE_ABORT and this routine will return SQLITE_ERROR.**** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this** routine to return SQLITE_ERROR.**** Other fatal errors return SQLITE_ERROR.**** After this routine has finished, sqliteVdbeFinalize() should be** used to clean up the mess that was left behind.*/int sqliteVdbeExec( Vdbe *p /* The VDBE */){ int pc; /* The program counter */ Op *pOp; /* Current operation */ int rc = SQLITE_OK; /* Value to return */ sqlite *db = p->db; /* The database */ Mem *pTos; /* Top entry in the operand stack */ char zBuf[100]; /* Space to sprintf() an integer */#ifdef VDBE_PROFILE unsigned long long start; /* CPU clock count at start of opcode */ int origPc; /* Program counter at start of opcode */#endif#ifndef SQLITE_OMIT_PROGRESS_CALLBACK int nProgressOps = 0; /* Opcodes executed since progress callback. */#endif if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE; assert( db->magic==SQLITE_MAGIC_BUSY ); assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY ); p->rc = SQLITE_OK; assert( p->explain==0 ); if( sqlite_malloc_failed ) goto no_mem; pTos = p->pTos; if( p->popStack ){ popStack(&pTos, p->popStack); p->popStack = 0; } CHECK_FOR_INTERRUPT; for(pc=p->pc; rc==SQLITE_OK; pc++){ assert( pc>=0 && pc<p->nOp ); assert( pTos<=&p->aStack[pc] );#ifdef VDBE_PROFILE origPc = pc; start = hwtime();#endif pOp = &p->aOp[pc]; /* Only allow tracing if NDEBUG is not defined. */#ifndef NDEBUG if( p->trace ){ sqliteVdbePrintOp(p->trace, pc, pOp); }#endif /* Check to see if we need to simulate an interrupt. This only happens ** if we have a special test build. */#ifdef SQLITE_TEST if( sqlite_interrupt_count>0 ){ sqlite_interrupt_count--; if( sqlite_interrupt_count==0 ){ sqlite_interrupt(db); } }#endif#ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* Call the progress callback if it is configured and the required number ** of VDBE ops have been executed (either since this invocation of ** sqliteVdbeExec() or since last time the progress callback was called). ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ if( db->xProgress ){ if( db->nProgressOps==nProgressOps ){ if( db->xProgress(db->pProgressArg)!=0 ){ rc = SQLITE_ABORT; continue; /* skip to the next iteration of the for loop */ } nProgressOps = 0; } nProgressOps++; }#endif switch( pOp->opcode ){/******************************************************************************* What follows is a massive switch statement where each case implements a** separate instruction in the virtual machine. If we follow the usual** indentation conventions, each case should be indented by 6 spaces. But** that is a lot of wasted space on the left margin. So the code within** the switch statement will break with convention and be flush-left. Another** big comment (similar to this one) will mark the point in the code where** we transition back to normal indentation.**** The formatting of each case is important. The makefile for SQLite** generates two C files "opcodes.h" and "opcodes.c" by scanning this** file looking for lines that begin with "case OP_". The opcodes.h files** will be filled with #defines that give unique integer values to each** opcode and the opcodes.c file is filled with an array of strings where** each string is the symbolic name for the corresponding opcode.**** Documentation about VDBE opcodes is generated by scanning this file** for lines of that contain "Opcode:". That line and all subsequent** comment lines are used in the generation of the opcode.html documentation** file.**** SUMMARY:**** Formatting is important to scripts that scan this file.** Do not deviate from the formatting style currently in use.*******************************************************************************//* Opcode: Goto * P2 ***** An unconditional jump to address P2.** The next instruction executed will be ** the one at index P2 from the beginning of** the program.*/case OP_Goto: { CHECK_FOR_INTERRUPT; pc = pOp->p2 - 1; break;}/* Opcode: Gosub * P2 ***** Push the current address plus 1 onto the return address stack** and then jump to address P2.**** The return address stack is of limited depth. If too many** OP_Gosub operations occur without intervening OP_Returns, then** the return address stack will fill up and processing will abort** with a fatal error.*/case OP_Gosub: { if( p->returnDepth>=sizeof(p->returnStack)/sizeof(p->returnStack[0]) ){ sqliteSetString(&p->zErrMsg, "return address stack overflow", (char*)0); p->rc = SQLITE_INTERNAL; return SQLITE_ERROR; } p->returnStack[p->returnDepth++] = pc+1; pc = pOp->p2 - 1; break;}/* Opcode: Return * * ***** Jump immediately to the next instruction after the last unreturned** OP_Gosub. If an OP_Return has occurred for all OP_Gosubs, then** processing aborts with a fatal error.*/case OP_Return: { if( p->returnDepth<=0 ){ sqliteSetString(&p->zErrMsg, "return address stack underflow", (char*)0); p->rc = SQLITE_INTERNAL; return SQLITE_ERROR; } p->returnDepth--; pc = p->returnStack[p->returnDepth] - 1; break;}/* Opcode: Halt P1 P2 ***** Exit immediately. All open cursors, Lists, Sorts, etc are closed** automatically.**** P1 is the result code returned by sqlite_exec(). For a normal** halt, this should be SQLITE_OK (0). For errors, it can be some** other value. If P1!=0 then P2 will determine whether or not to** rollback the current transaction. Do not rollback if P2==OE_Fail.** Do the rollback if P2==OE_Rollback. If P2==OE_Abort, then back** out all changes that have occurred during this execution of the** VDBE, but do not rollback the transaction. **** There is an implied "Halt 0 0 0" instruction inserted at the very end of** every program. So a jump past the last instruction of the program** is the same as executing Halt.*/case OP_Halt: { p->magic = VDBE_MAGIC_HALT; p->pTos = pTos; if( pOp->p1!=SQLITE_OK ){ p->rc = pOp->p1; p->errorAction = pOp->p2; if( pOp->p3 ){ sqliteSetString(&p->zErrMsg, pOp->p3, (char*)0); } return SQLITE_ERROR; }else{ p->rc = SQLITE_OK; return SQLITE_DONE; }}/* Opcode: Integer P1 * P3**** The integer value P1 is pushed onto the stack. If P3 is not zero** then it is assumed to be a string representation of the same integer.*/case OP_Integer: { pTos++; pTos->i = pOp->p1; pTos->flags = MEM_Int; if( pOp->p3 ){ pTos->z = pOp->p3; pTos->flags |= MEM_Str | MEM_Static; pTos->n = strlen(pOp->p3)+1; } break;}/* Opcode: String * * P3**** The string value P3 is pushed onto the stack. If P3==0 then a** NULL is pushed onto the stack.*/case OP_String: { char *z = pOp->p3; pTos++; if( z==0 ){ pTos->flags = MEM_Null; }else{ pTos->z = z; pTos->n = strlen(z) + 1; pTos->flags = MEM_Str | MEM_Static; } break;}/* Opcode: Variable P1 * ***** Push the value of variable P1 onto the stack. A variable is** an unknown in the original SQL string as handed to sqlite_compile().** Any occurance of the '?' character in the original SQL is considered** a variable. Variables in the SQL string are number from left to** right beginning with 1. The values of variables are set using the** sqlite_bind() API.*/case OP_Variable: { int j = pOp->p1 - 1; pTos++; if( j>=0 && j<p->nVar && p->azVar[j]!=0 ){ pTos->z = p->azVar[j]; pTos->n = p->anVar[j]; pTos->flags = MEM_Str | MEM_Static; }else{ pTos->flags = MEM_Null; } break;}/* Opcode: Pop P1 * ***** P1 elements are popped off of the top of stack and discarded.*/case OP_Pop: { assert( pOp->p1>=0 ); popStack(&pTos, pOp->p1); assert( pTos>=&p->aStack[-1] ); break;}/* Opcode: Dup P1 P2 ***** A copy of the P1-th element of the stack ** is made and pushed onto the top of the stack.** The top of the stack is element 0. So the** instruction "Dup 0 0 0" will make a copy of the** top of the stack.**** If the content of the P1-th element is a dynamically** allocated string, then a new copy of that string** is made if P2==0. If P2!=0, then just a pointer** to the string is copied.**** Also see the Pull instruction.*/case OP_Dup: { Mem *pFrom = &pTos[-pOp->p1]; assert( pFrom<=pTos && pFrom>=p->aStack ); pTos++; memcpy(pTos, pFrom, sizeof(*pFrom)-NBFS); if( pTos->flags & MEM_Str ){ if( pOp->p2 && (pTos->flags & (MEM_Dyn|MEM_Ephem)) ){ pTos->flags &= ~MEM_Dyn; pTos->flags |= MEM_Ephem; }else if( pTos->flags & MEM_Short ){ memcpy(pTos->zShort, pFrom->zShort, pTos->n); pTos->z = pTos->zShort; }else if( (pTos->flags & MEM_Static)==0 ){ pTos->z = sqliteMallocRaw(pFrom->n); if( sqlite_malloc_failed ) goto no_mem; memcpy(pTos->z, pFrom->z, pFrom->n); pTos->flags &= ~(MEM_Static|MEM_Ephem|MEM_Short); pTos->flags |= MEM_Dyn; } } break;}/* Opcode: Pull P1 * ***** The P1-th element is removed from its current location on ** the stack and pushed back on top of the stack. The** top of the stack is element 0, so "Pull 0 0 0" is** a no-op. "Pull 1 0 0" swaps the top two elements of** the stack.**** See also the Dup instruction.*/case OP_Pull: { Mem *pFrom = &pTos[-pOp->p1]; int i; Mem ts; ts = *pFrom; Deephemeralize(pTos); for(i=0; i<pOp->p1; i++, pFrom++){ Deephemeralize(&pFrom[1]); *pFrom = pFrom[1]; assert( (pFrom->flags & MEM_Ephem)==0 ); if( pFrom->flags & MEM_Short ){ assert( pFrom->flags & MEM_Str ); assert( pFrom->z==pFrom[1].zShort ); pFrom->z = pFrom->zShort; } } *pTos = ts; if( pTos->flags & MEM_Short ){ assert( pTos->flags & MEM_Str ); assert( pTos->z==pTos[-pOp->p1].zShort ); pTos->z = pTos->zShort; } break;}/* Opcode: Push P1 * ***** Overwrite the value of the P1-th element down on the** stack (P1==0 is the top of the stack) with the value** of the top of the stack. Then pop the top of the stack.*/case OP_Push: { Mem *pTo = &pTos[-pOp->p1]; assert( pTo>=p->aStack ); Deephemeralize(pTos); Release(pTo); *pTo = *pTos; if( pTo->flags & MEM_Short ){ assert( pTo->z==pTos->zShort ); pTo->z = pTo->zShort; } pTos--; break;}/* Opcode: ColumnName P1 P2 P3**** P3 becomes the P1-th column name (first is 0). An array of pointers** to all column names is passed as the 4th parameter to the callback.** If P2==1 then this is the last column in the result set and thus the** number of columns in the result set will be P1. There must be at least** one OP_ColumnName with a P2==1 before invoking OP_Callback and the** number of columns specified in OP_Callback must one more than the P1** value of the OP_ColumnName that has P2==1.*/case OP_ColumnName: { assert( pOp->p1>=0 && pOp->p1<p->nOp ); p->azColName[pOp->p1] = pOp->p3; p->nCallback = 0; if( pOp->p2 ) p->nResColumn = pOp->p1+1; break;}/* Opcode: Callback P1 * ***** Pop P1 values off the stack and form them into an array. Then
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -