added IN and BETWEEN operators (CVS 57)

FossilOrigin-Name: 54d198189b58366e4e40139102bc6de94ac55e18
This commit is contained in:
drh 2000-06-06 13:54:14 +00:00
parent cfab11bcba
commit 4794b98035
12 changed files with 286 additions and 55 deletions

View File

@ -1,5 +1,5 @@
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
@ -9,26 +9,27 @@ F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
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
@ -48,7 +49,7 @@ F www/c_interface.tcl 8867d76ddd416d2fbd41e4cb3de8efa9cef105a5
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

View File

@ -1 +1 @@
b52dd82fe32c38c999aef4f07d046d0428336965
54d198189b58366e4e40139102bc6de94ac55e18

View File

@ -24,7 +24,7 @@
** 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"
@ -43,6 +43,7 @@ void sqliteDeleteFrom(
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
@ -70,6 +71,7 @@ void sqliteDeleteFrom(
/* Resolve the field names in all the expressions.
*/
if( pWhere ){
sqliteExprResolveInSelect(pParse, pWhere);
if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
goto delete_from_cleanup;
}
@ -102,27 +104,28 @@ void sqliteDeleteFrom(
/* 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);

View File

@ -23,7 +23,7 @@
*************************************************************************
** 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"
@ -52,6 +52,38 @@ static int isConstant(Expr *p){
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
@ -186,11 +218,10 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
/* 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)
@ -201,15 +232,15 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
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++){
@ -248,12 +279,12 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
/* 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 ){
@ -512,7 +543,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
}
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 ){
@ -520,7 +551,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
}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: {

View File

@ -26,7 +26,7 @@
** 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}
@ -108,7 +108,7 @@ ccons ::= NOT NULL.
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.
@ -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) 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);}
@ -321,6 +329,13 @@ expr(A) ::= expr(W) BETWEEN expr(X) AND expr(Y). {
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;
@ -329,6 +344,16 @@ expr(A) ::= expr(X) IN LP select(Y) RP. {
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);
}

View File

@ -24,7 +24,7 @@
** 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"
@ -165,6 +165,15 @@ int sqliteSelect(
/* 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;

View File

@ -23,7 +23,7 @@
*************************************************************************
** 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"
@ -314,3 +314,4 @@ char *sqliteTableNameFromToken(Token*);
int sqliteExprCheck(Parse*, Expr*, int, int*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
void sqliteExprResolveInSelect(Parse*, Expr*);

View File

@ -24,7 +24,7 @@
** 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"
@ -45,6 +45,7 @@ void sqliteUpdate(
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.
@ -80,6 +81,12 @@ void sqliteUpdate(
** 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;
@ -155,9 +162,10 @@ void sqliteUpdate(
** 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
@ -168,7 +176,7 @@ void sqliteUpdate(
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.
*/
@ -176,10 +184,10 @@ void sqliteUpdate(
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.
@ -187,7 +195,7 @@ void sqliteUpdate(
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);
}
@ -202,13 +210,13 @@ void sqliteUpdate(
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.

View File

@ -41,7 +41,7 @@
** 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>
@ -795,7 +795,7 @@ int sqliteVdbeList(
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);
@ -878,7 +878,7 @@ int sqliteVdbeExec(
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 ){

View File

@ -25,7 +25,7 @@
** 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"
@ -348,7 +348,7 @@ WhereInfo *sqliteWhereBegin(
}
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;

View File

@ -23,7 +23,7 @@
# 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
@ -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.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
@ -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.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

150
test/in.test Normal file
View 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