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:
30
manifest
30
manifest
@@ -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
|
||||||
|
@@ -1 +1 @@
|
|||||||
7097716caed9d4aef49c7e766e41ea74abf5967f
|
2abc44eb3b9d489321baa50bc25e17dafbda3687
|
@@ -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" \
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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 ){
|
||||||
|
@@ -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);
|
||||||
|
201
src/vdbe.c
201
src/vdbe.c
@@ -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 = pCtx->isError;
|
||||||
rc = ctx.isError;
|
}
|
||||||
|
sqlite3VdbeMemRelease(&t);
|
||||||
|
}else{
|
||||||
|
assert( t.flags==MEM_Null );
|
||||||
}
|
}
|
||||||
if( ctx.skipFlag ){
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -279,14 +279,16 @@ struct AuxData {
|
|||||||
** (Mem) which are only defined there.
|
** (Mem) which are only defined there.
|
||||||
*/
|
*/
|
||||||
struct sqlite3_context {
|
struct sqlite3_context {
|
||||||
Mem *pOut; /* The return value is stored here */
|
Mem *pOut; /* The return value is stored here */
|
||||||
FuncDef *pFunc; /* Pointer to function information */
|
FuncDef *pFunc; /* Pointer to function information */
|
||||||
Mem *pMem; /* Memory cell used to store aggregate context */
|
Mem *pMem; /* Memory cell used to store aggregate context */
|
||||||
Vdbe *pVdbe; /* The VM that owns this context */
|
Vdbe *pVdbe; /* The VM that owns this context */
|
||||||
int iOp; /* Instruction number of OP_Function */
|
int iOp; /* Instruction number of OP_Function */
|
||||||
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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user