mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-08 03:22:21 +03:00
Continuing work toward converting the VM to a register machine. (CVS 4708)
FossilOrigin-Name: 426f31ecdd05d1179a2e49c2ca1666011cede9c6
This commit is contained in:
24
manifest
24
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Continuing\swork\stoward\sconverting\sthe\sVM\sinto\sa\sregister\smachine.\s(CVS\s4707)
|
C Continuing\swork\stoward\sconverting\sthe\sVM\sto\sa\sregister\smachine.\s(CVS\s4708)
|
||||||
D 2008-01-12T12:48:08
|
D 2008-01-12T19:03:49
|
||||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||||
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -80,7 +80,7 @@ F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4
|
|||||||
F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc
|
F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc
|
||||||
F src/alter.c 5a54f58d9481ac14c4e58b702f3f8758dee84d04
|
F src/alter.c 5a54f58d9481ac14c4e58b702f3f8758dee84d04
|
||||||
F src/analyze.c 5aa93f191b365ea308795f62ca6f2e8caa9de3e1
|
F src/analyze.c 5aa93f191b365ea308795f62ca6f2e8caa9de3e1
|
||||||
F src/attach.c 61f0cae7b1a0e7c3b5f5286be5dc1a7c4d7112d2
|
F src/attach.c 71f5c886004a9740fc6e6033d4e1ce0517ab6574
|
||||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||||
F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff
|
F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff
|
||||||
F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef
|
F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef
|
||||||
@@ -92,7 +92,7 @@ F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
|||||||
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
||||||
F src/delete.c 00e536847b8eedc5d35f89f7f38a8a7c1d2a22f9
|
F src/delete.c 00e536847b8eedc5d35f89f7f38a8a7c1d2a22f9
|
||||||
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
||||||
F src/expr.c 68bcc07517c763cc7601be45d60084bc11ee0212
|
F src/expr.c 14130c27fba6fa3c14dcfc4891c534a8ee71cc3c
|
||||||
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
||||||
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
||||||
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
||||||
@@ -131,12 +131,12 @@ F src/pragma.c 1d3d9deefcf325e14a99b94f9f506f1a90a9232b
|
|||||||
F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd
|
F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd
|
||||||
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
||||||
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
||||||
F src/select.c 9e3c65ca3d2508b585b6786dbcbe6cd65560b013
|
F src/select.c fc9cebb2033a84b31472405114ad36d73c30b967
|
||||||
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||||
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
||||||
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
||||||
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
||||||
F src/sqliteInt.h b143c53760aeb4feeb4eaf8cb10eb26ad5b6c89e
|
F src/sqliteInt.h c3f43826e48b0d2928b9e6fa3aca887317285392
|
||||||
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
||||||
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
||||||
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
||||||
@@ -168,7 +168,7 @@ F src/update.c aad823f97a930e6982264299863837d4c6107d3b
|
|||||||
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
||||||
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
||||||
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
||||||
F src/vdbe.c 20bd088657280d75b630d299c59cdb3c6a5c9b9e
|
F src/vdbe.c a05947fba057311149cb0635cccdee9bed42f3cb
|
||||||
F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e
|
F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e
|
||||||
F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346
|
F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346
|
||||||
F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
|
F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
|
||||||
@@ -177,7 +177,7 @@ F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120
|
|||||||
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
||||||
F src/vdbemem.c a86119b5ccc41ab8653e4746f83d591ff0ae892e
|
F src/vdbemem.c a86119b5ccc41ab8653e4746f83d591ff0ae892e
|
||||||
F src/vtab.c 7f206d148f6e76f427f008f589610c72a4b9336c
|
F src/vtab.c 7f206d148f6e76f427f008f589610c72a4b9336c
|
||||||
F src/where.c 9705df3c2b78ea8e02a768be8ac5d3f7a2902f1e
|
F src/where.c 27e40d32b7b47e70db9ac61b91a3a46c8dc6b47d
|
||||||
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/all.test ee350b9ab15b175fc0a8fb51bf2141ed3a3b9cba
|
F test/all.test ee350b9ab15b175fc0a8fb51bf2141ed3a3b9cba
|
||||||
@@ -314,7 +314,7 @@ F test/fts3ao.test 0aa29dd4fc1c8d46b1f7cfe5926f7ac97551bea9
|
|||||||
F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa
|
F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa
|
||||||
F test/fts3b.test b3a25180a633873d37d86e1ccd00ed690d37237a
|
F test/fts3b.test b3a25180a633873d37d86e1ccd00ed690d37237a
|
||||||
F test/fts3near.test 2d4dadcaac5025ab65bb87e66c45f39e92966194
|
F test/fts3near.test 2d4dadcaac5025ab65bb87e66c45f39e92966194
|
||||||
F test/func.test 4d54202f6a1c8498444d9efe460851b02a1e8e4f
|
F test/func.test 307b335a47a555bc1e5df94d7f4d6172df25f944
|
||||||
F test/fuzz.test 62fc19dd36a427777fd671b569df07166548628a
|
F test/fuzz.test 62fc19dd36a427777fd671b569df07166548628a
|
||||||
F test/fuzz2.test ea38692ce2da99ad79fe0be5eb1a452c1c4d37bb
|
F test/fuzz2.test ea38692ce2da99ad79fe0be5eb1a452c1c4d37bb
|
||||||
F test/fuzz_common.tcl ff4bc2dfc465f6878f8e2d819620914365382731
|
F test/fuzz_common.tcl ff4bc2dfc465f6878f8e2d819620914365382731
|
||||||
@@ -606,7 +606,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 4744257d3cd2dd96485fde6d9f60542714383421
|
P a6dddebcc5ccbbf3009c9d06163a8b59036331de
|
||||||
R 9fded3f0e818ece501c0ececcbd26a94
|
R 537e4808d9b23703b914b666ccd36884
|
||||||
U drh
|
U drh
|
||||||
Z fe475f28d0df336b5a859493e9293538
|
Z 1569ded7274b37b8c39c0600e4142054
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
a6dddebcc5ccbbf3009c9d06163a8b59036331de
|
426f31ecdd05d1179a2e49c2ca1666011cede9c6
|
||||||
12
src/attach.c
12
src/attach.c
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code used to implement the ATTACH and DETACH commands.
|
** This file contains code used to implement the ATTACH and DETACH commands.
|
||||||
**
|
**
|
||||||
** $Id: attach.c,v 1.67 2008/01/09 23:04:12 drh Exp $
|
** $Id: attach.c,v 1.68 2008/01/12 19:03:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -297,6 +297,7 @@ static void codeAttach(
|
|||||||
Vdbe *v;
|
Vdbe *v;
|
||||||
FuncDef *pFunc;
|
FuncDef *pFunc;
|
||||||
sqlite3* db = pParse->db;
|
sqlite3* db = pParse->db;
|
||||||
|
int regArgs;
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||||
assert( db->mallocFailed || pAuthArg );
|
assert( db->mallocFailed || pAuthArg );
|
||||||
@@ -326,13 +327,14 @@ static void codeAttach(
|
|||||||
}
|
}
|
||||||
|
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
sqlite3ExprCode(pParse, pFilename, 0);
|
regArgs = sqlite3GetTempRange(pParse, nFunc);
|
||||||
sqlite3ExprCode(pParse, pDbname, 0);
|
sqlite3ExprCode(pParse, pFilename, regArgs);
|
||||||
sqlite3ExprCode(pParse, pKey, 0);
|
sqlite3ExprCode(pParse, pDbname, regArgs+1);
|
||||||
|
sqlite3ExprCode(pParse, pKey, regArgs+2);
|
||||||
|
|
||||||
assert( v || db->mallocFailed );
|
assert( v || db->mallocFailed );
|
||||||
if( v ){
|
if( v ){
|
||||||
sqlite3VdbeAddOp0(v, OP_Function);
|
sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-nFunc, regArgs);
|
||||||
sqlite3VdbeChangeP5(v, nFunc);
|
sqlite3VdbeChangeP5(v, nFunc);
|
||||||
pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
|
pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
|
||||||
sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
|
sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
|
||||||
|
|||||||
433
src/expr.c
433
src/expr.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** for generating VDBE code that evaluates expressions in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.343 2008/01/12 12:48:08 drh Exp $
|
** $Id: expr.c,v 1.344 2008/01/12 19:03:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -1930,30 +1930,26 @@ void sqlite3ExprCodeGetColumn(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code into the current Vdbe to evaluate the given
|
** Generate code into the current Vdbe to evaluate the given
|
||||||
** expression and leaves the result in a register on on the stack.
|
** expression. Attempt to store the results in register "target".
|
||||||
|
** Return the register where results are stored.
|
||||||
**
|
**
|
||||||
** If the target register number is negative, allocate a new
|
** With this routine, there is no guaranteed that results will
|
||||||
** register to store the result. If the target register number
|
** be stored in target. The result might be stored in some other
|
||||||
** is zero then push the result onto the stack. Return the target
|
** register if it is convenient to do so. The calling function
|
||||||
** register number regardless.
|
** must check the return code and move the results to the desired
|
||||||
**
|
** register.
|
||||||
** This code depends on the fact that certain token values (ex: TK_EQ)
|
|
||||||
** are the same as opcode values (ex: OP_Eq) that implement the corresponding
|
|
||||||
** operation. Special comments in vdbe.c and the mkopcodeh.awk script in
|
|
||||||
** the make process cause these values to align. Assert()s in the code
|
|
||||||
** below verify that the numbers are aligned correctly.
|
|
||||||
*/
|
*/
|
||||||
int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe; /* The VM under construction */
|
||||||
int op;
|
int op; /* The opcode being coded */
|
||||||
int inReg = 0;
|
int inReg = target; /* Results stored in register inReg */
|
||||||
int origTarget = target;
|
int regFree1 = 0; /* If non-zero free this temporary register */
|
||||||
|
int regFree2 = 0; /* If non-zero free this temporary register */
|
||||||
|
int r1, r2, r3; /* Various register numbers */
|
||||||
|
|
||||||
assert( v!=0 || pParse->db->mallocFailed );
|
assert( v!=0 || pParse->db->mallocFailed );
|
||||||
|
assert( target>=0 );
|
||||||
if( v==0 ) return 0;
|
if( v==0 ) return 0;
|
||||||
if( target<0 ){
|
|
||||||
target = ++pParse->nMem;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pExpr==0 ){
|
if( pExpr==0 ){
|
||||||
op = TK_NULL;
|
op = TK_NULL;
|
||||||
@@ -1971,7 +1967,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
}else if( pAggInfo->useSortingIdx ){
|
}else if( pAggInfo->useSortingIdx ){
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdx,
|
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdx,
|
||||||
pCol->iSorterColumn, target);
|
pCol->iSorterColumn, target);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Otherwise, fall thru into the TK_COLUMN case */
|
/* Otherwise, fall thru into the TK_COLUMN case */
|
||||||
@@ -1984,30 +1979,25 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
}else{
|
}else{
|
||||||
sqlite3ExprCodeGetColumn(v, pExpr->pTab,
|
sqlite3ExprCodeGetColumn(v, pExpr->pTab,
|
||||||
pExpr->iColumn, pExpr->iTable, target);
|
pExpr->iColumn, pExpr->iTable, target);
|
||||||
inReg = target;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_INTEGER: {
|
case TK_INTEGER: {
|
||||||
codeInteger(v, (char*)pExpr->token.z, pExpr->token.n, 0, target);
|
codeInteger(v, (char*)pExpr->token.z, pExpr->token.n, 0, target);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_FLOAT: {
|
case TK_FLOAT: {
|
||||||
codeReal(v, (char*)pExpr->token.z, pExpr->token.n, 0, target);
|
codeReal(v, (char*)pExpr->token.z, pExpr->token.n, 0, target);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_STRING: {
|
case TK_STRING: {
|
||||||
sqlite3DequoteExpr(pParse->db, pExpr);
|
sqlite3DequoteExpr(pParse->db, pExpr);
|
||||||
sqlite3VdbeAddOp4(v,OP_String8, 0, target, 0,
|
sqlite3VdbeAddOp4(v,OP_String8, 0, target, 0,
|
||||||
(char*)pExpr->token.z, pExpr->token.n);
|
(char*)pExpr->token.z, pExpr->token.n);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_NULL: {
|
case TK_NULL: {
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||||
@@ -2022,7 +2012,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
z = "";
|
z = "";
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp4(v, op, 0, target, 0, z, n);
|
sqlite3VdbeAddOp4(v, op, 0, target, 0, z, n);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2031,7 +2020,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
if( pExpr->token.n>1 ){
|
if( pExpr->token.n>1 ){
|
||||||
sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);
|
sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);
|
||||||
}
|
}
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_REGISTER: {
|
case TK_REGISTER: {
|
||||||
@@ -2042,7 +2030,7 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
case TK_CAST: {
|
case TK_CAST: {
|
||||||
/* Expressions of the form: CAST(pLeft AS token) */
|
/* Expressions of the form: CAST(pLeft AS token) */
|
||||||
int aff, to_op;
|
int aff, to_op;
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, target);
|
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||||
aff = sqlite3AffinityType(&pExpr->token);
|
aff = sqlite3AffinityType(&pExpr->token);
|
||||||
to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
|
to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
|
||||||
assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
|
assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
|
||||||
@@ -2050,8 +2038,7 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
|
assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
|
||||||
assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
|
assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
|
||||||
assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL );
|
assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL );
|
||||||
sqlite3VdbeAddOp1(v, to_op, target);
|
sqlite3VdbeAddOp1(v, to_op, inReg);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_CAST */
|
#endif /* SQLITE_OMIT_CAST */
|
||||||
@@ -2061,20 +2048,17 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
case TK_GE:
|
case TK_GE:
|
||||||
case TK_NE:
|
case TK_NE:
|
||||||
case TK_EQ: {
|
case TK_EQ: {
|
||||||
int r1, r2;
|
|
||||||
assert( TK_LT==OP_Lt );
|
assert( TK_LT==OP_Lt );
|
||||||
assert( TK_LE==OP_Le );
|
assert( TK_LE==OP_Le );
|
||||||
assert( TK_GT==OP_Gt );
|
assert( TK_GT==OP_Gt );
|
||||||
assert( TK_GE==OP_Ge );
|
assert( TK_GE==OP_Ge );
|
||||||
assert( TK_EQ==OP_Eq );
|
assert( TK_EQ==OP_Eq );
|
||||||
assert( TK_NE==OP_Ne );
|
assert( TK_NE==OP_Ne );
|
||||||
if( target>0 ){
|
if( target==0 ){
|
||||||
inReg = target;
|
|
||||||
}else{
|
|
||||||
inReg = ++pParse->nMem;
|
inReg = ++pParse->nMem;
|
||||||
}
|
}
|
||||||
r1 = sqlite3ExprCode(pParse, pExpr->pLeft, -1);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||||
r2 = sqlite3ExprCode(pParse, pExpr->pRight, -1);
|
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||||
r1, r2, inReg, SQLITE_STOREP2);
|
r1, r2, inReg, SQLITE_STOREP2);
|
||||||
break;
|
break;
|
||||||
@@ -2091,7 +2075,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
case TK_LSHIFT:
|
case TK_LSHIFT:
|
||||||
case TK_RSHIFT:
|
case TK_RSHIFT:
|
||||||
case TK_CONCAT: {
|
case TK_CONCAT: {
|
||||||
int r1, r2;
|
|
||||||
assert( TK_AND==OP_And );
|
assert( TK_AND==OP_And );
|
||||||
assert( TK_OR==OP_Or );
|
assert( TK_OR==OP_Or );
|
||||||
assert( TK_PLUS==OP_Add );
|
assert( TK_PLUS==OP_Add );
|
||||||
@@ -2103,10 +2086,9 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
assert( TK_LSHIFT==OP_ShiftLeft );
|
assert( TK_LSHIFT==OP_ShiftLeft );
|
||||||
assert( TK_RSHIFT==OP_ShiftRight );
|
assert( TK_RSHIFT==OP_ShiftRight );
|
||||||
assert( TK_CONCAT==OP_Concat );
|
assert( TK_CONCAT==OP_Concat );
|
||||||
r1 = sqlite3ExprCode(pParse, pExpr->pLeft, -1);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||||
r2 = sqlite3ExprCode(pParse, pExpr->pRight, -1);
|
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||||
sqlite3VdbeAddOp3(v, op, r2, r1, target);
|
sqlite3VdbeAddOp3(v, op, r2, r1, target);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_UMINUS: {
|
case TK_UMINUS: {
|
||||||
@@ -2120,10 +2102,10 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
codeInteger(v, (char*)p->z, p->n, 1, target);
|
codeInteger(v, (char*)p->z, p->n, 1, target);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
int r1 = ++pParse->nMem;
|
regFree1 = r1 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, r1);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, r1);
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, target);
|
r2 = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||||
sqlite3VdbeAddOp3(v, OP_Subtract, target, r1, target);
|
sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
|
||||||
}
|
}
|
||||||
inReg = target;
|
inReg = target;
|
||||||
break;
|
break;
|
||||||
@@ -2132,8 +2114,8 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
case TK_NOT: {
|
case TK_NOT: {
|
||||||
assert( TK_BITNOT==OP_BitNot );
|
assert( TK_BITNOT==OP_BitNot );
|
||||||
assert( TK_NOT==OP_Not );
|
assert( TK_NOT==OP_Not );
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, 0);
|
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||||
sqlite3VdbeAddOp0(v, op);
|
sqlite3VdbeAddOp1(v, op, inReg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_ISNULL:
|
case TK_ISNULL:
|
||||||
@@ -2142,11 +2124,10 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
assert( TK_ISNULL==OP_IsNull );
|
assert( TK_ISNULL==OP_IsNull );
|
||||||
assert( TK_NOTNULL==OP_NotNull );
|
assert( TK_NOTNULL==OP_NotNull );
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, 0);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||||
addr = sqlite3VdbeAddOp0(v, op);
|
addr = sqlite3VdbeAddOp1(v, op, r1);
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
|
||||||
sqlite3VdbeJumpHere(v, addr);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_AGG_FUNCTION: {
|
case TK_AGG_FUNCTION: {
|
||||||
@@ -2178,7 +2159,8 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
assert( pDef!=0 );
|
assert( pDef!=0 );
|
||||||
if( pList ){
|
if( pList ){
|
||||||
nExpr = pList->nExpr;
|
nExpr = pList->nExpr;
|
||||||
sqlite3ExprCodeExprList(pParse, pList, 0);
|
r1 = sqlite3GetTempRange(pParse, nExpr);
|
||||||
|
sqlite3ExprCodeExprList(pParse, pList, r1);
|
||||||
}else{
|
}else{
|
||||||
nExpr = 0;
|
nExpr = 0;
|
||||||
}
|
}
|
||||||
@@ -2213,9 +2195,12 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
if( !pColl ) pColl = pParse->db->pDfltColl;
|
if( !pColl ) pColl = pParse->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, 0, 0,
|
sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target,
|
||||||
(char*)pDef, P4_FUNCDEF);
|
(char*)pDef, P4_FUNCDEF);
|
||||||
sqlite3VdbeChangeP5(v, nExpr);
|
sqlite3VdbeChangeP5(v, nExpr);
|
||||||
|
if( nExpr ){
|
||||||
|
sqlite3ReleaseTempRange(pParse, r1, nExpr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_SUBQUERY
|
#ifndef SQLITE_OMIT_SUBQUERY
|
||||||
@@ -2231,7 +2216,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
int j1, j2, j3, j4, j5;
|
int j1, j2, j3, j4, j5;
|
||||||
char affinity;
|
char affinity;
|
||||||
int eType;
|
int eType;
|
||||||
int r1, r2, r3;
|
|
||||||
|
|
||||||
eType = sqlite3FindInIndex(pParse, pExpr, 0);
|
eType = sqlite3FindInIndex(pParse, pExpr, 0);
|
||||||
|
|
||||||
@@ -2241,75 +2225,106 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
*/
|
*/
|
||||||
affinity = comparisonAffinity(pExpr);
|
affinity = comparisonAffinity(pExpr);
|
||||||
|
|
||||||
if( target ){
|
if( target==0 ){
|
||||||
r1 = target;
|
target = inReg = ++pParse->nMem;
|
||||||
}else{
|
|
||||||
r1 = sqlite3GetTempReg(pParse);
|
|
||||||
}
|
}
|
||||||
inReg = r1;
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, r1);
|
|
||||||
|
|
||||||
/* Code the <expr> from "<expr> IN (...)". The temporary table
|
/* Code the <expr> from "<expr> IN (...)". The temporary table
|
||||||
** pExpr->iTable contains the values that make up the (...) set.
|
** pExpr->iTable contains the values that make up the (...) set.
|
||||||
*/
|
*/
|
||||||
r2 = sqlite3ExprCode(pParse, pExpr->pLeft, -1);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r2);
|
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1);
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, r1);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||||
j2 = sqlite3VdbeAddOp0(v, OP_Goto);
|
j2 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
sqlite3VdbeJumpHere(v, j1);
|
sqlite3VdbeJumpHere(v, j1);
|
||||||
if( eType==IN_INDEX_ROWID ){
|
if( eType==IN_INDEX_ROWID ){
|
||||||
j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r2, 0, 1);
|
j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, 0, 1);
|
||||||
j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r2);
|
j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r1);
|
||||||
j5 = sqlite3VdbeAddOp0(v, OP_Goto);
|
j5 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
sqlite3VdbeJumpHere(v, j3);
|
sqlite3VdbeJumpHere(v, j3);
|
||||||
sqlite3VdbeJumpHere(v, j4);
|
sqlite3VdbeJumpHere(v, j4);
|
||||||
}else{
|
}else{
|
||||||
r3 = sqlite3GetTempReg(pParse);
|
r2 = regFree2 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp4(v, OP_RegMakeRec, r2, 1, r3, &affinity, 1);
|
sqlite3VdbeAddOp4(v, OP_RegMakeRec, r1, 1, r2, &affinity, 1);
|
||||||
j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r3);
|
j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r2);
|
||||||
sqlite3ReleaseTempReg(pParse, r3);
|
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, r1, -1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
|
||||||
sqlite3VdbeJumpHere(v, j2);
|
sqlite3VdbeJumpHere(v, j2);
|
||||||
sqlite3VdbeJumpHere(v, j5);
|
sqlite3VdbeJumpHere(v, j5);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
|
** x BETWEEN y AND z
|
||||||
|
**
|
||||||
|
** This is equivalent to
|
||||||
|
**
|
||||||
|
** x>=y AND x<=z
|
||||||
|
**
|
||||||
|
** X is stored in pExpr->pLeft.
|
||||||
|
** Y is stored in pExpr->pList->a[0].pExpr.
|
||||||
|
** Z is stored in pExpr->pList->a[1].pExpr.
|
||||||
|
*/
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
Expr *pLeft = pExpr->pLeft;
|
Expr *pLeft = pExpr->pLeft;
|
||||||
struct ExprList_item *pLItem = pExpr->pList->a;
|
struct ExprList_item *pLItem = pExpr->pList->a;
|
||||||
Expr *pRight = pLItem->pExpr;
|
Expr *pRight = pLItem->pExpr;
|
||||||
int r1, r2, r3, r4, r5;
|
|
||||||
|
|
||||||
if( target>0 ){
|
if( target==0 ){
|
||||||
inReg = target;
|
inReg = target = ++pParse->nMem;
|
||||||
}else{
|
|
||||||
inReg = ++pParse->nMem;
|
|
||||||
}
|
}
|
||||||
r1 = sqlite3ExprCode(pParse, pLeft, -1);
|
r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1);
|
||||||
r2 = sqlite3ExprCode(pParse, pRight, -1);
|
r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2);
|
||||||
r3 = ++pParse->nMem;
|
r3 = sqlite3GetTempReg(pParse);
|
||||||
codeCompare(pParse, pLeft, pRight, OP_Ge,
|
codeCompare(pParse, pLeft, pRight, OP_Ge,
|
||||||
r1, r2, r3, SQLITE_STOREP2);
|
r1, r2, r3, SQLITE_STOREP2);
|
||||||
pLItem++;
|
pLItem++;
|
||||||
pRight = pLItem->pExpr;
|
pRight = pLItem->pExpr;
|
||||||
r4 = sqlite3ExprCode(pParse, pRight, -1);
|
sqlite3ReleaseTempReg(pParse, regFree2);
|
||||||
r5 = ++pParse->nMem;
|
r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2);
|
||||||
codeCompare(pParse, pLeft, pRight, OP_Le, r1, r4, r5, SQLITE_STOREP2);
|
codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r2, SQLITE_STOREP2);
|
||||||
sqlite3VdbeAddOp3(v, OP_And, r3, r5, inReg);
|
sqlite3VdbeAddOp3(v, OP_And, r3, r2, target);
|
||||||
|
sqlite3ReleaseTempReg(pParse, r3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_UPLUS: {
|
case TK_UPLUS: {
|
||||||
inReg = sqlite3ExprCode(pParse, pExpr->pLeft, origTarget);
|
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Form A:
|
||||||
|
** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END
|
||||||
|
**
|
||||||
|
** Form B:
|
||||||
|
** CASE WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END
|
||||||
|
**
|
||||||
|
** Form A is can be transformed into the equivalent form B as follows:
|
||||||
|
** CASE WHEN x=e1 THEN r1 WHEN x=e2 THEN r2 ...
|
||||||
|
** WHEN x=eN THEN rN ELSE y END
|
||||||
|
**
|
||||||
|
** X (if it exists) is in pExpr->pLeft.
|
||||||
|
** Y is in pExpr->pRight. The Y is also optional. If there is no
|
||||||
|
** ELSE clause and no other term matches, then the result of the
|
||||||
|
** exprssion is NULL.
|
||||||
|
** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1].
|
||||||
|
**
|
||||||
|
** The result of the expression is the Ri for the first matching Ei,
|
||||||
|
** or if there is no matching Ei, the ELSE term Y, or if there is
|
||||||
|
** no ELSE term, NULL.
|
||||||
|
*/
|
||||||
case TK_CASE: {
|
case TK_CASE: {
|
||||||
int expr_end_label;
|
int endLabel; /* GOTO label for end of CASE stmt */
|
||||||
int jumpInst;
|
int nextCase; /* GOTO label for next WHEN clause */
|
||||||
int nExpr;
|
int nExpr; /* 2x number of WHEN terms */
|
||||||
int i;
|
int i; /* Loop counter */
|
||||||
ExprList *pEList;
|
ExprList *pEList; /* List of WHEN terms */
|
||||||
struct ExprList_item *aListelem;
|
struct ExprList_item *aListelem; /* Array of WHEN terms */
|
||||||
|
Expr opCompare; /* The X==Ei expression */
|
||||||
|
Expr cacheX; /* Cached expression X */
|
||||||
|
Expr *pX; /* The X expression */
|
||||||
|
Expr *pTest; /* X==Ei (form A) or just Ei (form B) */
|
||||||
|
|
||||||
assert(pExpr->pList);
|
assert(pExpr->pList);
|
||||||
assert((pExpr->pList->nExpr % 2) == 0);
|
assert((pExpr->pList->nExpr % 2) == 0);
|
||||||
@@ -2317,34 +2332,33 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
pEList = pExpr->pList;
|
pEList = pExpr->pList;
|
||||||
aListelem = pEList->a;
|
aListelem = pEList->a;
|
||||||
nExpr = pEList->nExpr;
|
nExpr = pEList->nExpr;
|
||||||
expr_end_label = sqlite3VdbeMakeLabel(v);
|
endLabel = sqlite3VdbeMakeLabel(v);
|
||||||
if( pExpr->pLeft ){
|
if( (pX = pExpr->pLeft)!=0 ){
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, 0);
|
cacheX = *pX;
|
||||||
|
cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, ®Free1);
|
||||||
|
cacheX.op = TK_REGISTER;
|
||||||
|
opCompare.op = TK_EQ;
|
||||||
|
opCompare.pLeft = &cacheX;
|
||||||
|
pTest = &opCompare;
|
||||||
}
|
}
|
||||||
for(i=0; i<nExpr; i=i+2){
|
for(i=0; i<nExpr; i=i+2){
|
||||||
sqlite3ExprCode(pParse, aListelem[i].pExpr, 0);
|
if( pX ){
|
||||||
if( pExpr->pLeft ){
|
opCompare.pRight = aListelem[i].pExpr;
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, -1);
|
|
||||||
jumpInst = codeCompare(pParse, pExpr->pLeft, aListelem[i].pExpr,
|
|
||||||
OP_Ne, 0, 0, 0, SQLITE_JUMPIFNULL);
|
|
||||||
sqlite3VdbeAddOp1(v, OP_Pop, 1);
|
|
||||||
}else{
|
}else{
|
||||||
jumpInst = sqlite3VdbeAddOp3(v, OP_IfNot, 0, 0, 1);
|
pTest = aListelem[i].pExpr;
|
||||||
}
|
}
|
||||||
|
nextCase = sqlite3VdbeMakeLabel(v);
|
||||||
|
sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
|
||||||
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
|
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, expr_end_label);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
|
||||||
sqlite3VdbeJumpHere(v, jumpInst);
|
sqlite3VdbeResolveLabel(v, nextCase);
|
||||||
}
|
|
||||||
if( pExpr->pLeft ){
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
|
|
||||||
}
|
}
|
||||||
if( pExpr->pRight ){
|
if( pExpr->pRight ){
|
||||||
sqlite3ExprCode(pParse, pExpr->pRight, target);
|
sqlite3ExprCode(pParse, pExpr->pRight, target);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||||
}
|
}
|
||||||
sqlite3VdbeResolveLabel(v, expr_end_label);
|
sqlite3VdbeResolveLabel(v, endLabel);
|
||||||
inReg = target;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
@@ -2371,44 +2385,78 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if( inReg!=target ){
|
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||||
if( origTarget!=-1 ){
|
sqlite3ReleaseTempReg(pParse, regFree2);
|
||||||
sqlite3VdbeAddOp2(v, (inReg>0 ? OP_SCopy : OP_Move), inReg, target);
|
return inReg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Generate code to evaluate an expression and store the results
|
||||||
|
** into a register. Return the register number where the results
|
||||||
|
** are stored.
|
||||||
|
**
|
||||||
|
** If the register is a temporary register that can be deallocated,
|
||||||
|
** then write its number into *pReg. If the result register is no
|
||||||
|
** a temporary, then set *pReg to zero.
|
||||||
|
*/
|
||||||
|
int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
||||||
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
|
int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
|
||||||
|
if( r2==r1 ){
|
||||||
|
*pReg = r1;
|
||||||
}else{
|
}else{
|
||||||
target = inReg;
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
|
*pReg = 0;
|
||||||
}
|
}
|
||||||
|
return r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Generate code that will evaluate expression pExpr and store the
|
||||||
|
** results in register target. The results are guaranteed to appear
|
||||||
|
** in register target.
|
||||||
|
*/
|
||||||
|
int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||||
|
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||||
|
if( inReg!=target ){
|
||||||
|
sqlite3VdbeAddOp2(pParse->pVdbe, (inReg>0 ? OP_SCopy : OP_Move),
|
||||||
|
inReg, target);
|
||||||
}
|
}
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
|
||||||
/*
|
/*
|
||||||
** Generate code that evalutes the given expression and leaves the result
|
** Generate code that evalutes the given expression and puts the result
|
||||||
** on the stack. See also sqlite3ExprCode().
|
** in register target. If target==-1, then allocate a temporary register
|
||||||
|
** in which to store the result. In either case, return the register
|
||||||
|
** number where the result is stored.
|
||||||
**
|
**
|
||||||
** This routine might also cache the result and modify the pExpr tree
|
** Also make a copy of the expression results into another "cache" register
|
||||||
** so that it will make use of the cached result on subsequent evaluations
|
** and modify the expression so that the next time it is evaluated,
|
||||||
** rather than evaluate the whole expression again. Trivial expressions are
|
** the result is a copy of the cache register.
|
||||||
** not cached. If the expression is cached, its result is stored in a
|
**
|
||||||
** memory location.
|
** This routine is used for expressions that are used multiple
|
||||||
|
** times. They are evaluated once and the results of the expression
|
||||||
|
** are reused.
|
||||||
*/
|
*/
|
||||||
void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
VdbeOp *pOp;
|
int inReg;
|
||||||
|
inReg = sqlite3ExprCode(pParse, pExpr, target);
|
||||||
|
if( pExpr->op!=TK_REGISTER ){
|
||||||
int iMem;
|
int iMem;
|
||||||
int addr1, addr2;
|
if( target<0 ){
|
||||||
if( v==0 ) return;
|
iMem = inReg;
|
||||||
addr1 = sqlite3VdbeCurrentAddr(v);
|
}else{
|
||||||
sqlite3ExprCode(pParse, pExpr, target);
|
iMem = ++pParse->nMem;
|
||||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem);
|
||||||
if( addr2>addr1+1
|
}
|
||||||
|| ((pOp = sqlite3VdbeGetOp(v, addr1))!=0 && pOp->opcode==OP_Function) ){
|
pExpr->iTable = iMem;
|
||||||
iMem = pExpr->iTable = ++pParse->nMem;
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Copy, target, iMem);
|
|
||||||
pExpr->op = TK_REGISTER;
|
pExpr->op = TK_REGISTER;
|
||||||
}
|
}
|
||||||
|
return inReg;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code that pushes the value of every element of the given
|
** Generate code that pushes the value of every element of the given
|
||||||
@@ -2457,6 +2505,10 @@ int sqlite3ExprCodeExprList(
|
|||||||
void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
int op = 0;
|
int op = 0;
|
||||||
|
int regFree1 = 0;
|
||||||
|
int regFree2 = 0;
|
||||||
|
int r1, r2;
|
||||||
|
|
||||||
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
|
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
|
||||||
if( v==0 || pExpr==0 ) return;
|
if( v==0 || pExpr==0 ) return;
|
||||||
op = pExpr->op;
|
op = pExpr->op;
|
||||||
@@ -2489,51 +2541,58 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
assert( TK_GE==OP_Ge );
|
assert( TK_GE==OP_Ge );
|
||||||
assert( TK_EQ==OP_Eq );
|
assert( TK_EQ==OP_Eq );
|
||||||
assert( TK_NE==OP_Ne );
|
assert( TK_NE==OP_Ne );
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, 0);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||||
sqlite3ExprCode(pParse, pExpr->pRight, 0);
|
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||||
0, 0, dest, jumpIfNull);
|
r1, r2, dest, jumpIfNull);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_ISNULL:
|
case TK_ISNULL:
|
||||||
case TK_NOTNULL: {
|
case TK_NOTNULL: {
|
||||||
assert( TK_ISNULL==OP_IsNull );
|
assert( TK_ISNULL==OP_IsNull );
|
||||||
assert( TK_NOTNULL==OP_NotNull );
|
assert( TK_NOTNULL==OP_NotNull );
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, 0);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||||
sqlite3VdbeAddOp2(v, op, 0, dest);
|
sqlite3VdbeAddOp2(v, op, r1, dest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
/* The expression "x BETWEEN y AND z" is implemented as:
|
/* x BETWEEN y AND z
|
||||||
**
|
**
|
||||||
** 1 IF (x < y) GOTO 3
|
** Is equivalent to
|
||||||
** 2 IF (x <= z) GOTO <dest>
|
**
|
||||||
** 3 ...
|
** x>=y AND x<=z
|
||||||
|
**
|
||||||
|
** Code it as such, taking care to do the common subexpression
|
||||||
|
** elementation of x.
|
||||||
*/
|
*/
|
||||||
int addr;
|
Expr exprAnd;
|
||||||
Expr *pLeft = pExpr->pLeft;
|
Expr compLeft;
|
||||||
Expr *pRight = pExpr->pList->a[0].pExpr;
|
Expr compRight;
|
||||||
sqlite3ExprCode(pParse, pLeft, 0);
|
Expr exprX;
|
||||||
sqlite3VdbeAddOp0(v, OP_Copy);
|
|
||||||
sqlite3ExprCode(pParse, pRight, 0);
|
|
||||||
addr = codeCompare(pParse, pLeft, pRight, OP_Lt, 0, 0, 0,
|
|
||||||
jumpIfNull ^ SQLITE_JUMPIFNULL);
|
|
||||||
|
|
||||||
pRight = pExpr->pList->a[1].pExpr;
|
exprX = *pExpr->pLeft;
|
||||||
sqlite3ExprCode(pParse, pRight, 0);
|
exprAnd.op = TK_AND;
|
||||||
codeCompare(pParse, pLeft, pRight, OP_Le, 0, 0, dest, jumpIfNull);
|
exprAnd.pLeft = &compLeft;
|
||||||
|
exprAnd.pRight = &compRight;
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
|
compLeft.op = TK_GE;
|
||||||
sqlite3VdbeJumpHere(v, addr);
|
compLeft.pLeft = &exprX;
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
|
compLeft.pRight = pExpr->pList->a[0].pExpr;
|
||||||
|
compRight.op = TK_LE;
|
||||||
|
compRight.pLeft = &exprX;
|
||||||
|
compRight.pRight = pExpr->pList->a[1].pExpr;
|
||||||
|
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1);
|
||||||
|
exprX.op = TK_REGISTER;
|
||||||
|
sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
sqlite3ExprCode(pParse, pExpr, 0);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1);
|
||||||
sqlite3VdbeAddOp3(v, OP_If, 0, dest, jumpIfNull!=0);
|
sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||||
|
sqlite3ReleaseTempReg(pParse, regFree2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2548,6 +2607,10 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
int op = 0;
|
int op = 0;
|
||||||
|
int regFree1 = 0;
|
||||||
|
int regFree2 = 0;
|
||||||
|
int r1, r2;
|
||||||
|
|
||||||
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
|
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
|
||||||
if( v==0 || pExpr==0 ) return;
|
if( v==0 || pExpr==0 ) return;
|
||||||
|
|
||||||
@@ -2605,49 +2668,56 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
case TK_GE:
|
case TK_GE:
|
||||||
case TK_NE:
|
case TK_NE:
|
||||||
case TK_EQ: {
|
case TK_EQ: {
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, 0);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||||
sqlite3ExprCode(pParse, pExpr->pRight, 0);
|
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||||
0, 0, dest, jumpIfNull);
|
r1, r2, dest, jumpIfNull);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_ISNULL:
|
case TK_ISNULL:
|
||||||
case TK_NOTNULL: {
|
case TK_NOTNULL: {
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, 0);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||||
sqlite3VdbeAddOp2(v, op, 0, dest);
|
sqlite3VdbeAddOp2(v, op, r1, dest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
/* The expression is "x BETWEEN y AND z". It is implemented as:
|
/* x BETWEEN y AND z
|
||||||
**
|
**
|
||||||
** 1 IF (x >= y) GOTO 3
|
** Is equivalent to
|
||||||
** 2 GOTO <dest>
|
**
|
||||||
** 3 IF (x > z) GOTO <dest>
|
** x>=y AND x<=z
|
||||||
|
**
|
||||||
|
** Code it as such, taking care to do the common subexpression
|
||||||
|
** elementation of x.
|
||||||
*/
|
*/
|
||||||
int addr;
|
Expr exprAnd;
|
||||||
Expr *pLeft = pExpr->pLeft;
|
Expr compLeft;
|
||||||
Expr *pRight = pExpr->pList->a[0].pExpr;
|
Expr compRight;
|
||||||
sqlite3ExprCode(pParse, pLeft, 0);
|
Expr exprX;
|
||||||
sqlite3VdbeAddOp0(v, OP_Copy);
|
|
||||||
sqlite3ExprCode(pParse, pRight, 0);
|
|
||||||
addr = sqlite3VdbeCurrentAddr(v);
|
|
||||||
codeCompare(pParse, pLeft, pRight, OP_Ge,
|
|
||||||
0, 0, addr+3, jumpIfNull ^ SQLITE_JUMPIFNULL);
|
|
||||||
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
|
exprX = *pExpr->pLeft;
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, dest);
|
exprAnd.op = TK_AND;
|
||||||
pRight = pExpr->pList->a[1].pExpr;
|
exprAnd.pLeft = &compLeft;
|
||||||
sqlite3ExprCode(pParse, pRight, 0);
|
exprAnd.pRight = &compRight;
|
||||||
codeCompare(pParse, pLeft, pRight, OP_Gt,
|
compLeft.op = TK_GE;
|
||||||
0, 0, dest, jumpIfNull);
|
compLeft.pLeft = &exprX;
|
||||||
|
compLeft.pRight = pExpr->pList->a[0].pExpr;
|
||||||
|
compRight.op = TK_LE;
|
||||||
|
compRight.pLeft = &exprX;
|
||||||
|
compRight.pRight = pExpr->pList->a[1].pExpr;
|
||||||
|
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1);
|
||||||
|
exprX.op = TK_REGISTER;
|
||||||
|
sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
sqlite3ExprCode(pParse, pExpr, 0);
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1);
|
||||||
sqlite3VdbeAddOp3(v, OP_IfNot, 0, dest, jumpIfNull!=0);
|
sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||||
|
sqlite3ReleaseTempReg(pParse, regFree2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2912,7 +2982,8 @@ int sqlite3GetTempReg(Parse *pParse){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
|
void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
|
||||||
if( pParse->nTempReg<sizeof(pParse->aTempReg)/sizeof(pParse->aTempReg[0]) ){
|
if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
|
||||||
|
assert( iReg>0 );
|
||||||
pParse->aTempReg[pParse->nTempReg++] = iReg;
|
pParse->aTempReg[pParse->nTempReg++] = iReg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/select.c
36
src/select.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.398 2008/01/12 12:48:08 drh Exp $
|
** $Id: select.c,v 1.399 2008/01/12 19:03:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -455,18 +455,21 @@ static void codeOffset(
|
|||||||
** stack if the top N elements are not distinct.
|
** stack if the top N elements are not distinct.
|
||||||
*/
|
*/
|
||||||
static void codeDistinct(
|
static void codeDistinct(
|
||||||
Vdbe *v, /* Generate code into this VM */
|
Parse *pParse, /* Parsing and code generating context */
|
||||||
int iTab, /* A sorting index used to test for distinctness */
|
int iTab, /* A sorting index used to test for distinctness */
|
||||||
int addrRepeat, /* Jump to here if not distinct */
|
int addrRepeat, /* Jump to here if not distinct */
|
||||||
int N, /* Number of elements */
|
int N, /* Number of elements */
|
||||||
int iMem /* First element */
|
int iMem /* First element */
|
||||||
){
|
){
|
||||||
sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, N);
|
Vdbe *v;
|
||||||
sqlite3VdbeAddOp2(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3);
|
int r1;
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrRepeat);
|
v = pParse->pVdbe;
|
||||||
VdbeComment((v, "skip indistinct records"));
|
r1 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, 0);
|
sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, N, r1);
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Found, iTab, addrRepeat, r1);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
|
||||||
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -564,7 +567,7 @@ static int selectInnerLoop(
|
|||||||
if( hasDistinct ){
|
if( hasDistinct ){
|
||||||
assert( pEList!=0 );
|
assert( pEList!=0 );
|
||||||
assert( pEList->nExpr==nColumn );
|
assert( pEList->nExpr==nColumn );
|
||||||
codeDistinct(v, distinct, iContinue, nColumn, iMem);
|
codeDistinct(pParse, distinct, iContinue, nColumn, iMem);
|
||||||
if( pOrderBy==0 ){
|
if( pOrderBy==0 ){
|
||||||
codeOffset(v, p, iContinue);
|
codeOffset(v, p, iContinue);
|
||||||
}
|
}
|
||||||
@@ -2859,7 +2862,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
if( pF->iDistinct>=0 ){
|
if( pF->iDistinct>=0 ){
|
||||||
addrNext = sqlite3VdbeMakeLabel(v);
|
addrNext = sqlite3VdbeMakeLabel(v);
|
||||||
assert( nArg==1 );
|
assert( nArg==1 );
|
||||||
codeDistinct(v, pF->iDistinct, addrNext, 1, regAgg);
|
codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
|
||||||
}
|
}
|
||||||
if( pF->pFunc->needCollSeq ){
|
if( pF->pFunc->needCollSeq ){
|
||||||
CollSeq *pColl = 0;
|
CollSeq *pColl = 0;
|
||||||
@@ -3440,22 +3443,17 @@ int sqlite3Select(
|
|||||||
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||||
for(j=0; j<pGroupBy->nExpr; j++){
|
for(j=0; j<pGroupBy->nExpr; j++){
|
||||||
if( groupBySort ){
|
if( groupBySort ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Column, sAggInfo.sortingIdx, j);
|
sqlite3VdbeAddOp3(v, OP_Column, sAggInfo.sortingIdx, j, iBMem+j);
|
||||||
}else{
|
}else{
|
||||||
sAggInfo.directMode = 1;
|
sAggInfo.directMode = 1;
|
||||||
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, 0);
|
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp2(v, j<pGroupBy->nExpr-1?OP_Move:OP_Copy, 0, iBMem+j);
|
|
||||||
}
|
}
|
||||||
for(j=pGroupBy->nExpr-1; j>=0; j--){
|
for(j=pGroupBy->nExpr-1; j>=0; j--){
|
||||||
if( j<pGroupBy->nExpr-1 ){
|
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, iBMem+j, 0);
|
|
||||||
}
|
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, iAMem+j, 0);
|
|
||||||
if( j==0 ){
|
if( j==0 ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Eq, 0, addrProcessRow);
|
sqlite3VdbeAddOp3(v, OP_Eq, iAMem+j, addrProcessRow, iBMem+j);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Ne, 0, addrGroupByChange);
|
sqlite3VdbeAddOp3(v, OP_Ne, iAMem+j, addrGroupByChange, iBMem+j);
|
||||||
}
|
}
|
||||||
sqlite3VdbeChangeP4(v, -1, (void*)pKeyInfo->aColl[j], P4_COLLSEQ);
|
sqlite3VdbeChangeP4(v, -1, (void*)pKeyInfo->aColl[j], P4_COLLSEQ);
|
||||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQUAL);
|
sqlite3VdbeChangeP5(v, SQLITE_NULLEQUAL);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.648 2008/01/12 12:48:08 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.649 2008/01/12 19:03:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1400,6 +1400,7 @@ struct Parse {
|
|||||||
u8 nested; /* Number of nested calls to the parser/code generator */
|
u8 nested; /* Number of nested calls to the parser/code generator */
|
||||||
u8 parseError; /* True after a parsing error. Ticket #1794 */
|
u8 parseError; /* True after a parsing error. Ticket #1794 */
|
||||||
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
|
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
|
||||||
|
u8 nTempInUse; /* Number of aTempReg[] currently checked out */
|
||||||
int aTempReg[8]; /* Holding area for temporary registers */
|
int aTempReg[8]; /* Holding area for temporary registers */
|
||||||
int nRangeReg; /* Size of the temporary register block */
|
int nRangeReg; /* Size of the temporary register block */
|
||||||
int iRangeReg; /* First register in temporary register block */
|
int iRangeReg; /* First register in temporary register block */
|
||||||
@@ -1768,7 +1769,8 @@ WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
|
|||||||
void sqlite3WhereEnd(WhereInfo*);
|
void sqlite3WhereEnd(WhereInfo*);
|
||||||
void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int);
|
void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int);
|
||||||
int sqlite3ExprCode(Parse*, Expr*, int);
|
int sqlite3ExprCode(Parse*, Expr*, int);
|
||||||
void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
|
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
||||||
|
int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
|
||||||
int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
|
int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
|
||||||
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
||||||
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
||||||
|
|||||||
45
src/vdbe.c
45
src/vdbe.c
@@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.693 2008/01/12 12:48:08 drh Exp $
|
** $Id: vdbe.c,v 1.694 2008/01/12 19:03:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -1062,17 +1062,6 @@ case OP_Variable: { /* out2-prerelease */
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: Pop P1 * * * *
|
|
||||||
**
|
|
||||||
** P1 elements are popped off of the top of stack and discarded.
|
|
||||||
*/
|
|
||||||
case OP_Pop: { /* no-push */
|
|
||||||
assert( pOp->p1>=0 );
|
|
||||||
popStack(&pTos, pOp->p1);
|
|
||||||
assert( pTos>=&p->aStack[-1] );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: Move P1 P2 * * *
|
/* Opcode: Move P1 P2 * * *
|
||||||
**
|
**
|
||||||
** Move the value in P1 into P2. If P1 is positive then read from the
|
** Move the value in P1 into P2. If P1 is positive then read from the
|
||||||
@@ -1404,6 +1393,7 @@ case OP_Function: {
|
|||||||
for(i=0; i<n; i++, pArg++){
|
for(i=0; i<n; i++, pArg++){
|
||||||
apVal[i] = pArg;
|
apVal[i] = pArg;
|
||||||
storeTypeInfo(pArg, encoding);
|
storeTypeInfo(pArg, encoding);
|
||||||
|
REGISTER_TRACE(pOp->p2, pArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
|
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
|
||||||
@@ -1472,6 +1462,7 @@ case OP_Function: {
|
|||||||
if( sqlite3VdbeMemTooBig(pOut) ){
|
if( sqlite3VdbeMemTooBig(pOut) ){
|
||||||
goto too_big;
|
goto too_big;
|
||||||
}
|
}
|
||||||
|
REGISTER_TRACE(pOp->p3, pOut);
|
||||||
UPDATE_MAX_BLOBSIZE(pOut);
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3149,44 +3140,26 @@ case OP_MoveGt: { /* no-push, jump, in3 */
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: Distinct P1 P2 P3 * *
|
|
||||||
**
|
|
||||||
** Use register P3 as a record created using MakeRecord. P1 is a
|
|
||||||
** cursor on a table that declared as an index. If that table contains an
|
|
||||||
** entry that matches the top of the stack fall thru. If the top of the stack
|
|
||||||
** matches no entry in P1 then jump to P2.
|
|
||||||
**
|
|
||||||
** The cursor is left pointing at the matching entry if it exists. The
|
|
||||||
** record on the top of the stack is not popped.
|
|
||||||
**
|
|
||||||
** This instruction is similar to NotFound except that this operation
|
|
||||||
** does not pop the key from the stack when P3==0.
|
|
||||||
**
|
|
||||||
** The instruction is used to implement the DISTINCT operator on SELECT
|
|
||||||
** statements. The P1 table is not a true index but rather a record of
|
|
||||||
** all results that have produced so far.
|
|
||||||
**
|
|
||||||
** See also: Found, NotFound, MoveTo, IsUnique, NotExists
|
|
||||||
*/
|
|
||||||
/* Opcode: Found P1 P2 P3 * *
|
/* Opcode: Found P1 P2 P3 * *
|
||||||
**
|
**
|
||||||
** Register P3 holds a blob constructed by MakeRecord. P1 is an index.
|
** Register P3 holds a blob constructed by MakeRecord. P1 is an index.
|
||||||
** If an entry that matches the top of the stack exists in P1 then
|
** If an entry that matches the top of the stack exists in P1 then
|
||||||
** jump to P2. If the top of the stack does not match any entry in P1
|
** jump to P2. If the top of the stack does not match any entry in P1
|
||||||
** then fall thru. The P1 cursor is left pointing at the matching entry
|
** then fall thru. The P1 cursor is left pointing at the matching entry
|
||||||
** if it exists. The blob is popped off the top of the stack.
|
** if it exists.
|
||||||
**
|
**
|
||||||
** This instruction is used to implement the IN operator where the
|
** This instruction is used to implement the IN operator where the
|
||||||
** left-hand side is a SELECT statement. P1 may be a true index, or it
|
** left-hand side is a SELECT statement. P1 may be a true index, or it
|
||||||
** may be a temporary index that holds the results of the SELECT
|
** may be a temporary index that holds the results of the SELECT
|
||||||
** statement.
|
** statement. This instruction is also used to implement the
|
||||||
|
** DISTINCT keyword in SELECT statements.
|
||||||
**
|
**
|
||||||
** This instruction checks if index P1 contains a record for which
|
** This instruction checks if index P1 contains a record for which
|
||||||
** the first N serialised values exactly match the N serialised values
|
** the first N serialised values exactly match the N serialised values
|
||||||
** in the record on the stack, where N is the total number of values in
|
** in the record on the stack, where N is the total number of values in
|
||||||
** the stack record (stack record is a prefix of the P1 record).
|
** the stack record (stack record is a prefix of the P1 record).
|
||||||
**
|
**
|
||||||
** See also: Distinct, NotFound, MoveTo, IsUnique, NotExists
|
** See also: NotFound, MoveTo, IsUnique, NotExists
|
||||||
*/
|
*/
|
||||||
/* Opcode: NotFound P1 P2 P3 * *
|
/* Opcode: NotFound P1 P2 P3 * *
|
||||||
**
|
**
|
||||||
@@ -3200,7 +3173,6 @@ case OP_MoveGt: { /* no-push, jump, in3 */
|
|||||||
**
|
**
|
||||||
** See also: Distinct, Found, MoveTo, NotExists, IsUnique
|
** See also: Distinct, Found, MoveTo, NotExists, IsUnique
|
||||||
*/
|
*/
|
||||||
case OP_Distinct: /* no-push, jump, in3 */
|
|
||||||
case OP_NotFound: /* no-push, jump, in3 */
|
case OP_NotFound: /* no-push, jump, in3 */
|
||||||
case OP_Found: { /* no-push, jump, in3 */
|
case OP_Found: { /* no-push, jump, in3 */
|
||||||
int i = pOp->p1;
|
int i = pOp->p1;
|
||||||
@@ -3229,9 +3201,6 @@ case OP_Found: { /* no-push, jump, in3 */
|
|||||||
}else{
|
}else{
|
||||||
if( !alreadyExists ) pc = pOp->p2 - 1;
|
if( !alreadyExists ) pc = pOp->p2 - 1;
|
||||||
}
|
}
|
||||||
if( pOp->opcode==OP_Distinct ){
|
|
||||||
nPop = 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
** so is applicable. Because this module is responsible for selecting
|
** so is applicable. Because this module is responsible for selecting
|
||||||
** indices, you might also think of this module as the "query optimizer".
|
** indices, you might also think of this module as the "query optimizer".
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.280 2008/01/09 23:04:13 drh Exp $
|
** $Id: where.c,v 1.281 2008/01/12 19:03:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -2591,8 +2591,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
sqlite3VdbeAddOp1(v, OP_Copy, 1-nEq);
|
sqlite3VdbeAddOp1(v, OP_Copy, 1-nEq);
|
||||||
}
|
}
|
||||||
buildIndexProbe(v, nEq, pIdx);
|
buildIndexProbe(v, nEq, pIdx);
|
||||||
sqlite3VdbeAddOp2(v, OP_Copy, 0, pLevel->iMem);
|
sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem);
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||||
buildIndexProbe(v, nEq+1, pIdx);
|
buildIndexProbe(v, nEq+1, pIdx);
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing built-in functions.
|
# focus of this file is testing built-in functions.
|
||||||
#
|
#
|
||||||
# $Id: func.test,v 1.71 2007/11/28 22:36:41 drh Exp $
|
# $Id: func.test,v 1.72 2008/01/12 19:03:49 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -438,9 +438,9 @@ do_test func-12.2 {
|
|||||||
} {0}
|
} {0}
|
||||||
do_test func-12.3 {
|
do_test func-12.3 {
|
||||||
execsql {
|
execsql {
|
||||||
SELECT test_destructor('hello')||' world', test_destructor_count();
|
SELECT test_destructor('hello')||' world'
|
||||||
}
|
}
|
||||||
} {{hello world} 0}
|
} {{hello world}}
|
||||||
do_test func-12.4 {
|
do_test func-12.4 {
|
||||||
execsql {
|
execsql {
|
||||||
SELECT test_destructor_count();
|
SELECT test_destructor_count();
|
||||||
|
|||||||
Reference in New Issue
Block a user