-C :-)\s(CVS\s56)
-D 2000-06-06T03:31:22
+C added\sIN\sand\sBETWEEN\soperators\s(CVS\s57)
+D 2000-06-06T13:54:15
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
F src/build.c 6c9454b2e2b866979527fb41b19ad8bc49c27a20
F src/dbbe.c ae8b5d2cdb4fa7dd11313059984be9457fa77f63
F src/dbbe.h a8a46f71238e0f09f3ec08fd9d1c8c7f4cdc49bf
-F src/delete.c e11433c14ed5cc8553cba14296b3baa3c23054bc
-F src/expr.c 278ff688ac72602ad985f4ccadcae665d245b13b
+F src/delete.c 8c733bb82a1b84126116d03dcdccf433c0856f5d
+F src/expr.c 1bedf5f426ee1e1609ef1758985b7ce0581987b8
F src/insert.c 5e69dd70c3f91cf5ec5090f39fd6cd8e135af9bf
F src/main.c 93a7ad14bb5a82ad13ad59da23ef674a94b0c3d6
-F src/parse.y 9c459212441d4786bb011945d6a587568368e202
-F src/select.c d90d577aa7687c860f2ce22dacabdbecb600f609
+F src/parse.y 51ef63a49e73ced4ef3e81d7b1f9fd825d776837
+F src/select.c a1891cfce003a98a57374c01fa5875366c8d9be2
F src/shell.c 5fa24c0bb678782ffe9070128e3e160674f297eb
F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268
-F src/sqliteInt.h 6f31db9b08bc7aec193c84f6f08b0f6c7ce9f270
+F src/sqliteInt.h 821b435a18e1c9d0fddcd7bfeefcf5f3fe925c6e
F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
F src/tokenize.c f190e16ebb82dd60497796022f1e56e2e0527975
-F src/update.c 3f05d5082fd2c34f15d1e4a4db17355ad8807a78
+F src/update.c 18746f920f989b3d19d96c08263c92584823cd35
F src/util.c 33f9baa01e45394ef0cf85361a0e872987884315
-F src/vdbe.c 7d00f9ff05cf1287ee21c2a73d9ba0ebdf07b4b6
+F src/vdbe.c 1ab61ada503b99d6b3224c9d40ed9bac855fe317
F src/vdbe.h 49e0f9c6742860e224cd81d1278059f5d029dfb6
-F src/where.c 6b840a726b06b5122f112e3bc3c142a230af6251
+F src/where.c c9b90e7672f4662a83ef9a27a193020d69fe034c
F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
F test/copy.test 73c3783535db538c8ebd8fffb931376864fc3226
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/insert.test b4c186ffa4b97a231643726f3bcee29815b24eaf
F test/select1.test a0b00df77e85adff75c338e487718c5d31f69e3a
F www/changes.tcl 567cc6066d87460bdedff8e5bbc20f41ddaadf77
F www/index.tcl f8189a7898f6d06307c34047b9d7e00860026e44
F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd
-P bd8b2645cc16759571c8c622dce4752bd35c04cf
-R 712a80d7b1f5a98574f5dc5cddb6e092
+P b52dd82fe32c38c999aef4f07d046d0428336965
+R d1b48bd641877701893f6074a4e397f8
U drh
-Z b053febfd62b58b2d6d5fa997754fe2c
+Z 3b39b6691fb1f454562ec994b26db409
-b52dd82fe32c38c999aef4f07d046d0428336965
\ No newline at end of file
+54d198189b58366e4e40139102bc6de94ac55e18
\ No newline at end of file
** This file contains C code routines that are called by the parser
** 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"
int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */
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
** put in an IdList structure because some of the subroutines will
/* Resolve the field names in all the expressions.
*/
if( pWhere ){
+ sqliteExprResolveInSelect(pParse, pWhere);
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
goto delete_from_cleanup;
}
/* Delete every item identified in the list.
*/
+ base = pParse->nTab;
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){
- sqliteVdbeAddOp(v, OP_Open, i, 1, pIdx->zName, 0);
+ sqliteVdbeAddOp(v, OP_Open, base+i, 1, pIdx->zName, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
if( pTab->pIndex ){
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){
int j;
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
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_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_ListClose, 0, 0, 0, end);
*************************************************************************
** 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"
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
** table fields. Nodes of the form ID.ID or ID resolve into an
/* Case 1: expr IN (SELECT ...)
**
** Generate code to write the results of the select into a temporary
- ** table. The cursor number of the temporary table is stored in
- ** iTable.
+ ** table. The cursor number of the temporary table has already
+ ** been put in iTable by sqliteExprResolveInSelect().
*/
- pExpr->iTable = pParse->nTab++;
- sqliteVdbeAddOp(v, OP_Open, pExpr->iTable, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Open, pExpr->iTable, 1, 0, 0);
if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
}else if( pExpr->pList ){
/* Case 2: expr IN (exprlist)
int i, iSet;
for(i=0; i<pExpr->pList->nExpr; i++){
Expr *pE2 = pExpr->pList->a[i].pExpr;
- if( sqliteExprCheck(pParse, pE2, 0, 0) ){
- return 1;
- }
if( !isConstant(pE2) ){
sqliteSetString(&pParse->zErrMsg,
"right-hand side of IN operator must be constant", 0);
pParse->nErr++;
return 1;
}
+ if( sqliteExprCheck(pParse, pE2, 0, 0) ){
+ return 1;
+ }
}
iSet = pExpr->iTable = pParse->nSet++;
for(i=0; i<pExpr->pList->nExpr; i++){
/* For all else, just recursively walk the tree */
default: {
- if( pExpr->pLeft
- && sqliteExprResolveIds(pParse, pTabList, pExpr->pLeft) ){
+ if( pExpr->pLeft
+ && sqliteExprResolveIds(pParse, pTabList, pExpr->pLeft) ){
return 1;
}
if( pExpr->pRight
- && sqliteExprResolveIds(pParse, pTabList, pExpr->pRight) ){
+ && sqliteExprResolveIds(pParse, pTabList, pExpr->pRight) ){
return 1;
}
if( pExpr->pList ){
}
case TK_IN: {
int addr;
- sqliteVdbeAddOp(v, OP_Integer, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Integer, 1, 0, 0, 0);
sqliteExprCode(pParse, pExpr->pLeft);
addr = sqliteVdbeCurrentAddr(v);
if( pExpr->pSelect ){
}else{
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;
}
case TK_BETWEEN: {
** the parser. Lemon will also generate a header file containing
** 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_type {Token}
ccons ::= PRIMARY KEY sortorder.
{sqliteCreateIndex(pParse,0,0,0,0,0);}
ccons ::= UNIQUE.
-ccons ::= CHECK expr.
+ccons ::= CHECK LP expr RP.
// For the time being, the only constraint we care about is the primary
// key.
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) 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) 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) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);}
expr(A) ::= expr(X) STAR expr(Y). {A = sqliteExpr(TK_STAR, X, Y, 0);}
A = sqliteExpr(TK_BETWEEN, W, 0, 0);
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. {
A = sqliteExpr(TK_IN, X, 0, 0);
A->pList = Y;
A = sqliteExpr(TK_IN, X, 0, 0);
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);
+}
** This file contains C code routines that are called by the parser
** 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"
/* 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++){
if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){
return 1;
*************************************************************************
** 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 "dbbe.h"
int sqliteExprCheck(Parse*, Expr*, int, int*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
+void sqliteExprResolveInSelect(Parse*, Expr*);
** This file contains C code routines that are called by the parser
** 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"
Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */
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 */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th field of the table.
** WHERE clause and in the new values. Also find the field index
** 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( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
goto update_cleanup;
** open every index that needs updating.
*/
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++){
- 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
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 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.
*/
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
pIdx = apIdx[i];
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_DeleteIdx, i+1, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
}
/* Compute a completely new data for this record.
for(i=0; i<pTab->nCol; i++){
j = aXRef[i];
if( j<0 ){
- sqliteVdbeAddOp(v, OP_Field, 0, i, 0, 0);
+ sqliteVdbeAddOp(v, OP_Field, base, i, 0, 0);
}else{
sqliteExprCode(pParse, pChanges->a[j].pExpr);
}
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_PutIdx, i+1, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
}
/* Write the new data back into the database.
*/
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
** all record selected by the WHERE clause have been updated.
** But other routines are also provided to help in building up
** 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 <unistd.h>
azField[3] = zP2;
azField[5] = 0;
rc = SQLITE_OK;
- if( pzErrMsg ){ *pzErrMsg = 0; }
+ /* if( pzErrMsg ){ *pzErrMsg = 0; } */
for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
sprintf(zAddr,"%d",i);
sprintf(zP1,"%d", p->aOp[i].p1);
p->trace = stderr;
}
#endif
- if( pzErrMsg ){ *pzErrMsg = 0; }
+ /* if( pzErrMsg ){ *pzErrMsg = 0; } */
for(pc=0; rc==SQLITE_OK && pc<p->nOp && pc>=0; pc++){
pOp = &p->aOp[pc];
if( p->trace ){
** the WHERE clause of SQL statements. Also found here are subroutines
** 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"
}
pWInfo->iContinue = cont;
if( pushKey && !haveKey ){
- sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Key, base, 0, 0, 0);
}
sqliteFree(aOrder);
return pWInfo;
# This file implements regression tests for SQLite library. The
# 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]
source $testdir/tester.tcl
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.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.2 {t1='abc', t2='ABC'} {t1 GLOB t2} 0
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.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
# executed as part of a WHERE clause. Create a table suitable
--- /dev/null
+# 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