mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
added IN and BETWEEN operators (CVS 57)
FossilOrigin-Name: 54d198189b58366e4e40139102bc6de94ac55e18
This commit is contained in:
29
manifest
29
manifest
@@ -1,5 +1,5 @@
|
|||||||
C :-)\s(CVS\s56)
|
C added\sIN\sand\sBETWEEN\soperators\s(CVS\s57)
|
||||||
D 2000-06-06T03:31:22
|
D 2000-06-06T13:54:15
|
||||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||||
F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644
|
F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644
|
||||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||||
@@ -9,26 +9,27 @@ F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
|
|||||||
F src/build.c 6c9454b2e2b866979527fb41b19ad8bc49c27a20
|
F src/build.c 6c9454b2e2b866979527fb41b19ad8bc49c27a20
|
||||||
F src/dbbe.c ae8b5d2cdb4fa7dd11313059984be9457fa77f63
|
F src/dbbe.c ae8b5d2cdb4fa7dd11313059984be9457fa77f63
|
||||||
F src/dbbe.h a8a46f71238e0f09f3ec08fd9d1c8c7f4cdc49bf
|
F src/dbbe.h a8a46f71238e0f09f3ec08fd9d1c8c7f4cdc49bf
|
||||||
F src/delete.c e11433c14ed5cc8553cba14296b3baa3c23054bc
|
F src/delete.c 8c733bb82a1b84126116d03dcdccf433c0856f5d
|
||||||
F src/expr.c 278ff688ac72602ad985f4ccadcae665d245b13b
|
F src/expr.c 1bedf5f426ee1e1609ef1758985b7ce0581987b8
|
||||||
F src/insert.c 5e69dd70c3f91cf5ec5090f39fd6cd8e135af9bf
|
F src/insert.c 5e69dd70c3f91cf5ec5090f39fd6cd8e135af9bf
|
||||||
F src/main.c 93a7ad14bb5a82ad13ad59da23ef674a94b0c3d6
|
F src/main.c 93a7ad14bb5a82ad13ad59da23ef674a94b0c3d6
|
||||||
F src/parse.y 9c459212441d4786bb011945d6a587568368e202
|
F src/parse.y 51ef63a49e73ced4ef3e81d7b1f9fd825d776837
|
||||||
F src/select.c d90d577aa7687c860f2ce22dacabdbecb600f609
|
F src/select.c a1891cfce003a98a57374c01fa5875366c8d9be2
|
||||||
F src/shell.c 5fa24c0bb678782ffe9070128e3e160674f297eb
|
F src/shell.c 5fa24c0bb678782ffe9070128e3e160674f297eb
|
||||||
F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268
|
F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268
|
||||||
F src/sqliteInt.h 6f31db9b08bc7aec193c84f6f08b0f6c7ce9f270
|
F src/sqliteInt.h 821b435a18e1c9d0fddcd7bfeefcf5f3fe925c6e
|
||||||
F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
|
F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
|
||||||
F src/tokenize.c f190e16ebb82dd60497796022f1e56e2e0527975
|
F src/tokenize.c f190e16ebb82dd60497796022f1e56e2e0527975
|
||||||
F src/update.c 3f05d5082fd2c34f15d1e4a4db17355ad8807a78
|
F src/update.c 18746f920f989b3d19d96c08263c92584823cd35
|
||||||
F src/util.c 33f9baa01e45394ef0cf85361a0e872987884315
|
F src/util.c 33f9baa01e45394ef0cf85361a0e872987884315
|
||||||
F src/vdbe.c 7d00f9ff05cf1287ee21c2a73d9ba0ebdf07b4b6
|
F src/vdbe.c 1ab61ada503b99d6b3224c9d40ed9bac855fe317
|
||||||
F src/vdbe.h 49e0f9c6742860e224cd81d1278059f5d029dfb6
|
F src/vdbe.h 49e0f9c6742860e224cd81d1278059f5d029dfb6
|
||||||
F src/where.c 6b840a726b06b5122f112e3bc3c142a230af6251
|
F src/where.c c9b90e7672f4662a83ef9a27a193020d69fe034c
|
||||||
F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
|
F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
|
||||||
F test/copy.test 73c3783535db538c8ebd8fffb931376864fc3226
|
F test/copy.test 73c3783535db538c8ebd8fffb931376864fc3226
|
||||||
F test/delete.test 30451333f89479d2deb5410edd3f3cce67339944
|
F test/delete.test 30451333f89479d2deb5410edd3f3cce67339944
|
||||||
F test/expr.test db6984d2a6e86118dfce68edade6539495f29022
|
F test/expr.test 52be5592143a88479e0006dfd7e2023e43294636
|
||||||
|
F test/in.test 17cd46a9ca0e5d4a804483e6fb496458494858e6
|
||||||
F test/index.test 9f99dca2d904b8de330863a978587f136e2df65a
|
F test/index.test 9f99dca2d904b8de330863a978587f136e2df65a
|
||||||
F test/insert.test b4c186ffa4b97a231643726f3bcee29815b24eaf
|
F test/insert.test b4c186ffa4b97a231643726f3bcee29815b24eaf
|
||||||
F test/select1.test a0b00df77e85adff75c338e487718c5d31f69e3a
|
F test/select1.test a0b00df77e85adff75c338e487718c5d31f69e3a
|
||||||
@@ -48,7 +49,7 @@ F www/c_interface.tcl 8867d76ddd416d2fbd41e4cb3de8efa9cef105a5
|
|||||||
F www/changes.tcl 567cc6066d87460bdedff8e5bbc20f41ddaadf77
|
F www/changes.tcl 567cc6066d87460bdedff8e5bbc20f41ddaadf77
|
||||||
F www/index.tcl f8189a7898f6d06307c34047b9d7e00860026e44
|
F www/index.tcl f8189a7898f6d06307c34047b9d7e00860026e44
|
||||||
F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd
|
F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd
|
||||||
P bd8b2645cc16759571c8c622dce4752bd35c04cf
|
P b52dd82fe32c38c999aef4f07d046d0428336965
|
||||||
R 712a80d7b1f5a98574f5dc5cddb6e092
|
R d1b48bd641877701893f6074a4e397f8
|
||||||
U drh
|
U drh
|
||||||
Z b053febfd62b58b2d6d5fa997754fe2c
|
Z 3b39b6691fb1f454562ec994b26db409
|
||||||
|
@@ -1 +1 @@
|
|||||||
b52dd82fe32c38c999aef4f07d046d0428336965
|
54d198189b58366e4e40139102bc6de94ac55e18
|
17
src/delete.c
17
src/delete.c
@@ -24,7 +24,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 DELETE FROM statements.
|
** to handle DELETE FROM statements.
|
||||||
**
|
**
|
||||||
** $Id: delete.c,v 1.2 2000/06/02 01:17:37 drh Exp $
|
** $Id: delete.c,v 1.3 2000/06/06 13:54:15 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -43,6 +43,7 @@ void sqliteDeleteFrom(
|
|||||||
int i; /* Loop counter */
|
int i; /* Loop counter */
|
||||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||||
Index *pIdx; /* For looping over indices of the table */
|
Index *pIdx; /* For looping over indices of the table */
|
||||||
|
int base; /* Index of the first available table cursor */
|
||||||
|
|
||||||
/* Locate the table which we want to update. This table has to be
|
/* Locate the table which we want to update. This table has to be
|
||||||
** put in an IdList structure because some of the subroutines will
|
** put in an IdList structure because some of the subroutines will
|
||||||
@@ -70,6 +71,7 @@ void sqliteDeleteFrom(
|
|||||||
/* Resolve the field names in all the expressions.
|
/* Resolve the field names in all the expressions.
|
||||||
*/
|
*/
|
||||||
if( pWhere ){
|
if( pWhere ){
|
||||||
|
sqliteExprResolveInSelect(pParse, pWhere);
|
||||||
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
|
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
|
||||||
goto delete_from_cleanup;
|
goto delete_from_cleanup;
|
||||||
}
|
}
|
||||||
@@ -102,27 +104,28 @@ void sqliteDeleteFrom(
|
|||||||
|
|
||||||
/* Delete every item identified in the list.
|
/* Delete every item identified in the list.
|
||||||
*/
|
*/
|
||||||
|
base = pParse->nTab;
|
||||||
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
|
sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
|
||||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||||
sqliteVdbeAddOp(v, OP_Open, i, 1, pIdx->zName, 0);
|
sqliteVdbeAddOp(v, OP_Open, base+i, 1, pIdx->zName, 0);
|
||||||
}
|
}
|
||||||
end = sqliteVdbeMakeLabel(v);
|
end = sqliteVdbeMakeLabel(v);
|
||||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
|
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
|
||||||
if( pTab->pIndex ){
|
if( pTab->pIndex ){
|
||||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Fetch, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
|
||||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||||
int j;
|
int j;
|
||||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
||||||
for(j=0; j<pIdx->nField; j++){
|
for(j=0; j<pIdx->nField; j++){
|
||||||
sqliteVdbeAddOp(v, OP_Field, 0, pIdx->aiField[j], 0, 0);
|
sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0);
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_DeleteIdx, i, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_Delete, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Delete, base, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
|
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
|
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
|
||||||
|
|
||||||
|
51
src/expr.c
51
src/expr.c
@@ -23,7 +23,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains C code routines used for processing expressions
|
** This file contains C code routines used for processing expressions
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.8 2000/06/06 03:31:22 drh Exp $
|
** $Id: expr.c,v 1.9 2000/06/06 13:54:15 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -52,6 +52,38 @@ static int isConstant(Expr *p){
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Walk the expression tree and process operators of the form:
|
||||||
|
**
|
||||||
|
** expr IN (SELECT ...)
|
||||||
|
**
|
||||||
|
** These operators have to be processed before field names are
|
||||||
|
** resolved because each such operator increments pParse->nTab
|
||||||
|
** to reserve a cursor number for its own use. But pParse->nTab
|
||||||
|
** needs to be constant once we begin resolving field names.
|
||||||
|
**
|
||||||
|
** Actually, the processing of IN-SELECT is only started by this
|
||||||
|
** routine. This routine allocates a cursor number to the IN-SELECT
|
||||||
|
** and then moves on. The code generation is done by
|
||||||
|
** sqliteExprResolveIds() which must be called afterwards.
|
||||||
|
*/
|
||||||
|
void sqliteExprResolveInSelect(Parse *pParse, Expr *pExpr){
|
||||||
|
if( pExpr==0 ) return;
|
||||||
|
if( pExpr->op==TK_IN && pExpr->pSelect!=0 ){
|
||||||
|
pExpr->iTable = pParse->nTab++;
|
||||||
|
}else{
|
||||||
|
if( pExpr->pLeft ) sqliteExprResolveInSelect(pParse, pExpr->pLeft);
|
||||||
|
if( pExpr->pRight ) sqliteExprResolveInSelect(pParse, pExpr->pRight);
|
||||||
|
if( pExpr->pList ){
|
||||||
|
int i;
|
||||||
|
ExprList *pList = pExpr->pList;
|
||||||
|
for(i=0; i<pList->nExpr; i++){
|
||||||
|
sqliteExprResolveInSelect(pParse, pList->a[i].pExpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine walks an expression tree and resolves references to
|
** This routine walks an expression tree and resolves references to
|
||||||
** table fields. Nodes of the form ID.ID or ID resolve into an
|
** table fields. Nodes of the form ID.ID or ID resolve into an
|
||||||
@@ -186,11 +218,10 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
|||||||
/* Case 1: expr IN (SELECT ...)
|
/* Case 1: expr IN (SELECT ...)
|
||||||
**
|
**
|
||||||
** Generate code to write the results of the select into a temporary
|
** Generate code to write the results of the select into a temporary
|
||||||
** table. The cursor number of the temporary table is stored in
|
** table. The cursor number of the temporary table has already
|
||||||
** iTable.
|
** been put in iTable by sqliteExprResolveInSelect().
|
||||||
*/
|
*/
|
||||||
pExpr->iTable = pParse->nTab++;
|
sqliteVdbeAddOp(v, OP_Open, pExpr->iTable, 1, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Open, pExpr->iTable, 0, 0, 0);
|
|
||||||
if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
|
if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
|
||||||
}else if( pExpr->pList ){
|
}else if( pExpr->pList ){
|
||||||
/* Case 2: expr IN (exprlist)
|
/* Case 2: expr IN (exprlist)
|
||||||
@@ -201,15 +232,15 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
|||||||
int i, iSet;
|
int i, iSet;
|
||||||
for(i=0; i<pExpr->pList->nExpr; i++){
|
for(i=0; i<pExpr->pList->nExpr; i++){
|
||||||
Expr *pE2 = pExpr->pList->a[i].pExpr;
|
Expr *pE2 = pExpr->pList->a[i].pExpr;
|
||||||
if( sqliteExprCheck(pParse, pE2, 0, 0) ){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if( !isConstant(pE2) ){
|
if( !isConstant(pE2) ){
|
||||||
sqliteSetString(&pParse->zErrMsg,
|
sqliteSetString(&pParse->zErrMsg,
|
||||||
"right-hand side of IN operator must be constant", 0);
|
"right-hand side of IN operator must be constant", 0);
|
||||||
pParse->nErr++;
|
pParse->nErr++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if( sqliteExprCheck(pParse, pE2, 0, 0) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
iSet = pExpr->iTable = pParse->nSet++;
|
iSet = pExpr->iTable = pParse->nSet++;
|
||||||
for(i=0; i<pExpr->pList->nExpr; i++){
|
for(i=0; i<pExpr->pList->nExpr; i++){
|
||||||
@@ -512,7 +543,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
|
|||||||
}
|
}
|
||||||
case TK_IN: {
|
case TK_IN: {
|
||||||
int addr;
|
int addr;
|
||||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Integer, 1, 0, 0, 0);
|
||||||
sqliteExprCode(pParse, pExpr->pLeft);
|
sqliteExprCode(pParse, pExpr->pLeft);
|
||||||
addr = sqliteVdbeCurrentAddr(v);
|
addr = sqliteVdbeCurrentAddr(v);
|
||||||
if( pExpr->pSelect ){
|
if( pExpr->pSelect ){
|
||||||
@@ -520,7 +551,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
|
|||||||
}else{
|
}else{
|
||||||
sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+2, 0, 0);
|
sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+2, 0, 0);
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_AddImm, 1, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_AddImm, -1, 0, 0, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
|
29
src/parse.y
29
src/parse.y
@@ -26,7 +26,7 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** numeric codes for all of the tokens.
|
||||||
**
|
**
|
||||||
** @(#) $Id: parse.y,v 1.11 2000/06/06 01:50:43 drh Exp $
|
** @(#) $Id: parse.y,v 1.12 2000/06/06 13:54:15 drh Exp $
|
||||||
*/
|
*/
|
||||||
%token_prefix TK_
|
%token_prefix TK_
|
||||||
%token_type {Token}
|
%token_type {Token}
|
||||||
@@ -108,7 +108,7 @@ ccons ::= NOT NULL.
|
|||||||
ccons ::= PRIMARY KEY sortorder.
|
ccons ::= PRIMARY KEY sortorder.
|
||||||
{sqliteCreateIndex(pParse,0,0,0,0,0);}
|
{sqliteCreateIndex(pParse,0,0,0,0,0);}
|
||||||
ccons ::= UNIQUE.
|
ccons ::= UNIQUE.
|
||||||
ccons ::= CHECK expr.
|
ccons ::= CHECK LP expr RP.
|
||||||
|
|
||||||
// For the time being, the only constraint we care about is the primary
|
// For the time being, the only constraint we care about is the primary
|
||||||
// key.
|
// key.
|
||||||
@@ -301,7 +301,15 @@ expr(A) ::= expr(X) GE expr(Y). {A = sqliteExpr(TK_GE, X, Y, 0);}
|
|||||||
expr(A) ::= expr(X) NE expr(Y). {A = sqliteExpr(TK_NE, X, Y, 0);}
|
expr(A) ::= expr(X) NE expr(Y). {A = sqliteExpr(TK_NE, X, Y, 0);}
|
||||||
expr(A) ::= expr(X) EQ expr(Y). {A = sqliteExpr(TK_EQ, X, Y, 0);}
|
expr(A) ::= expr(X) EQ expr(Y). {A = sqliteExpr(TK_EQ, X, Y, 0);}
|
||||||
expr(A) ::= expr(X) LIKE expr(Y). {A = sqliteExpr(TK_LIKE, X, Y, 0);}
|
expr(A) ::= expr(X) LIKE expr(Y). {A = sqliteExpr(TK_LIKE, X, Y, 0);}
|
||||||
|
expr(A) ::= expr(X) NOT LIKE expr(Y). {
|
||||||
|
A = sqliteExpr(TK_LIKE, X, Y, 0);
|
||||||
|
A = sqliteExpr(TK_NOT, A, 0, 0);
|
||||||
|
}
|
||||||
expr(A) ::= expr(X) GLOB expr(Y). {A = sqliteExpr(TK_GLOB,X,Y,0);}
|
expr(A) ::= expr(X) GLOB expr(Y). {A = sqliteExpr(TK_GLOB,X,Y,0);}
|
||||||
|
expr(A) ::= expr(X) NOT GLOB expr(Y). {
|
||||||
|
A = sqliteExpr(TK_GLOB, X, Y, 0);
|
||||||
|
A = sqliteExpr(TK_NOT, A, 0, 0);
|
||||||
|
}
|
||||||
expr(A) ::= expr(X) PLUS expr(Y). {A = sqliteExpr(TK_PLUS, X, Y, 0);}
|
expr(A) ::= expr(X) PLUS expr(Y). {A = sqliteExpr(TK_PLUS, X, Y, 0);}
|
||||||
expr(A) ::= expr(X) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);}
|
expr(A) ::= expr(X) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);}
|
||||||
expr(A) ::= expr(X) STAR expr(Y). {A = sqliteExpr(TK_STAR, X, Y, 0);}
|
expr(A) ::= expr(X) STAR expr(Y). {A = sqliteExpr(TK_STAR, X, Y, 0);}
|
||||||
@@ -321,6 +329,13 @@ expr(A) ::= expr(W) BETWEEN expr(X) AND expr(Y). {
|
|||||||
A = sqliteExpr(TK_BETWEEN, W, 0, 0);
|
A = sqliteExpr(TK_BETWEEN, W, 0, 0);
|
||||||
A->pList = pList;
|
A->pList = pList;
|
||||||
}
|
}
|
||||||
|
expr(A) ::= expr(W) NOT BETWEEN expr(X) AND expr(Y). {
|
||||||
|
ExprList *pList = sqliteExprListAppend(0, X, 0);
|
||||||
|
pList = sqliteExprListAppend(pList, Y, 0);
|
||||||
|
A = sqliteExpr(TK_BETWEEN, W, 0, 0);
|
||||||
|
A->pList = pList;
|
||||||
|
A = sqliteExpr(TK_NOT, A, 0, 0);
|
||||||
|
}
|
||||||
expr(A) ::= expr(X) IN LP exprlist(Y) RP. {
|
expr(A) ::= expr(X) IN LP exprlist(Y) RP. {
|
||||||
A = sqliteExpr(TK_IN, X, 0, 0);
|
A = sqliteExpr(TK_IN, X, 0, 0);
|
||||||
A->pList = Y;
|
A->pList = Y;
|
||||||
@@ -329,6 +344,16 @@ expr(A) ::= expr(X) IN LP select(Y) RP. {
|
|||||||
A = sqliteExpr(TK_IN, X, 0, 0);
|
A = sqliteExpr(TK_IN, X, 0, 0);
|
||||||
A->pSelect = Y;
|
A->pSelect = Y;
|
||||||
}
|
}
|
||||||
|
expr(A) ::= expr(X) NOT IN LP exprlist(Y) RP. {
|
||||||
|
A = sqliteExpr(TK_IN, X, 0, 0);
|
||||||
|
A->pList = Y;
|
||||||
|
A = sqliteExpr(TK_NOT, A, 0, 0);
|
||||||
|
}
|
||||||
|
expr(A) ::= expr(X) NOT IN LP select(Y) RP. {
|
||||||
|
A = sqliteExpr(TK_IN, X, 0, 0);
|
||||||
|
A->pSelect = Y;
|
||||||
|
A = sqliteExpr(TK_NOT, A, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
11
src/select.c
11
src/select.c
@@ -24,7 +24,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.
|
** to handle SELECT statements.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.9 2000/06/06 01:50:43 drh Exp $
|
** $Id: select.c,v 1.10 2000/06/06 13:54:15 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -165,6 +165,15 @@ int sqliteSelect(
|
|||||||
|
|
||||||
/* Resolve the field names and do a semantics check on all the expressions.
|
/* Resolve the field names and do a semantics check on all the expressions.
|
||||||
*/
|
*/
|
||||||
|
for(i=0; i<pEList->nExpr; i++){
|
||||||
|
sqliteExprResolveInSelect(pParse, pEList->a[i].pExpr);
|
||||||
|
}
|
||||||
|
if( pWhere ) sqliteExprResolveInSelect(pParse, pWhere);
|
||||||
|
if( pOrderBy ){
|
||||||
|
for(i=0; i<pOrderBy->nExpr; i++){
|
||||||
|
sqliteExprResolveInSelect(pParse, pOrderBy->a[i].pExpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
for(i=0; i<pEList->nExpr; i++){
|
for(i=0; i<pEList->nExpr; i++){
|
||||||
if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){
|
if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){
|
||||||
return 1;
|
return 1;
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.16 2000/06/06 01:50:43 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.17 2000/06/06 13:54:15 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
#include "dbbe.h"
|
#include "dbbe.h"
|
||||||
@@ -314,3 +314,4 @@ char *sqliteTableNameFromToken(Token*);
|
|||||||
int sqliteExprCheck(Parse*, Expr*, int, int*);
|
int sqliteExprCheck(Parse*, Expr*, int, int*);
|
||||||
int sqliteFuncId(Token*);
|
int sqliteFuncId(Token*);
|
||||||
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
|
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
|
||||||
|
void sqliteExprResolveInSelect(Parse*, Expr*);
|
||||||
|
26
src/update.c
26
src/update.c
@@ -24,7 +24,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 UPDATE statements.
|
** to handle UPDATE statements.
|
||||||
**
|
**
|
||||||
** $Id: update.c,v 1.3 2000/06/03 18:06:53 drh Exp $
|
** $Id: update.c,v 1.4 2000/06/06 13:54:16 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -45,6 +45,7 @@ void sqliteUpdate(
|
|||||||
Vdbe *v; /* The virtual database engine */
|
Vdbe *v; /* The virtual database engine */
|
||||||
Index *pIdx; /* For looping over indices */
|
Index *pIdx; /* For looping over indices */
|
||||||
int nIdx; /* Number of indices that need updating */
|
int nIdx; /* Number of indices that need updating */
|
||||||
|
int base; /* Index of first available table cursor */
|
||||||
Index **apIdx = 0; /* An array of indices that need updating too */
|
Index **apIdx = 0; /* An array of indices that need updating too */
|
||||||
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
|
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
|
||||||
** an expression for the i-th field of the table.
|
** an expression for the i-th field of the table.
|
||||||
@@ -80,6 +81,12 @@ void sqliteUpdate(
|
|||||||
** WHERE clause and in the new values. Also find the field index
|
** WHERE clause and in the new values. Also find the field index
|
||||||
** for each field to be updated in the pChanges array.
|
** for each field to be updated in the pChanges array.
|
||||||
*/
|
*/
|
||||||
|
if( pWhere ){
|
||||||
|
sqliteExprResolveInSelect(pParse, pWhere);
|
||||||
|
}
|
||||||
|
for(i=0; i<pChanges->nExpr; i++){
|
||||||
|
sqliteExprResolveInSelect(pParse, pChanges->a[i].pExpr);
|
||||||
|
}
|
||||||
if( pWhere ){
|
if( pWhere ){
|
||||||
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
|
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
|
||||||
goto update_cleanup;
|
goto update_cleanup;
|
||||||
@@ -155,9 +162,10 @@ void sqliteUpdate(
|
|||||||
** open every index that needs updating.
|
** open every index that needs updating.
|
||||||
*/
|
*/
|
||||||
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
|
base = pParse->nTab;
|
||||||
|
sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
|
||||||
for(i=0; i<nIdx; i++){
|
for(i=0; i<nIdx; i++){
|
||||||
sqliteVdbeAddOp(v, OP_Open, i+1, 1, apIdx[i]->zName, 0);
|
sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop over every record that needs updating. We have to load
|
/* Loop over every record that needs updating. We have to load
|
||||||
@@ -168,7 +176,7 @@ void sqliteUpdate(
|
|||||||
end = sqliteVdbeMakeLabel(v);
|
end = sqliteVdbeMakeLabel(v);
|
||||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
|
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Fetch, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
|
||||||
|
|
||||||
/* Delete the old indices for the current record.
|
/* Delete the old indices for the current record.
|
||||||
*/
|
*/
|
||||||
@@ -176,10 +184,10 @@ void sqliteUpdate(
|
|||||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
||||||
pIdx = apIdx[i];
|
pIdx = apIdx[i];
|
||||||
for(j=0; j<pIdx->nField; j++){
|
for(j=0; j<pIdx->nField; j++){
|
||||||
sqliteVdbeAddOp(v, OP_Field, 0, pIdx->aiField[j], 0, 0);
|
sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0);
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_DeleteIdx, i+1, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute a completely new data for this record.
|
/* Compute a completely new data for this record.
|
||||||
@@ -187,7 +195,7 @@ void sqliteUpdate(
|
|||||||
for(i=0; i<pTab->nCol; i++){
|
for(i=0; i<pTab->nCol; i++){
|
||||||
j = aXRef[i];
|
j = aXRef[i];
|
||||||
if( j<0 ){
|
if( j<0 ){
|
||||||
sqliteVdbeAddOp(v, OP_Field, 0, i, 0, 0);
|
sqliteVdbeAddOp(v, OP_Field, base, i, 0, 0);
|
||||||
}else{
|
}else{
|
||||||
sqliteExprCode(pParse, pChanges->a[j].pExpr);
|
sqliteExprCode(pParse, pChanges->a[j].pExpr);
|
||||||
}
|
}
|
||||||
@@ -202,13 +210,13 @@ void sqliteUpdate(
|
|||||||
sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0);
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_PutIdx, i+1, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the new data back into the database.
|
/* Write the new data back into the database.
|
||||||
*/
|
*/
|
||||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0);
|
||||||
|
|
||||||
/* Repeat the above with the next record to be updated, until
|
/* Repeat the above with the next record to be updated, until
|
||||||
** all record selected by the WHERE clause have been updated.
|
** all record selected by the WHERE clause have been updated.
|
||||||
|
@@ -41,7 +41,7 @@
|
|||||||
** But other routines are also provided to help in building up
|
** But other routines are also provided to help in building up
|
||||||
** a program instruction by instruction.
|
** a program instruction by instruction.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.19 2000/06/06 03:31:22 drh Exp $
|
** $Id: vdbe.c,v 1.20 2000/06/06 13:54:16 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -795,7 +795,7 @@ int sqliteVdbeList(
|
|||||||
azField[3] = zP2;
|
azField[3] = zP2;
|
||||||
azField[5] = 0;
|
azField[5] = 0;
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
if( pzErrMsg ){ *pzErrMsg = 0; }
|
/* if( pzErrMsg ){ *pzErrMsg = 0; } */
|
||||||
for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
|
for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
|
||||||
sprintf(zAddr,"%d",i);
|
sprintf(zAddr,"%d",i);
|
||||||
sprintf(zP1,"%d", p->aOp[i].p1);
|
sprintf(zP1,"%d", p->aOp[i].p1);
|
||||||
@@ -878,7 +878,7 @@ int sqliteVdbeExec(
|
|||||||
p->trace = stderr;
|
p->trace = stderr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if( pzErrMsg ){ *pzErrMsg = 0; }
|
/* if( pzErrMsg ){ *pzErrMsg = 0; } */
|
||||||
for(pc=0; rc==SQLITE_OK && pc<p->nOp && pc>=0; pc++){
|
for(pc=0; rc==SQLITE_OK && pc<p->nOp && pc>=0; pc++){
|
||||||
pOp = &p->aOp[pc];
|
pOp = &p->aOp[pc];
|
||||||
if( p->trace ){
|
if( p->trace ){
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
** the WHERE clause of SQL statements. Also found here are subroutines
|
** the WHERE clause of SQL statements. Also found here are subroutines
|
||||||
** to generate VDBE code to evaluate expressions.
|
** to generate VDBE code to evaluate expressions.
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.6 2000/06/05 18:54:47 drh Exp $
|
** $Id: where.c,v 1.7 2000/06/06 13:54:16 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -348,7 +348,7 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
}
|
}
|
||||||
pWInfo->iContinue = cont;
|
pWInfo->iContinue = cont;
|
||||||
if( pushKey && !haveKey ){
|
if( pushKey && !haveKey ){
|
||||||
sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0);
|
sqliteVdbeAddOp(v, OP_Key, base, 0, 0, 0);
|
||||||
}
|
}
|
||||||
sqliteFree(aOrder);
|
sqliteFree(aOrder);
|
||||||
return pWInfo;
|
return pWInfo;
|
||||||
|
@@ -23,7 +23,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 expressions.
|
# focus of this file is testing expressions.
|
||||||
#
|
#
|
||||||
# $Id: expr.test,v 1.4 2000/06/03 19:19:42 drh Exp $
|
# $Id: expr.test,v 1.5 2000/06/06 13:54:16 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -143,6 +143,8 @@ test_expr expr-5.5 {t1='abc', t2='A%C'} {t1 LIKE t2} 1
|
|||||||
test_expr expr-5.6 {t1='abxyzzyc', t2='A%C'} {t1 LIKE t2} 1
|
test_expr expr-5.6 {t1='abxyzzyc', t2='A%C'} {t1 LIKE t2} 1
|
||||||
test_expr expr-5.7 {t1='abxyzzy', t2='A%C'} {t1 LIKE t2} 0
|
test_expr expr-5.7 {t1='abxyzzy', t2='A%C'} {t1 LIKE t2} 0
|
||||||
test_expr expr-5.8 {t1='abxyzzycx', t2='A%C'} {t1 LIKE t2} 0
|
test_expr expr-5.8 {t1='abxyzzycx', t2='A%C'} {t1 LIKE t2} 0
|
||||||
|
test_expr expr-5.9 {t1='abc', t2='xyz'} {t1 NOT LIKE t2} 1
|
||||||
|
test_expr expr-5.10 {t1='abc', t2='ABC'} {t1 NOT LIKE t2} 0
|
||||||
|
|
||||||
test_expr expr-6.1 {t1='abc', t2='xyz'} {t1 GLOB t2} 0
|
test_expr expr-6.1 {t1='abc', t2='xyz'} {t1 GLOB t2} 0
|
||||||
test_expr expr-6.2 {t1='abc', t2='ABC'} {t1 GLOB t2} 0
|
test_expr expr-6.2 {t1='abc', t2='ABC'} {t1 GLOB t2} 0
|
||||||
@@ -154,7 +156,8 @@ test_expr expr-6.7 {t1='abc', t2='a*c'} {t1 GLOB t2} 1
|
|||||||
test_expr expr-6.8 {t1='abxyzzyc', t2='a*c'} {t1 GLOB t2} 1
|
test_expr expr-6.8 {t1='abxyzzyc', t2='a*c'} {t1 GLOB t2} 1
|
||||||
test_expr expr-6.9 {t1='abxyzzy', t2='a*c'} {t1 GLOB t2} 0
|
test_expr expr-6.9 {t1='abxyzzy', t2='a*c'} {t1 GLOB t2} 0
|
||||||
test_expr expr-6.10 {t1='abxyzzycx', t2='a*c'} {t1 GLOB t2} 0
|
test_expr expr-6.10 {t1='abxyzzycx', t2='a*c'} {t1 GLOB t2} 0
|
||||||
|
test_expr expr-6.11 {t1='abc', t2='xyz'} {t1 NOT GLOB t2} 1
|
||||||
|
test_expr expr-6.12 {t1='abc', t2='a?c'} {t1 NOT GLOB t2} 0
|
||||||
|
|
||||||
# The sqliteExprIfFalse and sqliteExprIfTrue routines are only
|
# The sqliteExprIfFalse and sqliteExprIfTrue routines are only
|
||||||
# executed as part of a WHERE clause. Create a table suitable
|
# executed as part of a WHERE clause. Create a table suitable
|
||||||
|
150
test/in.test
Normal file
150
test/in.test
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
# Copyright (c) 1999, 2000 D. Richard Hipp
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public
|
||||||
|
# License along with this library; if not, write to the
|
||||||
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
# Boston, MA 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Author contact information:
|
||||||
|
# drh@hwaci.com
|
||||||
|
# http://www.hwaci.com/drh/
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing the IN and BETWEEN operator.
|
||||||
|
#
|
||||||
|
# $Id: in.test,v 1.1 2000/06/06 13:54:16 drh Exp $
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
# Generate the test data we will need for the first squences of tests.
|
||||||
|
#
|
||||||
|
do_test in-1.0 {
|
||||||
|
set fd [open data1.txt w]
|
||||||
|
for {set i 1} {$i<=10} {incr i} {
|
||||||
|
puts $fd "$i\t[expr {int(pow(2,$i))}]"
|
||||||
|
}
|
||||||
|
close $fd
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t1(a int, b int);
|
||||||
|
COPY t1 FROM 'data1.txt';
|
||||||
|
}
|
||||||
|
file delete -force data1.txt
|
||||||
|
execsql {SELECT count(*) FROM t1}
|
||||||
|
} {10}
|
||||||
|
|
||||||
|
# Do basic testing of BETWEEN.
|
||||||
|
#
|
||||||
|
do_test in-1.1 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b BETWEEN 10 AND 50 ORDER BY a}
|
||||||
|
} {4 5}
|
||||||
|
do_test in-1.2 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b NOT BETWEEN 10 AND 50 ORDER BY a}
|
||||||
|
} {1 2 3 6 7 8 9 10}
|
||||||
|
do_test in-1.3 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b BETWEEN a AND a*5 ORDER BY a}
|
||||||
|
} {1 2 3 4}
|
||||||
|
do_test in-1.4 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b NOT BETWEEN a AND a*5 ORDER BY a}
|
||||||
|
} {5 6 7 8 9 10}
|
||||||
|
do_test in-1.6 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b BETWEEN a AND a*5 OR b=512 ORDER BY a}
|
||||||
|
} {1 2 3 4 9}
|
||||||
|
do_test in-1.7 {
|
||||||
|
execsql {SELECT a+ 100*(a BETWEEN 1 and 3) FROM t1 ORDER BY b}
|
||||||
|
} {101 102 103 4 5 6 7 8 9 10}
|
||||||
|
|
||||||
|
|
||||||
|
# Testing of the IN operator using static lists on the right-hand side.
|
||||||
|
#
|
||||||
|
do_test in-2.1 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b IN (8,12,16,24,32) ORDER BY a}
|
||||||
|
} {3 4 5}
|
||||||
|
do_test in-2.2 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b NOT IN (8,12,16,24,32) ORDER BY a}
|
||||||
|
} {1 2 6 7 8 9 10}
|
||||||
|
do_test in-2.3 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b IN (8,12,16,24,32) OR b=512 ORDER BY a}
|
||||||
|
} {3 4 5 9}
|
||||||
|
do_test in-2.4 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b NOT IN (8,12,16,24,32) OR b=512 ORDER BY a}
|
||||||
|
} {1 2 6 7 8 9 10}
|
||||||
|
do_test in-2.5 {
|
||||||
|
execsql {SELECT a+100*(b IN (8,16,24)) FROM t1 ORDER BY b}
|
||||||
|
} {1 2 103 104 5 6 7 8 9 10}
|
||||||
|
|
||||||
|
do_test in-2.6 {
|
||||||
|
set v [catch {execsql {SELECT a FROM t1 WHERE b IN (b+10,20)}} msg]
|
||||||
|
lappend v $msg
|
||||||
|
} {1 {right-hand side of IN operator must be constant}}
|
||||||
|
do_test in-2.7 {
|
||||||
|
set v [catch {execsql {SELECT a FROM t1 WHERE b IN (max(5,10,b),20)}} msg]
|
||||||
|
lappend v $msg
|
||||||
|
} {1 {right-hand side of IN operator must be constant}}
|
||||||
|
do_test in-2.8 {
|
||||||
|
execsql {SELECT a FROM t1 WHERE b IN (8*2,64/2) ORDER BY b}
|
||||||
|
} {4 5}
|
||||||
|
do_test in-2.9 {
|
||||||
|
set v [catch {execsql {SELECT a FROM t1 WHERE b IN (xyz(5,10),20)}} msg]
|
||||||
|
lappend v $msg
|
||||||
|
} {1 {no such function: xyz}}
|
||||||
|
do_test in-2.10 {
|
||||||
|
set v [catch {execsql {SELECT a FROM t1 WHERE min(0,b IN (a,30))}} msg]
|
||||||
|
lappend v $msg
|
||||||
|
} {1 {right-hand side of IN operator must be constant}}
|
||||||
|
do_test in-2.11 {
|
||||||
|
set v [catch {execsql {SELECT a FROM t1 WHERE c IN (10,20)}} msg]
|
||||||
|
lappend v $msg
|
||||||
|
} {1 {no such field: c}}
|
||||||
|
|
||||||
|
# Testing the IN operator where the right-hand side is a SELECT
|
||||||
|
#
|
||||||
|
do_test in-3.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM t1
|
||||||
|
WHERE b IN (SELECT b FROM t1 WHERE a<5)
|
||||||
|
ORDER BY a
|
||||||
|
}
|
||||||
|
} {1 2 3 4}
|
||||||
|
do_test in-3.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM t1
|
||||||
|
WHERE b IN (SELECT b FROM t1 WHERE a<5) OR b==512
|
||||||
|
ORDER BY a
|
||||||
|
}
|
||||||
|
} {1 2 3 4 9}
|
||||||
|
do_test in-3.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT a + 100*(b IN (SELECT b FROM t1 WHERE a<5)) FROM t1 ORDER BY b
|
||||||
|
}
|
||||||
|
} {101 102 103 104 5 6 7 8 9 10}
|
||||||
|
|
||||||
|
# Make sure the UPDATE and DELETE commands work with IN-SELECT
|
||||||
|
#
|
||||||
|
do_test in-4.1 {
|
||||||
|
execsql {
|
||||||
|
UPDATE t1 SET b=b*2
|
||||||
|
WHERE b IN (SELECT b FROM t1 WHERE a>8)
|
||||||
|
}
|
||||||
|
execsql {SELECT b FROM t1 ORDER BY b}
|
||||||
|
} {2 4 8 16 32 64 128 256 1024 2048}
|
||||||
|
do_test in-4.2 {
|
||||||
|
execsql {
|
||||||
|
DELETE FROM t1 WHERE b IN (SELECT b FROM t1 WHERE a>8)
|
||||||
|
}
|
||||||
|
execsql {SELECT a FROM t1 ORDER BY a}
|
||||||
|
} {1 2 3 4 5 6 7 8}
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
Reference in New Issue
Block a user