📄 vdbe.c
字号:
** 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++; sqlite3VdbeMemShallowCopy(pTos, pFrom, MEM_Ephem); if( pOp->p2 ){ Deephemeralize(pTos); } 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: { /* no-push */ Mem *pFrom = &pTos[-pOp->p1]; int i; Mem ts; ts = *pFrom; Deephemeralize(pTos); for(i=0; i<pOp->p1; i++, pFrom++){ Deephemeralize(&pFrom[1]); assert( (pFrom->flags & MEM_Ephem)==0 ); *pFrom = pFrom[1]; if( pFrom->flags & MEM_Short ){ assert( pFrom->flags & (MEM_Str|MEM_Blob) ); assert( pFrom->z==pFrom[1].zShort ); pFrom->z = pFrom->zShort; } } *pTos = ts; if( pTos->flags & MEM_Short ){ assert( pTos->flags & (MEM_Str|MEM_Blob) ); 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: { /* no-push */ Mem *pTo = &pTos[-pOp->p1]; assert( pTo>=p->aStack ); sqlite3VdbeMemMove(pTo, pTos); pTos--; 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: { /* no-push */ int i; assert( p->nResColumn==pOp->p1 ); for(i=0; i<pOp->p1; i++){ Mem *pVal = &pTos[0-i]; sqlite3VdbeMemNulTerminate(pVal); storeTypeInfo(pVal, db->enc); } p->resOnStack = 1; p->nCallback++; p->popStack = pOp->p1; p->pc = pc + 1; p->pTos = pTos; return SQLITE_ROW;}/* Opcode: Concat P1 P2 ***** Look at the first P1+2 elements of the stack. Append them all ** together with the lowest element first. The original P1+2 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.**** When P1==1, this routine makes a copy of the top stack element** into memory obtained from sqliteMalloc().*/case OP_Concat: { /* same as TK_CONCAT */ char *zNew; int nByte; int nField; int i, j; Mem *pTerm; /* Loop through the stack elements to see how long the result will be. */ nField = pOp->p1 + 2; pTerm = &pTos[1-nField]; nByte = 0; for(i=0; i<nField; i++, pTerm++){ assert( pOp->p2==0 || (pTerm->flags&MEM_Str) ); if( pTerm->flags&MEM_Null ){ nByte = -1; break; } Stringify(pTerm, db->enc); nByte += pTerm->n; } if( nByte<0 ){ /* If nByte is less than zero, then there is a NULL value on the stack. ** In this case just pop the values off the stack (if required) and ** push on a NULL. */ if( pOp->p2==0 ){ popStack(&pTos, nField); } pTos++; pTos->flags = MEM_Null; }else{ /* Otherwise malloc() space for the result and concatenate all the ** stack values. */ zNew = sqliteMallocRaw( nByte+2 ); if( zNew==0 ) goto no_mem; j = 0; pTerm = &pTos[1-nField]; for(i=j=0; i<nField; i++, pTerm++){ int n = pTerm->n; assert( pTerm->flags & MEM_Str ); memcpy(&zNew[j], pTerm->z, n); j += n; } zNew[j] = 0; zNew[j+1] = 0; assert( j==nByte ); if( pOp->p2==0 ){ popStack(&pTos, nField); } pTos++; pTos->n = j; pTos->flags = MEM_Str|MEM_Dyn|MEM_Term; pTos->xDel = 0; pTos->enc = db->enc; pTos->z = 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: /* same as TK_PLUS, no-push */case OP_Subtract: /* same as TK_MINUS, no-push */case OP_Multiply: /* same as TK_STAR, no-push */case OP_Divide: /* same as TK_SLASH, no-push */case OP_Remainder: { /* same as TK_REM, no-push */ Mem *pNos = &pTos[-1]; assert( pNos>=p->aStack ); if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){ Release(pTos); pTos--; Release(pTos); pTos->flags = MEM_Null; }else if( (pTos->flags & pNos->flags & MEM_Int)==MEM_Int ){ i64 a, b; a = pTos->i; b = pNos->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; } } Release(pTos); pTos--; Release(pTos); pTos->i = b; pTos->flags = MEM_Int; }else{ double a, b; a = sqlite3VdbeRealValue(pTos); b = sqlite3VdbeRealValue(pNos); 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; } } Release(pTos); pTos--; Release(pTos); pTos->r = b; pTos->flags = MEM_Real; } break;divide_by_zero: Release(pTos); pTos--; Release(pTos); pTos->flags = MEM_Null; break;}/* Opcode: CollSeq * * P3**** P3 is a pointer to a CollSeq struct. If the next call to a user function** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will** be returned. This is used by the built-in min(), max() and nullif()** functions.**** The interface used by the implementation of the aforementioned functions** to retrieve the collation sequence set by this opcode is not available** publicly, only to user functions defined in func.c.*/case OP_CollSeq: { /* no-push */ assert( pOp->p3type==P3_COLLSEQ ); break;}/* Opcode: Function P1 P2 P3**** Invoke a user function (P3 is a pointer to a Function structure that** defines the function) with P1 arguments taken from the stack. Pop all** arguments from the stack and push back the result.**** P2 is a 32-bit bitmask indicating whether or not each argument to the ** function was determined to be constant at compile time. If the first** argument was constant then bit 0 of P2 is set. This is used to determine** whether meta data associated with a user function argument using the** sqlite3_set_auxdata() API may be safely retained until the next** invocation of this opcode.**** See also: AggFunc*/case OP_Function: { int i; Mem *pArg; sqlite3_context ctx; sqlite3_value **apVal; int n = pOp->p1; n = pOp->p1; apVal = p->apArg; assert( apVal || n==0 ); pArg = &pTos[1-n]; for(i=0; i<n; i++, pArg++){ apVal[i] = pArg; storeTypeInfo(pArg, db->enc); } assert( pOp->p3type==P3_FUNCDEF || pOp->p3type==P3_VDBEFUNC ); if( pOp->p3type==P3_FUNCDEF ){ ctx.pFunc = (FuncDef*)pOp->p3; ctx.pVdbeFunc = 0; }else{ ctx.pVdbeFunc = (VdbeFunc*)pOp->p3; ctx.pFunc = ctx.pVdbeFunc->pFunc; } ctx.s.flags = MEM_Null; ctx.s.z = 0; ctx.s.xDel = 0; ctx.isError = 0; if( ctx.pFunc->needCollSeq ){ assert( pOp>p->aOp ); assert( pOp[-1].p3type==P3_COLLSEQ ); assert( pOp[-1].opcode==OP_CollSeq ); ctx.pColl = (CollSeq *)pOp[-1].p3; } if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; (*ctx.pFunc->xFunc)(&ctx, n, apVal); if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( sqlite3_malloc_failed ) goto no_mem; popStack(&pTos, n); /* If any auxilary data functions have been called by this user function, ** immediately call the destructor for any non-static values. */ if( ctx.pVdbeFunc ){ sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p2); pOp->p3 = (char *)ctx.pVdbeFunc; pOp->p3type = P3_VDBEFUNC; } /* Copy the result of the function to the top of the stack */ sqlite3VdbeChangeEncoding(&ctx.s, db->enc); pTos++; pTos->flags = 0; sqlite3VdbeMemMove(pTos, &ctx.s); /* If the function returned an error, throw an exception */ if( ctx.isError ){ if( !(pTos->flags&MEM_Str) ){ sqlite3SetString(&p->zErrMsg, "user function error", (char*)0); }else{ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pTos), (char*)0); sqlite3VdbeChangeEncoding(pTos, db->enc); } rc = SQLITE_ERROR; } break;}/* Opcode: BitAnd * * ***** Pop the top two elements from the stack. Convert both elements** to integers. Push back onto the stack the bit-wise AND of the** two elements.** If either operand is NULL, the result is NULL.*//* Opcode: BitOr * * ***** Pop the top two elements from the stack. Convert both elements** to integers. Push back onto the stack the bit-wise OR of the** two elements.** If either operand is NULL, the result is NULL.*//* Opcode: ShiftLeft * * ***** Pop the top two elements from the stack. Convert both elements** to integers. Push back onto the stack the second element shifted** left by N bits where N is the top element on the stack.** If either operand is NULL, the result is NULL.*//* Opcode: ShiftRight * * ***** Pop the top two elements from the stack. Convert both elements** to integers. Push back onto the stack the second element shifted** right by N bits where N is the top element on the stack.** If either operand is NULL, the result is NULL.*/case OP_BitAnd: /* same as TK_BITAND, no-push */case OP_BitOr: /* same as TK_BITOR, no-push */case OP_ShiftLeft: /* same as TK_LSHIFT, no-push */case OP_ShiftRight: { /* same as TK_RSHIFT, no-push */ Mem *pNos = &pTos[-1]; int a, b; assert( pNos>=p->aStack ); if( (pTos->flags | pNos->flags) & MEM_Null ){ popStack(&pTos, 2); pTos++; pTos->flags = MEM_Null; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -