1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Cache the sqlite3_context structure in the P4 operand of VDBE programs

for faster SQL function dispatch.

FossilOrigin-Name: 2abc44eb3b9d489321baa50bc25e17dafbda3687
This commit is contained in:
drh
2015-06-26 18:16:52 +00:00
parent 68cdd0eda2
commit 9c7c913cd6
11 changed files with 179 additions and 106 deletions

View File

@@ -1,5 +1,5 @@
C Fix\sharmless\scompiler\swarning\sin\sassert\sstatement. C Cache\sthe\ssqlite3_context\sstructure\sin\sthe\sP4\soperand\sof\sVDBE\sprograms\nfor\sfaster\sSQL\sfunction\sdispatch.
D 2015-06-26T03:12:27.469 D 2015-06-26T18:16:52.781
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025 F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -173,7 +173,7 @@ F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F main.mk 68f86c21505d6b66765a13c193f00a53dde6a212 F main.mk 68f86c21505d6b66765a13c193f00a53dde6a212
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkopcodeh.awk 0e7f04a8eb90f92259e47d80110e4e98d7ce337a
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -186,8 +186,8 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 48e14b8aea28dc58baafe3cfcb8889c086b7744a F src/alter.c 48e14b8aea28dc58baafe3cfcb8889c086b7744a
F src/analyze.c d23790787f80ebed58df7774744b4cf96401498b F src/analyze.c f89727c36f997bd2bf6c5e546c2f51dc94e6f2a4
F src/attach.c c38ac5a520a231d5d0308fd7f2ad95191c867bae F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3 F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d
@@ -202,7 +202,7 @@ F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac
F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a
F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa
F src/expr.c 32c836d9fa22c25371039febf074849dcefb3de9 F src/expr.c c5c58e4d01c7ceb2266791d8d877f1b23a88e316
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/fkey.c c9b63a217d86582c22121699a47f22f524608869
F src/func.c a98ea5880dc50e9ca6dd6f57079a37b9cfcdecf1 F src/func.c a98ea5880dc50e9ca6dd6f57079a37b9cfcdecf1
@@ -250,7 +250,7 @@ F src/printf.c db11b5960105ee661dcac690f2ae6276e49bf251
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 2d47554370de8de6dd5be060cef9559eec315005 F src/resolve.c 2d47554370de8de6dd5be060cef9559eec315005
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c 9baeda79f93cfd180d471273a2f9c82c682a37a2 F src/select.c 009c6138be8788449d4f911f380d99e8608040e2
F src/shell.c 8af3cced094aebb5f57a8ad739b9dafc7867eed7 F src/shell.c 8af3cced094aebb5f57a8ad739b9dafc7867eed7
F src/sqlite.h.in 76d2f5637eb795b6300d9dd3c3ec3632ffafd721 F src/sqlite.h.in 76d2f5637eb795b6300d9dd3c3ec3632ffafd721
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
@@ -313,11 +313,11 @@ F src/update.c 487747b328b7216bb7f6af0695d6937d5c9e605f
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c a6431c92803b975b7322724a7b433e538d243539 F src/util.c a6431c92803b975b7322724a7b433e538d243539
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
F src/vdbe.c 3af2d06e2b36012631dc3331957df52febdf8678 F src/vdbe.c 8fde5281f304c31fd635891b3cb138e6b79ce9f5
F src/vdbe.h 90048aea1910f9df93e6044592bd4a466dc9c5e7 F src/vdbe.h 7a75045d879118b9d3af7e8b3c108f2f27c51473
F src/vdbeInt.h 20295e482121d13437f69985f77db211cdc8bac1 F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816
F src/vdbeapi.c 6a0d7757987018ff6b1b81bc5293219cd26bb299 F src/vdbeapi.c 6a0d7757987018ff6b1b81bc5293219cd26bb299
F src/vdbeaux.c 4c82d6f686f72ea7d266d26d528a171b728626f7 F src/vdbeaux.c 316e6bc773559d164155848f086c4b7d146f483a
F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90
F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090 F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090
F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b
@@ -1286,7 +1286,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 015302f15e46a087ec92f3644c6741600dbf4306 P 7097716caed9d4aef49c7e766e41ea74abf5967f
R 868fbc5146ce4734a4f8cc498ff855f9 R 61b5a8d7a0dc65b1ab9c06045c3a6290
U mistachkin U drh
Z 40a758e35083225387fb9eeb28b88d0c Z 9dd787a20069829fde828ff0d1be6044

View File

@@ -1 +1 @@
7097716caed9d4aef49c7e766e41ea74abf5967f 2abc44eb3b9d489321baa50bc25e17dafbda3687

View File

@@ -122,9 +122,7 @@ END {
for(i=0; i<n_op; i++){ for(i=0; i<n_op; i++){
name = order[i]; name = order[i];
if( op[name]>=0 ) continue; if( op[name]>=0 ) continue;
if( name=="OP_Function" \ if( name=="OP_Transaction" \
|| name=="OP_AggStep" \
|| name=="OP_Transaction" \
|| name=="OP_AutoCommit" \ || name=="OP_AutoCommit" \
|| name=="OP_Savepoint" \ || name=="OP_Savepoint" \
|| name=="OP_Checkpoint" \ || name=="OP_Checkpoint" \

View File

@@ -943,7 +943,7 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
#else #else
UNUSED_PARAMETER( iParam ); UNUSED_PARAMETER( iParam );
#endif #endif
sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4, regOut); sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4, regOut);
sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, 1 + IsStat34); sqlite3VdbeChangeP5(v, 1 + IsStat34);
} }
@@ -1098,7 +1098,7 @@ static void analyzeOneTable(
#endif #endif
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1); sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4); sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4+1, regStat4);
sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, 2+IsStat34); sqlite3VdbeChangeP5(v, 2+IsStat34);
@@ -1194,7 +1194,7 @@ static void analyzeOneTable(
} }
#endif #endif
assert( regChng==(regStat4+1) ); assert( regChng==(regStat4+1) );
sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp); sqlite3VdbeAddOp3(v, OP_Function0, 1, regStat4, regTemp);
sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, 2+IsStat34); sqlite3VdbeChangeP5(v, 2+IsStat34);
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);

View File

@@ -359,7 +359,7 @@ static void codeAttach(
assert( v || db->mallocFailed ); assert( v || db->mallocFailed );
if( v ){ if( v ){
sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-pFunc->nArg, regArgs+3); sqlite3VdbeAddOp3(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3);
assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg ); assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg)); sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF); sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);

View File

@@ -2925,7 +2925,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
if( !pColl ) pColl = db->pDfltColl; if( !pColl ) pColl = db->pDfltColl;
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
} }
sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target, sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target,
(char*)pDef, P4_FUNCDEF); (char*)pDef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nFarg); sqlite3VdbeChangeP5(v, (u8)nFarg);
if( nFarg && constMask==0 ){ if( nFarg && constMask==0 ){

View File

@@ -4686,7 +4686,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
} }
sqlite3VdbeAddOp4(v, OP_AggStep, 0, regAgg, pF->iMem, sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem,
(void*)pF->pFunc, P4_FUNCDEF); (void*)pF->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nArg); sqlite3VdbeChangeP5(v, (u8)nArg);
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg); sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);

View File

@@ -1546,7 +1546,7 @@ case OP_CollSeq: {
break; break;
} }
/* Opcode: Function P1 P2 P3 P4 P5 /* Opcode: Function0 P1 P2 P3 P4 P5
** Synopsis: r[P3]=func(r[P2@P5]) ** Synopsis: r[P3]=func(r[P2@P5])
** **
** Invoke a user function (P4 is a pointer to a Function structure that ** Invoke a user function (P4 is a pointer to a Function structure that
@@ -1561,59 +1561,99 @@ case OP_CollSeq: {
** sqlite3_set_auxdata() API may be safely retained until the next ** sqlite3_set_auxdata() API may be safely retained until the next
** invocation of this opcode. ** invocation of this opcode.
** **
** See also: AggStep and AggFinal ** See also: Function, AggStep, AggFinal
*/ */
case OP_Function: { /* Opcode: Function P1 P2 P3 P4 P5
int i; ** Synopsis: r[P3]=func(r[P2@P5])
Mem *pArg; **
sqlite3_context ctx; ** Invoke a user function (P4 is a pointer to an sqlite3_context object that
sqlite3_value **apVal; ** contains a pointer to the function to be run) with P5 arguments taken
** from register P2 and successors. The result of the function is stored
** in register P3. Register P3 must not be one of the function inputs.
**
** P1 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 P1 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.
**
** SQL functions are initially coded as OP_Function0 with P4 pointing
** to the function itself. But on first evaluation, the P4 operand is
** automatically converted into an sqlite3_context object and the operation
** changed to this OP_Function opcode. In this way, the initialization of
** the sqlite3_context object occurs only once, rather than once for each
** evaluation of the function.
**
** See also: Function0, AggStep, AggFinal
*/
case OP_Function0: {
int n; int n;
sqlite3_context *pCtx;
n = pOp->p5;
apVal = p->apArg;
assert( apVal || n==0 );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
ctx.pOut = &aMem[pOp->p3];
memAboutToChange(p, ctx.pOut);
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pArg = &aMem[pOp->p2];
for(i=0; i<n; i++, pArg++){
assert( memIsValid(pArg) );
apVal[i] = pArg;
Deephemeralize(pArg);
REGISTER_TRACE(pOp->p2+i, pArg);
}
assert( pOp->p4type==P4_FUNCDEF ); assert( pOp->p4type==P4_FUNCDEF );
ctx.pFunc = pOp->p4.pFunc; n = pOp->p5;
ctx.iOp = (int)(pOp - aOp); assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
ctx.pVdbe = p; assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
MemSetTypeFlag(ctx.pOut, MEM_Null); assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
ctx.fErrorOrAux = 0; pCtx = sqlite3DbMallocRaw(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
if( pCtx==0 ) goto no_mem;
pCtx->pOut = 0;
pCtx->pFunc = pOp->p4.pFunc;
pCtx->iOp = (int)(pOp - aOp);
pCtx->pVdbe = p;
pCtx->argc = n;
pOp->p4type = P4_FUNCCTX;
pOp->p4.pCtx = pCtx;
pOp->opcode = OP_Function;
/* Fall through into OP_Function */
}
case OP_Function: {
int i;
sqlite3_context *pCtx;
assert( pOp->p4type==P4_FUNCCTX );
pCtx = pOp->p4.pCtx;
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
** reinitializes the relavant parts of the sqlite3_context object */
if( pCtx->pOut != &aMem[pOp->p3] ){
pCtx->pOut = &aMem[pOp->p3];
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
}
memAboutToChange(p, pCtx->pOut);
#ifdef SQLITE_DEBUG
for(i=0; i<pCtx->argc; i++){
assert( memIsValid(pCtx->argv[i]) );
REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
}
#endif
MemSetTypeFlag(pCtx->pOut, MEM_Null);
pCtx->fErrorOrAux = 0;
db->lastRowid = lastRowid; db->lastRowid = lastRowid;
(*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */ (*pCtx->pFunc->xFunc)(pCtx, pCtx->argc, pCtx->argv); /* IMP: R-24505-23230 */
lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */ lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */
/* If the function returned an error, throw an exception */ /* If the function returned an error, throw an exception */
if( ctx.fErrorOrAux ){ if( pCtx->fErrorOrAux ){
if( ctx.isError ){ if( pCtx->isError ){
sqlite3VdbeError(p, "%s", sqlite3_value_text(ctx.pOut)); sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
rc = ctx.isError; rc = pCtx->isError;
} }
sqlite3VdbeDeleteAuxData(p, (int)(pOp - aOp), pOp->p1); sqlite3VdbeDeleteAuxData(p, (int)(pOp - aOp), pOp->p1);
} }
/* Copy the result of the function into register P3 */ /* Copy the result of the function into register P3 */
sqlite3VdbeChangeEncoding(ctx.pOut, encoding); sqlite3VdbeChangeEncoding(pCtx->pOut, encoding);
if( sqlite3VdbeMemTooBig(ctx.pOut) ){ if( sqlite3VdbeMemTooBig(pCtx->pOut) ){
goto too_big; goto too_big;
} }
REGISTER_TRACE(pOp->p3, ctx.pOut); REGISTER_TRACE(pOp->p3, pCtx->pOut);
UPDATE_MAX_BLOBSIZE(ctx.pOut); UPDATE_MAX_BLOBSIZE(pCtx->pOut);
break; break;
} }
@@ -5708,46 +5748,73 @@ case OP_JumpZeroIncr: { /* jump, in1 */
** The P5 arguments are taken from register P2 and its ** The P5 arguments are taken from register P2 and its
** successors. ** successors.
*/ */
case OP_AggStep: { case OP_AggStep0: {
int n; int n;
int i; sqlite3_context *pCtx;
Mem *pMem;
Mem *pRec;
Mem t;
sqlite3_context ctx;
sqlite3_value **apVal;
assert( pOp->p4type==P4_FUNCDEF );
n = pOp->p5; n = pOp->p5;
assert( n>=0 );
pRec = &aMem[pOp->p2];
apVal = p->apArg;
assert( apVal || n==0 );
for(i=0; i<n; i++, pRec++){
assert( memIsValid(pRec) );
apVal[i] = pRec;
memAboutToChange(p, pRec);
}
ctx.pFunc = pOp->p4.pFunc;
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
ctx.pMem = pMem = &aMem[pOp->p3]; assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pCtx = sqlite3DbMallocRaw(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
if( pCtx==0 ) goto no_mem;
pCtx->pMem = 0;
pCtx->pFunc = pOp->p4.pFunc;
pCtx->iOp = (int)(pOp - aOp);
pCtx->pVdbe = p;
pCtx->argc = n;
pOp->p4type = P4_FUNCCTX;
pOp->p4.pCtx = pCtx;
pOp->opcode = OP_AggStep;
/* Fall through into OP_AggStep */
}
case OP_AggStep: {
int i;
sqlite3_context *pCtx;
Mem *pMem;
Mem t;
assert( pOp->p4type==P4_FUNCCTX );
pCtx = pOp->p4.pCtx;
pMem = &aMem[pOp->p3];
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
** reinitializes the relavant parts of the sqlite3_context object */
if( pCtx->pMem != pMem ){
pCtx->pMem = pMem;
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
}
#ifdef SQLITE_DEBUG
for(i=0; i<pCtx->argc; i++){
assert( memIsValid(pCtx->argv[i]) );
REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
}
#endif
pMem->n++; pMem->n++;
sqlite3VdbeMemInit(&t, db, MEM_Null); sqlite3VdbeMemInit(&t, db, MEM_Null);
ctx.pOut = &t; pCtx->pOut = &t;
ctx.isError = 0; pCtx->fErrorOrAux = 0;
ctx.pVdbe = p; pCtx->skipFlag = 0;
ctx.iOp = (int)(pOp - aOp); (pCtx->pFunc->xStep)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
ctx.skipFlag = 0; if( pCtx->fErrorOrAux ){
(ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */ if( pCtx->isError ){
if( ctx.isError ){
sqlite3VdbeError(p, "%s", sqlite3_value_text(&t)); sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
rc = ctx.isError; rc = pCtx->isError;
} }
if( ctx.skipFlag ){ sqlite3VdbeMemRelease(&t);
}else{
assert( t.flags==MEM_Null );
}
if( pCtx->skipFlag ){
assert( pOp[-1].opcode==OP_CollSeq ); assert( pOp[-1].opcode==OP_CollSeq );
i = pOp[-1].p1; i = pOp[-1].p1;
if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1); if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1);
} }
sqlite3VdbeMemRelease(&t);
break; break;
} }

View File

@@ -46,13 +46,14 @@ struct VdbeOp {
int p1; /* First operand */ int p1; /* First operand */
int p2; /* Second parameter (often the jump destination) */ int p2; /* Second parameter (often the jump destination) */
int p3; /* The third parameter */ int p3; /* The third parameter */
union { /* fourth parameter */ union p4union { /* fourth parameter */
int i; /* Integer value if p4type==P4_INT32 */ int i; /* Integer value if p4type==P4_INT32 */
void *p; /* Generic pointer */ void *p; /* Generic pointer */
char *z; /* Pointer to data for string (char array) types */ char *z; /* Pointer to data for string (char array) types */
i64 *pI64; /* Used when p4type is P4_INT64 */ i64 *pI64; /* Used when p4type is P4_INT64 */
double *pReal; /* Used when p4type is P4_REAL */ double *pReal; /* Used when p4type is P4_REAL */
FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */
sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */
CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
Mem *pMem; /* Used when p4type is P4_MEM */ Mem *pMem; /* Used when p4type is P4_MEM */
VTable *pVtab; /* Used when p4type is P4_VTAB */ VTable *pVtab; /* Used when p4type is P4_VTAB */
@@ -119,6 +120,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */
#define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ #define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
#define P4_FUNCCTX (-20) /* P4 is a pointer to an sqlite3_context object */
/* Error message codes for OP_Halt */ /* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1 #define P5_ConstraintNotNull 1

View File

@@ -287,6 +287,8 @@ struct sqlite3_context {
int isError; /* Error code returned by the function. */ int isError; /* Error code returned by the function. */
u8 skipFlag; /* Skip accumulator loading if true */ u8 skipFlag; /* Skip accumulator loading if true */
u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */ u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
u8 argc; /* Number of arguments */
sqlite3_value *argv[1]; /* Argument set */
}; };
/* /*

View File

@@ -489,11 +489,6 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
/* NOTE: Be sure to update mkopcodeh.awk when adding or removing /* NOTE: Be sure to update mkopcodeh.awk when adding or removing
** cases from this switch! */ ** cases from this switch! */
switch( opcode ){ switch( opcode ){
case OP_Function:
case OP_AggStep: {
if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
break;
}
case OP_Transaction: { case OP_Transaction: {
if( pOp->p2!=0 ) p->readOnly = 0; if( pOp->p2!=0 ) p->readOnly = 0;
/* fall thru */ /* fall thru */
@@ -737,6 +732,10 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
if( p4 ){ if( p4 ){
assert( db ); assert( db );
switch( p4type ){ switch( p4type ){
case P4_FUNCCTX: {
freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc);
/* Fall through into the next case */
}
case P4_REAL: case P4_REAL:
case P4_INT64: case P4_INT64:
case P4_DYNAMIC: case P4_DYNAMIC:
@@ -1121,6 +1120,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg); sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
break; break;
} }
case P4_FUNCCTX: {
FuncDef *pDef = pOp->p4.pCtx->pFunc;
sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
case P4_INT64: { case P4_INT64: {
sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64); sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64);
break; break;