]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Bug fixing in the new integer primary key code. (CVS 334)
authordrh <drh@noemail.net>
Sat, 22 Dec 2001 14:49:24 +0000 (14:49 +0000)
committerdrh <drh@noemail.net>
Sat, 22 Dec 2001 14:49:24 +0000 (14:49 +0000)
FossilOrigin-Name: 29cab124b4f7eae9d9feb60d2f3a2c443fd9b9aa

15 files changed:
manifest
manifest.uuid
src/build.c
src/insert.c
src/parse.y
src/select.c
src/sqlite.h.in
src/update.c
src/util.c
src/vdbe.c
src/vdbe.h
src/where.c
test/func.test
test/intpkey.test
test/where.test

index 84223197e92e02abd13c9ce612f3b01d91a4e10f..4837e0f49078df53a8999ec02db95417c97e5dd8 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Added\ssupport\sfor\sthe\sINTEGER\sPRIMARY\sKEY\scolumn\stype.\s(CVS\s333)
-D 2001-12-21T14:30:43
+C Bug\sfixing\sin\sthe\snew\sinteger\sprimary\skey\scode.\s(CVS\s334)
+D 2001-12-22T14:49:25
 F Makefile.in 352fed589f09dd94347e0bb391d047118ebd6105
 F Makefile.template 0fbf0ee1fe38183d760170a13e91fffec64e73f5
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -21,25 +21,25 @@ F publish.sh cb0f8f7bcb65b8360d0f6668a216a9ac9d5da892
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c c3c36b3b5f07c3efdabf76df9ea423086b1ce142
 F src/btree.h 8767bd4ecf841c4999b7aee6876906bd607546e7
-F src/build.c 36b3bf95bb2f0bdf1d19436b8af5125997c95735
+F src/build.c 6c01002e98204ad2b993d0d043ee56c8c7dc8692
 F src/delete.c f7690efc09ad6a2f1f3f0490e1b0cbb676bb95cf
 F src/expr.c ef1c365c5d558fa691878830501d3c36ed7edb25
 F src/hash.c 6f1a7712ae3aac8351662969aec5693740a2fbf7
 F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
-F src/insert.c 18353ee08ee29241e147187c63ade3669b0af007
+F src/insert.c 8119b42a4858bc4401bd5dfae8e9f28b8205871d
 F src/main.c 00a9f5603e130fc0b1a05f731731c9c99ebdc2dc
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
 F src/os.c 07882cde5c61f26751b8ee76fd84726c1f7e453c
 F src/os.h 00a18e0ae1139a64f1d3ead465ae2b9ff43f3db2
 F src/pager.c dde0eb5bf9af0ac0ff8a4429b2bee2aec2194ec9
 F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe
-F src/parse.y c62f32e332c291612a3a2e856ab48b636c82ee03
+F src/parse.y f050644e7a2586227686e8c1709aa2662b9bcf9c
 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
 F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
-F src/select.c 76a8fafb29935865ddbef263ee90f1398d950d8b
+F src/select.c bb7bf8d6e6154269145158952e041755cc4d9873
 F src/shell.c 407095aaeeae78f42deb3e846b1ad77f8ed3b4ef
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
-F src/sqlite.h.in 934de9112747ad8d8e7d5fec44876246b24ca5a3
+F src/sqlite.h.in a4c11d38d62b1bfbd50a5804edee8ca54c1adc9b
 F src/sqliteInt.h 0b1e8ba2738440e2f06a4e01bb89230492bc203b
 F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
 F src/tclsqlite.c b82e4faeae89fdb7304b3c970979ade299336a1f
@@ -47,11 +47,11 @@ F src/test1.c 41eabe255970ef947263b94145c9b2766bab8675
 F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
 F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
 F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
-F src/update.c 9c266e5c9d1beba74475fd2fb8078dc3d5b23182
-F src/util.c 13dcd870ee0e424f5427e8178480ca1b1833a706
-F src/vdbe.c 49227b52911dcc6811d5c71d36024172feb22195
-F src/vdbe.h cd4c8647051a0c22c0e133c375f1cd17bb8b1e06
-F src/where.c 05d27a01e53c20b8cd10589b7e789b2a64367988
+F src/update.c 6a77d1459d2e829fd9dd244ce8b5ada7ac485317
+F src/util.c 8e9ca72d8288cae39c57c6f397abd14a56b14a38
+F src/vdbe.c f97e2d5bc6db936a2d001e0a1a94102e99ece821
+F src/vdbe.h e5cc6fb13d1905a4339db4d6dba4ab393c0765fa
+F src/where.c 178a908a40cc6d72150a747db69638a97bd86487
 F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
 F test/btree.test 6ab4dc5f595905a276ef588fad3c9236dc07a47b
@@ -60,12 +60,12 @@ F test/btree3.test 9caa9e22491dd8cd8aa36d7ac3b48b089817c895
 F test/copy.test 768e6f1701a07d08090e1ca7f7dcce0a7a72b43e
 F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
 F test/expr.test d350ef5b21cc26599357fb93d15b8a5f7b524769
-F test/func.test 9012f7fc5369422c890e93549aa61d762e0c8bb3
+F test/func.test 51dbe3f8a4c28972751697423e6acc5d6b551df1
 F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
 F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
 F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
 F test/insert2.test d6901ca931e308fea7fca8c95ebe7dc957cc9fc2
-F test/intpkey.test 79be8360e6f0a5506b513f3ab4399da797cd8b3e
+F test/intpkey.test 1f3b36bcf772597809fb445202af77d1d17bb39f
 F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
 F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a
 F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1
@@ -93,7 +93,7 @@ F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9
 F test/unique.test 07776624b82221a80c8b4138ce0dd8b0853bb3ea
 F test/update.test 3cf1ca0565f678063c2dfa9a7948d2d66ae1a778
 F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e
-F test/where.test 20b19475fe894b86b06d2979592260dd16beeb17
+F test/where.test 032d581c3de4893eba33b569e581c46b941bb02a
 F tool/lemon.c bfd036ab9309c7f34e1357d9a065ad137814e741
 F tool/lempar.c 9b604e6a8b3d55c0b9cbcb130a7302fb8bafe2b9
 F tool/memleak.awk 296dfbce7a9ca499b95ce04e30334e64a50052e0
@@ -118,7 +118,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
 F www/tclsqlite.tcl 880ef67cb4f2797b95bf1368fc4e0d8ca0fda956
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P ffbdd43f5de62e7bf81631c83473aca29c3a6c98
-R 56465183b3eaba81097d58ab4fff365b
+P 236a54d289e858a1e0505a20d907a2a40c01b521
+R 5707cbf46f7d3e66441cb3379d943ba9
 U drh
-Z 8ca8d028861bf23d8008c82aec39ab1e
+Z 49b0682a1be06cb764aeb1e921e472ac
index 09d004ee09e15765bbabd32d0d63983dc6d6afe7..dc823da4a426a6d107be5045b5aa0b006e80074e 100644 (file)
@@ -1 +1 @@
-236a54d289e858a1e0505a20d907a2a40c01b521
\ No newline at end of file
+29cab124b4f7eae9d9feb60d2f3a2c443fd9b9aa
\ No newline at end of file
index 1d0654b1bab346e1de4dcec96fad9a108ce05ec8..32e7e5fa42965cfc1213725fa03fc8ae064a8ba9 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.60 2001/12/21 14:30:43 drh Exp $
+** $Id: build.c,v 1.61 2001/12/22 14:49:25 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1314,12 +1314,23 @@ void sqliteCopy(
     }else{
       sqliteVdbeChangeP3(v, addr, "\t", 1);
     }
-    sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
+    if( pTab->iPKey>=0 ){
+      sqliteVdbeAddOp(v, OP_FileColumn, pTab->iPKey, 0);
+      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
+    }else{
+      sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
+    }
     if( pTab->pIndex ){
       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
     }
     for(i=0; i<pTab->nCol; i++){
-      sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
+      if( i==pTab->iPKey ){
+        /* The integer primary key column is filled with NULL since its
+        ** value is always pulled from the record number */
+        sqliteVdbeAddOp(v, OP_String, 0, 0);
+      }else{
+        sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
+      }
     }
     sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
     sqliteVdbeAddOp(v, OP_Put, 0, 0);
index d51a5791f68244587f77f9f4516ad3ee210f6602..f8cb25451b6bec45aebb3ba4226b9cca3b92b91e 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.27 2001/12/21 14:30:43 drh Exp $
+** $Id: insert.c,v 1.28 2001/12/22 14:49:25 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -200,7 +200,7 @@ void sqliteInsert(
     }else{
       sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
     }
-    sqliteVdbeAddOp(v, OP_AddImm, 0, 0);  /* Make sure ROWID is an integer */
+    sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
   }else{
     sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
   }
index 525ed4d3feaf15f4db4ba1ebf212e06fb2d9c9fa..c21b7c8daadb230fbf37d73adbd02bd64ab8953e 100644 (file)
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.40 2001/12/21 14:30:43 drh Exp $
+** @(#) $Id: parse.y,v 1.41 2001/12/22 14:49:25 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -515,13 +515,13 @@ idxlist(A) ::= idxitem(Y).
      {A = sqliteIdListAppend(0,&Y);}
 idxitem(A) ::= ids(X).          {A = X;}
 
-///////////////////////////// The CREATE INDEX command ///////////////////////
+///////////////////////////// The DROP INDEX command /////////////////////////
 //
 
 cmd ::= DROP INDEX ids(X).      {sqliteDropIndex(pParse, &X);}
 
 
-///////////////////////////// The DROP INDEX command /////////////////////////
+///////////////////////////// The COPY command ///////////////////////////////
 //
 cmd ::= COPY ids(X) FROM ids(Y) USING DELIMITERS STRING(Z).
     {sqliteCopy(pParse,&X,&Y,&Z);}
index 2179cb5b4ff912c6fdf3bdfff0239a667296f348..cc6e174bf674603487442a1ea611c38d33c1276f 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.50 2001/12/16 20:05:06 drh Exp $
+** $Id: select.c,v 1.51 2001/12/22 14:49:25 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -258,20 +258,22 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
       sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
       sqliteVdbeCompressSpace(v, addr);
     }else if( p->op==TK_COLUMN && pTabList ){
+      Table *pTab = pTabList->a[p->iTable - pParse->nTab].pTab;
+      int iCol = p->iColumn;
+      if( iCol<0 ) iCol = pTab->iPKey;
+      assert( iCol>=0 && iCol<pTab->nCol );
       if( pTabList->nId>1 || showFullNames ){
         char *zName = 0;
-        Table *pTab = pTabList->a[p->iTable - pParse->nTab].pTab;
         char *zTab;
  
         zTab = pTabList->a[p->iTable - pParse->nTab].zAlias;
         if( showFullNames || zTab==0 ) zTab = pTab->zName;
-        sqliteSetString(&zName, zTab, ".", pTab->aCol[p->iColumn].zName, 0);
+        sqliteSetString(&zName, zTab, ".", pTab->aCol[iCol].zName, 0);
         sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
         sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
         sqliteFree(zName);
       }else{
-        Table *pTab = pTabList->a[0].pTab;
-        char *zName = pTab->aCol[p->iColumn].zName;
+        char *zName = pTab->aCol[iCol].zName;
         sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
         sqliteVdbeChangeP3(v, -1, zName, P3_STATIC);
       }
index 8a139021217af99560a86b769420dabf5a60cd3f..4e2601f06d8deb86e80c43f20d9197e2c6ecb1f2 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.23 2001/11/03 23:57:09 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.24 2001/12/22 14:49:25 drh Exp $
 */
 #ifndef _SQLITE_H_
 #define _SQLITE_H_
@@ -160,6 +160,7 @@ int sqlite_exec(
 #define SQLITE_SCHEMA      17   /* The database schema changed */
 #define SQLITE_TOOBIG      18   /* Too much data for one row of a table */
 #define SQLITE_CONSTRAINT  19   /* Abort due to contraint violation */
+#define SQLITE_MISMATCH    20   /* Data type mismatch */
 
 /* If the parameter to this routine is one of the return value constants
 ** defined above, then this routine returns a constant text string which
index 4c2bbd96b3602f68a6f380dfc3d19a5674a52bc1..7ea634e6c8890f034ece2fce332e6b98d13cdbcc 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.23 2001/12/21 14:30:43 drh Exp $
+** $Id: update.c,v 1.24 2001/12/22 14:49:25 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -215,7 +215,7 @@ void sqliteUpdate(
   if( chngRecno ){
     sqliteVdbeAddOp(v, OP_Pop, 1, 0);
     sqliteExprCode(pParse, pRecnoExpr);
-    sqliteVdbeAddOp(v, OP_AddImm, 0, 0);
+    sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
   }
 
   /* Compute new data for this record.  
index 166660a1e12caab2ab67b11659600fc4f3a51f07..90f9bb97a468dccdb0084fb4915e998a2a8d779d 100644 (file)
@@ -14,7 +14,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.33 2001/11/24 00:31:46 drh Exp $
+** $Id: util.c,v 1.34 2001/12/22 14:49:25 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -1070,6 +1070,7 @@ const char *sqlite_error_string(int rc){
     case SQLITE_SCHEMA:     z = "database schema has changed";           break;
     case SQLITE_TOOBIG:     z = "too much data for one table row";       break;
     case SQLITE_CONSTRAINT: z = "constraint failed";                     break;
+    case SQLITE_MISMATCH:   z = "datatype mismatch";                     break;
     default:                z = "unknown error";                         break;
   }
   return z;
index 88cc6e9c37a3b01e2d57f9906ca325cfd051b595..c8c237609c262cb5165867849695ac9050416b83 100644 (file)
@@ -30,7 +30,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.101 2001/12/21 14:30:43 drh Exp $
+** $Id: vdbe.c,v 1.102 2001/12/22 14:49:25 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -709,6 +709,15 @@ static int isNumber(const char *zNum){
   return *zNum==0;
 }
 
+/*
+** Return TRUE if zNum is an integer.
+*/
+static int isInteger(const char *zNum){
+  if( *zNum=='-' || *zNum=='+' ) zNum++;
+  while( isdigit(*zNum) ) zNum++;
+  return *zNum==0;
+}
+
 /*
 ** Delete a keylist
 */
@@ -860,15 +869,15 @@ static char *zOpName[] = { 0,
   "Goto",              "If",                "Halt",              "ColumnCount",
   "ColumnName",        "Callback",          "NullCallback",      "Integer",
   "String",            "Pop",               "Dup",               "Pull",
-  "Add",               "AddImm",            "Subtract",          "Multiply",
-  "Divide",            "Remainder",         "BitAnd",            "BitOr",
-  "BitNot",            "ShiftLeft",         "ShiftRight",        "AbsValue",
-  "Precision",         "Min",               "Max",               "Like",
-  "Glob",              "Eq",                "Ne",                "Lt",
-  "Le",                "Gt",                "Ge",                "IsNull",
-  "NotNull",           "Negative",          "And",               "Or",
-  "Not",               "Concat",            "Noop",              "Strlen",
-  "Substr",            "Limit",           
+  "MustBeInt",         "Add",               "AddImm",            "Subtract",
+  "Multiply",          "Divide",            "Remainder",         "BitAnd",
+  "BitOr",             "BitNot",            "ShiftLeft",         "ShiftRight",
+  "AbsValue",          "Precision",         "Min",               "Max",
+  "Like",              "Glob",              "Eq",                "Ne",
+  "Lt",                "Le",                "Gt",                "Ge",
+  "IsNull",            "NotNull",           "Negative",          "And",
+  "Or",                "Not",               "Concat",            "Noop",
+  "Strlen",            "Substr",            "Limit",           
 };
 
 /*
@@ -966,10 +975,21 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
 }
 
 /*
-** Convert an integer into a big-endian integer.  In other words,
-** make sure the most significant byte comes first.
+** Convert an integer in between the native integer format and
+** the bigEndian format used as the record number for tables.
+**
+** The bigEndian format (most significant byte first) is used for
+** record numbers so that records will sort into the correct order
+** even though memcmp() is used to compare the keys.  On machines
+** whose native integer format is little endian (ex: i486) the
+** order of bytes is reversed.  On native big-endian machines
+** (ex: Alpha, Sparc, Motorola) the byte order is the same.
+**
+** This function is its own inverse.  In other words
+**
+**         X == byteSwap(byteSwap(X))
 */
-static int bigEndian(int x){
+static int byteSwap(int x){
   union {
      char zBuf[sizeof(int)];
      int i;
@@ -981,6 +1001,15 @@ static int bigEndian(int x){
   return ux.i;
 }
 
+/*
+** When converting from the native format to the key format and back
+** again, in addition to changing the byte order we invert the high-order
+** bit of the most significant byte.  This causes negative numbers to
+** sort before positive numbers in the memcmp() function.
+*/
+#define keyToInt(X)   (byteSwap(X) ^ 0x80000000)
+#define intToKey(X)   (byteSwap((X) ^ 0x80000000))
+
 /*
 ** Code contained within the VERIFY() macro is not needed for correct
 ** execution.  It is there only to catch errors.  So when we compile
@@ -1667,6 +1696,47 @@ case OP_AddImm: {
   break;
 }
 
+/* Opcode: MustBeInt  * P2 *
+** 
+** Force the top of the stack to be an integer.  If the top of the
+** stack is not an integer and cannot be comverted into an integer
+** with out data loss, then jump immediately to P2, or if P2==0
+** raise an SQLITE_MISMATCH exception.
+*/
+case OP_MustBeInt: {
+  int tos = p->tos;
+  VERIFY( if( tos<0 ) goto not_enough_stack; )
+  if( aStack[tos].flags & STK_Int ){
+    /* Do nothing */
+  }else if( aStack[tos].flags & STK_Real ){
+    int i = aStack[tos].r;
+    double r = i;
+    if( r!=aStack[tos].r ){
+      goto mismatch;
+    }
+    aStack[tos].i = i;
+  }else if( aStack[tos].flags & STK_Str ){
+    if( !isInteger(zStack[tos]) ){
+      goto mismatch;
+    }
+    p->aStack[tos].i = atoi(p->zStack[tos]);
+  }else{
+    goto mismatch;
+  }
+  Release(p, tos);
+  p->aStack[tos].flags = STK_Int;
+  break;
+
+mismatch:
+  if( pOp->p2==0 ){
+    rc = SQLITE_MISMATCH;
+    goto abort_due_to_error;
+  }else{
+    pc = pOp->p2 - 1;
+  }
+  break;
+}
+
 /* Opcode: Eq * P2 *
 **
 ** Pop the top two elements from the stack.  If they are equal, then
@@ -2155,7 +2225,7 @@ case OP_MakeKey: {
   if( addRowid ){
     u32 iKey;
     Integerify(p, p->tos-nField);
-    iKey = bigEndian(aStack[p->tos-nField].i);
+    iKey = intToKey(aStack[p->tos-nField].i);
     memcpy(&zNewKey[j], &iKey, sizeof(u32));
   }
   if( pOp->p2==0 ) PopStack(p, nField+addRowid);
@@ -2540,10 +2610,10 @@ case OP_MoveTo: {
   if( i>=0 && i<p->nCursor && (pC = &p->aCsr[i])->pCursor!=0 ){
     int res;
     if( aStack[tos].flags & STK_Int ){
-      int iKey = bigEndian(aStack[tos].i);
+      int iKey = intToKey(aStack[tos].i);
       sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res);
       pC->lastRecno = aStack[tos].i;
-      pC->recnoIsValid = 1;
+      pC->recnoIsValid = res==0;
     }else{
       if( Stringify(p, tos) ) goto no_mem;
       sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res);
@@ -2606,7 +2676,7 @@ case OP_Found: {
   if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){
     int res, rx;
     if( aStack[tos].flags & STK_Int ){
-      int iKey = bigEndian(aStack[tos].i);
+      int iKey = intToKey(aStack[tos].i);
       rx = sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res);
     }else{
       if( Stringify(p, tos) ) goto no_mem;
@@ -2665,7 +2735,7 @@ case OP_NewRecno: {
         v += sqliteRandomByte() + 1;
       }
       if( v==0 ) continue;
-      x = bigEndian(v);
+      x = intToKey(v);
       rx = sqliteBtreeMoveto(pC->pCursor, &x, sizeof(int), &res);
       cnt++;
     }while( cnt<1000 && rx==SQLITE_OK && res==0 );
@@ -2707,7 +2777,7 @@ case OP_Put: {
       zKey = zStack[nos];
     }else{
       nKey = sizeof(int);
-      iKey = bigEndian(aStack[nos].i);
+      iKey = intToKey(aStack[nos].i);
       zKey = (char*)&iKey;
     }
     if( pOp->p2 ){
@@ -2875,7 +2945,7 @@ case OP_Recno: {
       v = p->aCsr[i].lastRecno;
     }else{
       sqliteBtreeKey(pCrsr, 0, sizeof(u32), (char*)&v);
-      v = bigEndian(v);
+      v = keyToInt(v);
     }
     aStack[tos].i = v;
     aStack[tos].flags = STK_Int;
@@ -3060,7 +3130,7 @@ case OP_IdxRecno: {
     int sz;
     sqliteBtreeKeySize(pCrsr, &sz);
     sqliteBtreeKey(pCrsr, sz - sizeof(u32), sizeof(u32), (char*)&v);
-    v = bigEndian(v);
+    v = keyToInt(v);
     aStack[tos].i = v;
     aStack[tos].flags = STK_Int;
   }
index 2c21dbbe1443fa21dbfceb47c93a058e09d2dd95..4f48f23a0750d87263b057ad9b8842d9c1854538 100644 (file)
@@ -15,7 +15,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.36 2001/11/08 00:45:22 drh Exp $
+** $Id: vdbe.h,v 1.37 2001/12/22 14:49:26 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -158,45 +158,46 @@ typedef struct VdbeOp VdbeOp;
 #define OP_Pop                74
 #define OP_Dup                75
 #define OP_Pull               76
-
-#define OP_Add                77
-#define OP_AddImm             78
-#define OP_Subtract           79
-#define OP_Multiply           80
-#define OP_Divide             81
-#define OP_Remainder          82
-#define OP_BitAnd             83
-#define OP_BitOr              84
-#define OP_BitNot             85
-#define OP_ShiftLeft          86
-#define OP_ShiftRight         87
-#define OP_AbsValue           88
-#define OP_Precision          89
-#define OP_Min                90
-#define OP_Max                91
-#define OP_Like               92
-#define OP_Glob               93
-#define OP_Eq                 94
-#define OP_Ne                 95
-#define OP_Lt                 96
-#define OP_Le                 97
-#define OP_Gt                 98
-#define OP_Ge                 99
-#define OP_IsNull            100
-#define OP_NotNull           101
-#define OP_Negative          102
-#define OP_And               103
-#define OP_Or                104
-#define OP_Not               105
-#define OP_Concat            106
-#define OP_Noop              107
-
-#define OP_Strlen            108
-#define OP_Substr            109
-
-#define OP_Limit             110
-
-#define OP_MAX               110
+#define OP_MustBeInt          77
+
+#define OP_Add                78
+#define OP_AddImm             79
+#define OP_Subtract           80
+#define OP_Multiply           81
+#define OP_Divide             82
+#define OP_Remainder          83
+#define OP_BitAnd             84
+#define OP_BitOr              85
+#define OP_BitNot             86
+#define OP_ShiftLeft          87
+#define OP_ShiftRight         88
+#define OP_AbsValue           89
+#define OP_Precision          90
+#define OP_Min                91
+#define OP_Max                92
+#define OP_Like               93
+#define OP_Glob               94
+#define OP_Eq                 95
+#define OP_Ne                 96
+#define OP_Lt                 97
+#define OP_Le                 98
+#define OP_Gt                 99
+#define OP_Ge                100
+#define OP_IsNull            101
+#define OP_NotNull           102
+#define OP_Negative          103
+#define OP_And               104
+#define OP_Or                105
+#define OP_Not               106
+#define OP_Concat            107
+#define OP_Noop              108
+
+#define OP_Strlen            109
+#define OP_Substr            110
+
+#define OP_Limit             111
+
+#define OP_MAX               111
 
 /*
 ** Prototypes for the VDBE interface.  See comments on the implementation
index 89a7258c907f633f57637c469438921c2fea45d5..54a2cddcbdbfde74bcb4d2c824dc8310da33ea75 100644 (file)
@@ -13,7 +13,7 @@
 ** the WHERE clause of SQL statements.  Also found here are subroutines
 ** to generate VDBE code to evaluate expressions.
 **
-** $Id: where.c,v 1.28 2001/11/12 13:51:43 drh Exp $
+** $Id: where.c,v 1.29 2001/12/22 14:49:26 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -167,6 +167,9 @@ WhereInfo *sqliteWhereBegin(
   int base;            /* First available index for OP_Open opcodes */
   int nCur;            /* Next unused cursor number */
   int aDirect[32];     /* If TRUE, then index this table using ROWID */
+  int iDirectEq[32];   /* Term of the form ROWID==X for the N-th table */
+  int iDirectLt[32];   /* Term of the form ROWID<X or ROWID<=X */
+  int iDirectGt[32];   /* Term of the form ROWID>X or ROWID>=X */
   ExprInfo aExpr[50];  /* The WHERE clause is divided into these expressions */
 
   /* Allocate space for aOrder[] and aiMem[]. */
@@ -218,8 +221,13 @@ WhereInfo *sqliteWhereBegin(
   /* Figure out what index to use (if any) for each nested loop.
   ** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested
   ** loop where i==0 is the outer loop and i==pTabList->nId-1 is the inner
-  ** loop.  If the expression uses only the ROWID field, then set
-  ** aDirect[i] to 1.
+  ** loop. 
+  **
+  ** If terms exist that use the ROWID of any table, then set the
+  ** iDirectEq[], iDirectLt[], or iDirectGt[] elements for that table
+  ** to the index of the term containing the ROWID.  We always prefer
+  ** to use a ROWID which can directly access a table rather than an
+  ** index which requires two accesses.
   **
   ** Actually, if there are more than 32 tables in the join, only the
   ** first 32 tables are candidates for indices.
@@ -234,23 +242,37 @@ WhereInfo *sqliteWhereBegin(
     int bestScore = 0;
 
     /* Check to see if there is an expression that uses only the
-    ** ROWID field of this table.  If so, set aDirect[i] to 1.
-    ** If not, set aDirect[i] to 0.
+    ** ROWID field of this table.  For terms of the form ROWID==expr
+    ** set iDirectEq[i] to the index of the term.  For terms of the
+    ** form ROWID<expr or ROWID<=expr set iDirectLt[i] to the term index.
+    ** For terms like ROWID>expr or ROWID>=expr set iDirectGt[i].
     */
-    aDirect[i] = 0;
+    iDirectEq[i] = -1;
+    iDirectLt[i] = -1;
+    iDirectGt[i] = -1;
     for(j=0; j<nExpr; j++){
       if( aExpr[j].idxLeft==idx && aExpr[j].p->pLeft->iColumn<0
             && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
-        aDirect[i] = 1;
-        break;
+        switch( aExpr[j].p->op ){
+          case TK_EQ: iDirectEq[i] = j; break;
+          case TK_LE:
+          case TK_LT: iDirectLt[i] = j; break;
+          case TK_GE:
+          case TK_GT: iDirectGt[i] = j;  break;
+        }
       }
       if( aExpr[j].idxRight==idx && aExpr[j].p->pRight->iColumn<0
             && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
-        aDirect[i] = 1;
-        break;
+        switch( aExpr[j].p->op ){
+          case TK_EQ: iDirectEq[i] = j;  break;
+          case TK_LE:
+          case TK_LT: iDirectGt[i] = j;  break;
+          case TK_GE:
+          case TK_GT: iDirectLt[i] = j;  break;
+        }
       }
     }
-    if( aDirect[i] ){
+    if( iDirectEq[i]>=0 ){
       loopMask |= 1<<idx;
       pWInfo->a[i].pIdx = 0;
       continue;
@@ -394,43 +416,27 @@ WhereInfo *sqliteWhereBegin(
   for(i=0; i<pTabList->nId; i++){
     int j, k;
     int idx = aOrder[i];
-    int goDirect;
     Index *pIdx;
     WhereLevel *pLevel = &pWInfo->a[i];
 
-    if( i<ARRAYSIZE(aDirect) ){
-      pIdx = pLevel->pIdx;
-      goDirect = aDirect[i];
-    }else{
-      pIdx = 0;
-      goDirect = 0;
-    }
-
-    if( goDirect ){
-      /* Case 1:  We can directly reference a single row using the ROWID field.
+    pIdx = pLevel->pIdx;
+    if( i<ARRAYSIZE(iDirectEq) && iDirectEq[i]>=0 ){
+      /* Case 1:  We can directly reference a single row using an
+      **          equality comparison against the ROWID field.
       */
-      for(k=0; k<nExpr; k++){
-        if( aExpr[k].p==0 ) continue;
-        if( aExpr[k].idxLeft==idx 
-           && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
-           && aExpr[k].p->pLeft->iColumn<0
-        ){
-          sqliteExprCode(pParse, aExpr[k].p->pRight);
-          aExpr[k].p = 0;
-          break;
-        }
-        if( aExpr[k].idxRight==idx 
-           && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
-           && aExpr[k].p->pRight->iColumn<0
-        ){
-          sqliteExprCode(pParse, aExpr[k].p->pLeft);
-          aExpr[k].p = 0;
-          break;
-        }
+      k = iDirectEq[i];
+      assert( k<nExpr );
+      assert( aExpr[k].p!=0 );
+      assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx );
+      if( aExpr[k].idxLeft==idx ){
+        sqliteExprCode(pParse, aExpr[k].p->pRight);
+      }else{
+        sqliteExprCode(pParse, aExpr[k].p->pLeft);
       }
-      sqliteVdbeAddOp(v, OP_AddImm, 0, 0);
+      aExpr[k].p = 0;
       brk = pLevel->brk = sqliteVdbeMakeLabel(v);
       cont = pLevel->cont = brk;
+      sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk);
       if( i==pTabList->nId-1 && pushKey ){
         haveKey = 1;
       }else{
@@ -438,22 +444,8 @@ WhereInfo *sqliteWhereBegin(
         haveKey = 0;
       }
       pLevel->op = OP_Noop;
-    }else if( pIdx==0 ){
-      /* Case 2:  There was no usable index.  We must do a complete
-      **          scan of the entire database table.
-      */
-      int start;
-
-      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
-      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
-      sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk);
-      start = sqliteVdbeCurrentAddr(v);
-      pLevel->op = OP_Next;
-      pLevel->p1 = base+idx;
-      pLevel->p2 = start;
-      haveKey = 0;
-    }else if( pLevel->score%4==0 ){
-      /* Case 3:  All index constraints are equality operators.
+    }else if( pIdx!=0 && pLevel->score%4==0 ){
+      /* Case 2:  All index constraints are equality operators.
       */
       int start;
       int testOp;
@@ -507,8 +499,79 @@ WhereInfo *sqliteWhereBegin(
       pLevel->op = OP_Next;
       pLevel->p1 = pLevel->iCur;
       pLevel->p2 = start;
+    }else if( i<ARRAYSIZE(iDirectLt) && (iDirectLt[i]>=0 || iDirectGt[i]>=0) ){
+      /* Case 3:  We have an inequality comparison against the ROWID field.
+      */
+      int testOp = OP_Noop;
+      int start;
+
+      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
+      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
+      if( iDirectGt[i]>=0 ){
+        k = iDirectGt[i];
+        assert( k<nExpr );
+        assert( aExpr[k].p!=0 );
+        assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx );
+        if( aExpr[k].idxLeft==idx ){
+          sqliteExprCode(pParse, aExpr[k].p->pRight);
+        }else{
+          sqliteExprCode(pParse, aExpr[k].p->pLeft);
+        }
+        sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk);
+        if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ){
+          sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
+        }
+        sqliteVdbeAddOp(v, OP_MoveTo, base+idx, brk);
+        aExpr[k].p = 0;
+      }else{
+        sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk);
+      }
+      if( iDirectLt[i]>=0 ){
+        k = iDirectLt[i];
+        assert( k<nExpr );
+        assert( aExpr[k].p!=0 );
+        assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx );
+        if( aExpr[k].idxLeft==idx ){
+          sqliteExprCode(pParse, aExpr[k].p->pRight);
+        }else{
+          sqliteExprCode(pParse, aExpr[k].p->pLeft);
+        }
+        sqliteVdbeAddOp(v, OP_MustBeInt, 0, sqliteVdbeCurrentAddr(v)+1);
+        pLevel->iMem = pParse->nMem++;
+        sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
+        if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ){
+          testOp = OP_Ge;
+        }else{
+          testOp = OP_Gt;
+        }
+        aExpr[k].p = 0;
+      }
+      start = sqliteVdbeCurrentAddr(v);
+      pLevel->op = OP_Next;
+      pLevel->p1 = base+idx;
+      pLevel->p2 = start;
+      if( testOp!=OP_Noop ){
+        sqliteVdbeAddOp(v, OP_Recno, base+idx, 0);
+        sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
+        sqliteVdbeAddOp(v, testOp, 0, brk);
+      }
+      haveKey = 0;
+    }else if( pIdx==0 ){
+      /* Case 4:  There was no usable index.  We must do a complete
+      **          scan of the entire database table.
+      */
+      int start;
+
+      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
+      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
+      sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk);
+      start = sqliteVdbeCurrentAddr(v);
+      pLevel->op = OP_Next;
+      pLevel->p1 = base+idx;
+      pLevel->p2 = start;
+      haveKey = 0;
     }else{
-      /* Case 4: The contraints on the right-most index field are
+      /* Case 5: The contraints on the right-most index field are
       **         inequalities.
       */
       int score = pLevel->score;
index 884b599fbed0a64f619164ecfb2feaffe75c8371..066a00fc6b0883b288dd762356f00681983e26bb 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing built-in functions.
 #
-# $Id: func.test,v 1.6 2001/10/20 12:30:12 drh Exp $
+# $Id: func.test,v 1.7 2001/12/22 14:49:26 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -146,8 +146,8 @@ do_test func-4.5 {
   catchsql {SELECT round(a,b,c) FROM t1}
 } {1 {too many arguments to function round()}}
 do_test func-4.6 {
-  catchsql {SELECT round(b,2) FROM t1}
-} {0 {2.00 1.23 -2.00}}
+  catchsql {SELECT round(b,2) FROM t1 ORDER BY b}
+} {0 {-2.00 1.23 2.00}}
 do_test func-4.7 {
   catchsql {SELECT round(b,0) FROM t1 ORDER BY a}
 } {0 {2 1 -2}}
index 9868b7326c0217ff1e2f8eb28b574d0f62f84e6c..abee972daf2c57e3ca8e6603f5cccd6aef6ce088 100644 (file)
@@ -13,7 +13,7 @@
 # This file implements tests for the special processing associated
 # with INTEGER PRIMARY KEY columns.
 #
-# $Id: intpkey.test,v 1.1 2001/12/21 14:30:44 drh Exp $
+# $Id: intpkey.test,v 1.2 2001/12/22 14:49:26 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -121,5 +121,250 @@ do_test intpkey-1.12 {
   }
 } {7 one two}
 
+# Try to insert a non-integer value into the primary key field.  This
+# should result in a data type mismatch.
+#
+do_test intpkey-1.13 {
+  set r [catch {execsql {
+    INSERT INTO t1 VALUES('x','y','z');
+  }} msg]
+  lappend r $msg
+} {1 {datatype mismatch}}
+do_test intpkey-1.14 {
+  set r [catch {execsql {
+    INSERT INTO t1 VALUES(3.4,'y','z');
+  }} msg]
+  lappend r $msg
+} {1 {datatype mismatch}}
+do_test intpkey-1.15 {
+  set r [catch {execsql {
+    INSERT INTO t1 VALUES(-3,'y','z');
+  }} msg]
+  lappend r $msg
+} {0 {}}
+do_test intpkey-1.16 {
+  execsql {SELECT * FROM t1}
+} {-3 y z 5 hello world 6 second entry 7 one two}
+
+#### INDICES
+# Check to make sure indices work correctly with integer primary keys
+#
+do_test intpkey-2.1 {
+  execsql {
+    CREATE INDEX i1 ON t1(b);
+    SELECT * FROM t1 WHERE b=='y'
+  }
+} {-3 y z}
+do_test intpkey-2.1.1 {
+  execsql {
+    SELECT * FROM t1 WHERE b=='y' AND rowid<0
+  }
+} {-3 y z}
+do_test intpkey-2.1.2 {
+  execsql {
+    SELECT * FROM t1 WHERE b=='y' AND rowid<0 AND rowid>=-20
+  }
+} {-3 y z}
+do_test intpkey-2.1.3 {
+  execsql {
+    SELECT * FROM t1 WHERE b>='y'
+  }
+} {-3 y z}
+do_test intpkey-2.1.4 {
+  execsql {
+    SELECT * FROM t1 WHERE b>='y' AND rowid<10
+  }
+} {-3 y z}
+do_test intpkey-2.2 {
+  execsql {
+    UPDATE t1 SET a=8 WHERE b=='y';
+    SELECT * FROM t1 WHERE b=='y';
+  }
+} {8 y z}
+do_test intpkey-2.3 {
+  execsql {
+    SELECT rowid, * FROM t1;
+  }
+} {5 5 hello world 6 6 second entry 7 7 one two 8 8 y z}
+do_test intpkey-2.4 {
+  execsql {
+    SELECT rowid, * FROM t1 WHERE b<'second'
+  }
+} {5 5 hello world 7 7 one two}
+do_test intpkey-2.4.1 {
+  execsql {
+    SELECT rowid, * FROM t1 WHERE 'second'>b
+  }
+} {5 5 hello world 7 7 one two}
+do_test intpkey-2.4.2 {
+  execsql {
+    SELECT rowid, * FROM t1 WHERE 8>rowid AND 'second'>b
+  }
+} {5 5 hello world 7 7 one two}
+do_test intpkey-2.4.3 {
+  execsql {
+    SELECT rowid, * FROM t1 WHERE 8>rowid AND 'second'>b AND 0<rowid
+  }
+} {5 5 hello world 7 7 one two}
+do_test intpkey-2.5 {
+  execsql {
+    SELECT rowid, * FROM t1 WHERE b>'a'
+  }
+} {5 5 hello world 7 7 one two 6 6 second entry 8 8 y z}
+do_test intpkey-2.6 {
+  execsql {
+    DELETE FROM t1 WHERE rowid=7;
+    SELECT * FROM t1 WHERE b>'a';
+  }
+} {5 hello world 6 second entry 8 y z}
+do_test intpkey-2.7 {
+  execsql {
+    UPDATE t1 SET a=-4 WHERE rowid=8;
+    SELECT * FROM t1 WHERE b>'a';
+  }
+} {5 hello world 6 second entry -4 y z}
+do_test intpkey-2.7 {
+  execsql {
+    SELECT * FROM t1
+  }
+} {-4 y z 5 hello world 6 second entry}
+
+# Do an SQL statement.  Append the search count to the end of the result.
+#
+proc count sql {
+  set ::sqlite_search_count 0
+  return [concat [execsql $sql] $::sqlite_search_count]
+}
+
+# Create indices that include the integer primary key as one of their
+# columns.
+#
+do_test intpkey-3.1 {
+  execsql {
+    CREATE INDEX i2 ON t1(a);
+  }
+} {}
+do_test intpkey-3.2 {
+  count {
+    SELECT * FROM t1 WHERE a=5;
+  }
+} {5 hello world 0}
+do_test intpkey-3.3 {
+  count {
+    SELECT * FROM t1 WHERE a>4 AND a<6;
+  }
+} {5 hello world 2}
+do_test intpkey-3.4 {
+  count {
+    SELECT * FROM t1 WHERE b>='hello' AND b<'hello2';
+  }
+} {5 hello world 3}
+do_test intpkey-3.5 {
+  execsql {
+    CREATE INDEX i3 ON t1(c,a);
+  }
+} {}
+do_test intpkey-3.6 {
+  count {
+    SELECT * FROM t1 WHERE c=='world';
+  }
+} {5 hello world 3}
+do_test intpkey-3.7 {
+  execsql {INSERT INTO t1 VALUES(11,'hello','world')}
+  count {
+    SELECT * FROM t1 WHERE c=='world';
+  }
+} {5 hello world 11 hello world 5}
+do_test intpkey-3.8 {
+  count {
+    SELECT * FROM t1 WHERE c=='world' AND a>7;
+  }
+} {11 hello world 5}
+do_test intpkey-3.9 {
+  count {
+    SELECT * FROM t1 WHERE 7<a;
+  }
+} {11 hello world 1}
+
+# Test inequality constraints on integer primary keys and rowids
+#
+do_test intpkey-4.1 {
+  count {
+    SELECT * FROM t1 WHERE 11=rowid
+  }
+} {11 hello world 0}
+do_test intpkey-4.2 {
+  count {
+    SELECT * FROM t1 WHERE 11=rowid AND b=='hello'
+  }
+} {11 hello world 0}
+do_test intpkey-4.3 {
+  count {
+    SELECT * FROM t1 WHERE 11=rowid AND b=='hello' AND c IS NOT NULL;
+  }
+} {11 hello world 0}
+do_test intpkey-4.4 {
+  count {
+    SELECT * FROM t1 WHERE rowid==11
+  }
+} {11 hello world 0}
+do_test intpkey-4.5 {
+  count {
+    SELECT * FROM t1 WHERE oid==11 AND b=='hello'
+  }
+} {11 hello world 0}
+do_test intpkey-4.6 {
+  count {
+    SELECT * FROM t1 WHERE a==11 AND b=='hello' AND c IS NOT NULL;
+  }
+} {11 hello world 0}
+
+do_test intpkey-4.7 {
+  count {
+    SELECT * FROM t1 WHERE 8<rowid;
+  }
+} {11 hello world 1}
+do_test intpkey-4.8 {
+  count {
+    SELECT * FROM t1 WHERE 8<rowid AND 11>=oid;
+  }
+} {11 hello world 1}
+do_test intpkey-4.9 {
+  count {
+    SELECT * FROM t1 WHERE 11<=_rowid_ AND 12>=a;
+  }
+} {11 hello world 1}
+do_test intpkey-4.10 {
+  count {
+    SELECT * FROM t1 WHERE 0>=_rowid_;
+  }
+} {-4 y z 1}
+do_test intpkey-4.11 {
+  count {
+    SELECT * FROM t1 WHERE a<0;
+  }
+} {-4 y z 1}
+do_test intpkey-4.12 {
+  count {
+    SELECT * FROM t1 WHERE a<0 AND a>10;
+  }
+} {1}
+
+# Make sure it is OK to insert a rowid of 0
+#
+do_test intpkey-5.1 {
+  execsql {
+    INSERT INTO t1 VALUES(0,'zero','entry');
+  }
+  count {
+    SELECT * FROM t1 WHERE a=0;
+  }
+} {0 zero entry 0}
+do_test intpkey=5.2 {
+  execsql {
+    SELECT rowid, a FROM t1
+  }
+} {-4 -4 0 0 5 5 6 6 11 11}
+
 
 finish_test
index 85096f7c15008d7c56be883e602eb3026c123cfd..4ab658b14476afc44ad4ada7baab6d93239c2bc9 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the use of indices in WHERE clases.
 #
-# $Id: where.test,v 1.4 2001/11/08 00:45:22 drh Exp $
+# $Id: where.test,v 1.5 2001/12/22 14:49:26 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -167,7 +167,7 @@ do_test where-1.36 {
   count {SELECT w FROM t1 WHERE w<=3}
 } {1 2 3 6}
 do_test where-1.37 {
-  count {SELECT w FROM t1 WHERE w+1<=4}
+  count {SELECT w FROM t1 WHERE w+1<=4 ORDER BY w}
 } {1 2 3 99}