📄 vdbe.c
字号:
/* 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: { int i = ++p->tos; aStack[i].i = pOp->p1; aStack[i].flags = STK_Int; if( pOp->p3 ){ zStack[i] = pOp->p3; aStack[i].flags |= STK_Str | STK_Static; aStack[i].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: { int i = ++p->tos; char *z; z = pOp->p3; if( z==0 ){ zStack[i] = 0; aStack[i].n = 0; aStack[i].flags = STK_Null; }else{ zStack[i] = z; aStack[i].n = strlen(z) + 1; aStack[i].flags = STK_Str | STK_Static; } break;}/* Opcode: Pop P1 * ***** P1 elements are popped off of the top of stack and discarded.*/case OP_Pop: { assert( p->tos+1>=pOp->p1 ); PopStack(p, pOp->p1); 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: { int i = p->tos - pOp->p1; int j = ++p->tos; VERIFY( if( i<0 ) goto not_enough_stack; ) memcpy(&aStack[j], &aStack[i], sizeof(aStack[i])-NBFS); if( aStack[j].flags & STK_Str ){ int isStatic = (aStack[j].flags & STK_Static)!=0; if( pOp->p2 || isStatic ){ zStack[j] = zStack[i]; aStack[j].flags &= ~STK_Dyn; if( !isStatic ) aStack[j].flags |= STK_Ephem; }else if( aStack[i].n<=NBFS ){ memcpy(aStack[j].z, zStack[i], aStack[j].n); zStack[j] = aStack[j].z; aStack[j].flags &= ~(STK_Static|STK_Dyn|STK_Ephem); }else{ zStack[j] = sqliteMallocRaw( aStack[j].n ); if( zStack[j]==0 ) goto no_mem; memcpy(zStack[j], zStack[i], aStack[j].n); aStack[j].flags &= ~(STK_Static|STK_Ephem); aStack[j].flags |= STK_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: { int from = p->tos - pOp->p1; int to = p->tos; int i; Stack ts; char *tz; VERIFY( if( from<0 ) goto not_enough_stack; ) Deephemeralize(p, from); ts = aStack[from]; tz = zStack[from]; Deephemeralize(p, to); for(i=from; i<to; i++){ Deephemeralize(p, i+1); aStack[i] = aStack[i+1]; assert( (aStack[i].flags & STK_Ephem)==0 ); if( aStack[i].flags & (STK_Dyn|STK_Static) ){ zStack[i] = zStack[i+1]; }else{ zStack[i] = aStack[i].z; } } aStack[to] = ts; assert( (aStack[to].flags & STK_Ephem)==0 ); if( aStack[to].flags & (STK_Dyn|STK_Static) ){ zStack[to] = tz; }else{ zStack[to] = aStack[to].z; } 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: { int from = p->tos; int to = p->tos - pOp->p1; VERIFY( if( to<0 ) goto not_enough_stack; ) if( aStack[to].flags & STK_Dyn ){ sqliteFree(zStack[to]); } Deephemeralize(p, from); aStack[to] = aStack[from]; if( aStack[to].flags & (STK_Dyn|STK_Static|STK_Ephem) ){ zStack[to] = zStack[from]; }else{ zStack[to] = aStack[to].z; } aStack[from].flags = 0; p->tos--; break;}/* Opcode: ColumnName P1 * 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.*/case OP_ColumnName: { assert( pOp->p1>=0 && pOp->p1<p->nOp ); p->azColName[pOp->p1] = pOp->p3; p->nCallback = 0; break;}/* Opcode: Callback P1 * ***** Pop P1 values off the stack and form them into an array. Then** invoke the callback function using the newly formed array as the** 3rd parameter.*/case OP_Callback: { int i = p->tos - pOp->p1 + 1; int j; VERIFY( if( i<0 ) goto not_enough_stack; ) for(j=i; j<=p->tos; j++){ if( aStack[j].flags & STK_Null ){ zStack[j] = 0; }else{ Stringify(p, j); } } zStack[p->tos+1] = 0; if( p->xCallback==0 ){ p->azResColumn = &zStack[i]; p->nResColumn = pOp->p1; p->popStack = pOp->p1; p->pc = pc + 1; return SQLITE_ROW; } if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; if( p->xCallback(p->pCbArg, pOp->p1, &zStack[i], p->azColName)!=0 ){ rc = SQLITE_ABORT; } if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; p->nCallback++; PopStack(p, pOp->p1); if( sqlite_malloc_failed ) goto no_mem; break;}/* Opcode: NullCallback P1 * ***** Invoke the callback function once with the 2nd argument (the** number of columns) equal to P1 and with the 4th argument (the** names of the columns) set according to prior OP_ColumnName** instructions. This is all like the regular** OP_Callback or OP_SortCallback opcodes. But the 3rd argument** which normally contains a pointer to an array of pointers to** data is NULL.**** The callback is only invoked if there have been no prior calls** to OP_Callback or OP_SortCallback.**** This opcode is used to report the number and names of columns** in cases where the result set is empty.*/case OP_NullCallback: { if( p->nCallback==0 && p->xCallback!=0 ){ if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; if( p->xCallback(p->pCbArg, pOp->p1, 0, p->azColName)!=0 ){ rc = SQLITE_ABORT; } if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; p->nCallback++; if( sqlite_malloc_failed ) goto no_mem; } p->nResColumn = pOp->p1; break;}/* Opcode: Concat P1 P2 P3**** Look at the first P1 elements of the stack. Append them all ** together with the lowest element first. Use P3 as a separator. ** Put the result on the top of the stack. The original P1 elements** are popped from the stack if P2==0 and retained if P2==1. If** any element of the stack is NULL, then the result is NULL.**** If P3 is NULL, then use no separator. When P1==1, this routine** makes a copy of the top stack element into memory obtained** from sqliteMalloc().*/case OP_Concat: { char *zNew; int nByte; int nField; int i, j; char *zSep; int nSep; nField = pOp->p1; zSep = pOp->p3; if( zSep==0 ) zSep = ""; nSep = strlen(zSep); VERIFY( if( p->tos+1<nField ) goto not_enough_stack; ) nByte = 1 - nSep; for(i=p->tos-nField+1; i<=p->tos; i++){ if( aStack[i].flags & STK_Null ){ nByte = -1; break; }else{ Stringify(p, i); nByte += aStack[i].n - 1 + nSep; } } if( nByte<0 ){ if( pOp->p2==0 ) PopStack(p, nField); p->tos++; aStack[p->tos].flags = STK_Null; zStack[p->tos] = 0; break; } zNew = sqliteMallocRaw( nByte ); if( zNew==0 ) goto no_mem; j = 0; for(i=p->tos-nField+1; i<=p->tos; i++){ if( (aStack[i].flags & STK_Null)==0 ){ memcpy(&zNew[j], zStack[i], aStack[i].n-1); j += aStack[i].n-1; } if( nSep>0 && i<p->tos ){ memcpy(&zNew[j], zSep, nSep); j += nSep; } } zNew[j] = 0; if( pOp->p2==0 ) PopStack(p, nField); p->tos++; aStack[p->tos].n = nByte; aStack[p->tos].flags = STK_Str|STK_Dyn; zStack[p->tos] = zNew; break;}/* Opcode: Add * * ***** Pop the top two elements from the stack, add them together,** and push the result back onto the stack. If either element** is a string then it is converted to a double using the atof()** function before the addition.** If either operand is NULL, the result is NULL.*//* Opcode: Multiply * * ***** Pop the top two elements from the stack, multiply them together,** and push the result back onto the stack. If either element** is a string then it is converted to a double using the atof()** function before the multiplication.** If either operand is NULL, the result is NULL.*//* Opcode: Subtract * * ***** Pop the top two elements from the stack, subtract the** first (what was on top of the stack) from the second (the** next on stack)** and push the result back onto the stack. If either element** is a string then it is converted to a double using the atof()** function before the subtraction.** If either operand is NULL, the result is NULL.*//* Opcode: Divide * * ***** Pop the top two elements from the stack, divide the** first (what was on top of the stack) from the second (the** next on stack)** and push the result back onto the stack. If either element** is a string then it is converted to a double using the atof()** function before the division. Division by zero returns NULL.** If either operand is NULL, the result is NULL.*//* Opcode: Remainder * * ***** Pop the top two elements from the stack, divide the** first (what was on top of the stack) from the second (the** next on stack)** and push the remainder after division onto the stack. If either element** is a string then it is converted to a double using the atof()** function before the division. Division by zero returns NULL.** If either operand is NULL, the result is NULL.*/case OP_Add:case OP_Subtract:case OP_Multiply:case OP_Divide:case OP_Remainder: { int tos = p->tos; int nos = tos - 1; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( ((aStack[tos].flags | aStack[nos].flags) & STK_Null)!=0 ){ POPSTACK; Release(p, nos); aStack[nos].flags = STK_Null; }else if( (aStack[tos].flags & aStack[nos].flags & STK_Int)==STK_Int ){ int a, b; a = aStack[tos].i; b = aStack[nos].i; switch( pOp->opcode ){ case OP_Add: b += a; break; case OP_Subtract: b -= a; break; case OP_Multiply: b *= a; break; case OP_Divide: { if( a==0 ) goto divide_by_zero; b /= a; break; } default: { if( a==0 ) goto divide_by_zero; b %= a; break; } } POPSTACK; Release(p, nos); aStack[nos].i = b; aStack[nos].flags = STK_Int; }else{ double a, b; Realify(p, tos); Realify(p, nos); a = aStack[tos].r; b = aStack[nos].r; switch( pOp->opcode ){ case OP_Add: b += a; break; case OP_Subtract: b -= a; break; case OP_Multiply: b *= a; break; case OP_Divide: { if( a==0.0 ) goto divide_by_zero; b /= a; break; } default: { int ia = (int)a; int ib = (int)b; if( ia==0.0 ) goto divide_by_zero; b = ib % ia; break; } } POPSTACK; Release(p, nos); aStack[nos].r = b; aStack[nos].flags = STK_Real; } break;divide_by_zero: PopStack(p, 2); p->tos = nos; aStack[nos].flags = STK_Null; break;}/* Opcode: Function P1 * P3**** Invoke a user function (P3 is a pointer to a Function structure that** defines the function) with P1 string arguments taken from the stack.** Pop all arguments from the stack and push back the result.**** See also: AggFunc*/case OP_Function: { int n, i; sqlite_func ctx; n = pOp->p1; VERIFY( if( n<0 ) goto bad_instruction; ) VERIFY( if( p->tos+1<n ) goto not
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -