]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
added IN and BETWEEN operators (CVS 57)
authordrh <drh@noemail.net>
Tue, 6 Jun 2000 13:54:14 +0000 (13:54 +0000)
committerdrh <drh@noemail.net>
Tue, 6 Jun 2000 13:54:14 +0000 (13:54 +0000)
FossilOrigin-Name: 54d198189b58366e4e40139102bc6de94ac55e18

12 files changed:
manifest
manifest.uuid
src/delete.c
src/expr.c
src/parse.y
src/select.c
src/sqliteInt.h
src/update.c
src/vdbe.c
src/where.c
test/expr.test
test/in.test [new file with mode: 0644]

index 4041a7b6def2c876df16a5b044f628d7fc4bf662..5d19b5ec922a0cb5a0bd4caa414f18eab2a6c3f1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index 9ac7f98a325bee9289fdf851436032c144fb6b46..247d36057520599657cfb115d13dafe5c8460e7f 100644 (file)
@@ -1 +1 @@
-b52dd82fe32c38c999aef4f07d046d0428336965
\ No newline at end of file
+54d198189b58366e4e40139102bc6de94ac55e18
\ No newline at end of file
index 498c35f22f3d12d7510e2ec0eb22b62f4bcc8748..3f640430645de1c77759711b69d8ef86519dc3b5 100644 (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);
 
index 857d7277c66f2527074c9808b53704830a26dadd..ab07a54f633925eda27ec21e0d732fe47702ee30 100644 (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: {
index 8ac4bddcecc4fb645033e91d10823d01fe01db2c..ab16c8b4cf4b9f18e1f6e843ca2a0e27ac6426a6 100644 (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);
+}
 
 
 
index eb84495cab298297845c938405c273b820b51836..cf2587e9e4d6e6a8a9851d90ae9ccbd2d16923d8 100644 (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;
index 17332b6d37efa3bfef17abaca97b178c61130100..42590f828136dd36d346a8a69796ccf3081067a4 100644 (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*);
index 323c4254aef1302867175a034a2efa4ed09db93a..ca114254188cc9a77bc54533a659d2be81d2c228 100644 (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.
index a563d983b50a199d0783d5f74940d3c18d19c8e3..6d31c1b9b1a041c5860176d5856dad0570f39f38 100644 (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 ){
index 69c7e1612759f0e77933b24753fd49265490e0d9..bfdd2a78293ad7b39db0326d071e88e173310517 100644 (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;
index febe9fb21c90ed3809ee5707886797c2d4778e94..2fb44af6cb86685ddb3e9a469797eb81b57b612f 100644 (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
diff --git a/test/in.test b/test/in.test
new file mode 100644 (file)
index 0000000..c30879e
--- /dev/null
@@ -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