]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix comparison functions so that they are consistent with the order
authordrh <drh@noemail.net>
Sat, 24 Nov 2001 00:31:46 +0000 (00:31 +0000)
committerdrh <drh@noemail.net>
Sat, 24 Nov 2001 00:31:46 +0000 (00:31 +0000)
of elements in indices.  Fix the handling of large integers. (CVS 317)

FossilOrigin-Name: fc2aae04578c305304a45ec6b76d3ab216cc7526

14 files changed:
Makefile.in
Makefile.template
VERSION
manifest
manifest.uuid
src/expr.c
src/shell.c
src/util.c
test/bigrow.test
test/expr.test
test/index.test
www/changes.tcl
www/faq.tcl [new file with mode: 0644]
www/index.tcl

index 3840766f800fb27f53a56e3d951a1140b49b15f6..d43b85453f7a6f2d7c19a5152c95cfc0c4295c0a 100644 (file)
@@ -270,6 +270,9 @@ tclsqlite.html:     $(TOP)/www/tclsqlite.tcl
 speed.html:    $(TOP)/www/speed.tcl
        tclsh $(TOP)/www/speed.tcl >speed.html
 
+faq.html:      $(TOP)/www/faq.tcl
+       tclsh $(TOP)/www/faq.tcl >faq.html
+
 download.html: $(TOP)/www/download.tcl
        tclsh $(TOP)/www/download.tcl >download.html
 
@@ -290,7 +293,8 @@ DOC = \
   mingw.html \
   tclsqlite.html \
   download.html \
-  speed.html
+  speed.html \
+  faq.html
 
 doc:   $(DOC)
        mkdir -p doc
index e9486371dca763aaebaaf93af2efc849393a6903..ae3cd7c2ade69643220cefce5f9cb5fed45a61a0 100644 (file)
@@ -329,6 +329,9 @@ tclsqlite.html:     $(TOP)/www/tclsqlite.tcl
 speed.html:    $(TOP)/www/speed.tcl
        tclsh $(TOP)/www/speed.tcl >speed.html
 
+faq.html:      $(TOP)/www/faq.tcl
+       tclsh $(TOP)/www/faq.tcl >faq.html
+
 download.html: $(TOP)/www/download.tcl
        tclsh $(TOP)/www/download.tcl >download.html
 
@@ -349,7 +352,8 @@ DOC = \
   mingw.html \
   tclsqlite.html \
   download.html \
-  speed.html
+  speed.html \
+  faq.html
 
 doc:   $(DOC)
        mkdir -p doc
diff --git a/VERSION b/VERSION
index eca07e4c1a8cbc603e5d5c2885dc0f0f9b1eef8d..ac2cdeba0137a6c2cbca06867b7ab994a913e294 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.1.2
+2.1.3
index b8ea46634f10b25d849aaf7ff79db48e39b73aea..2c5187780af8f3e34f707c78df80756156a443b3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Version\s2.1.2\s(CVS\s459)
-D 2001-11-23T00:30:00
-F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd
-F Makefile.template 1fdb891f14083ee0b63cf7282f91529634438e7a
+C Fix\scomparison\sfunctions\sso\sthat\sthey\sare\sconsistent\swith\sthe\sorder\nof\selements\sin\sindices.\s\sFix\sthe\shandling\sof\slarge\sintegers.\s(CVS\s317)
+D 2001-11-24T00:31:46
+F Makefile.in 352fed589f09dd94347e0bb391d047118ebd6105
+F Makefile.template b6c3d3ba089e97e3a721e967f3151350f36cb42b
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
-F VERSION c5cc20339d1ecb09a252aeef3d5417cd4d802473
+F VERSION e6864ec01e9107b1044207a2556c4e96c3457007
 F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
 F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
 F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
@@ -23,7 +23,7 @@ F src/btree.c d40fa46c8c578f1d166f4ea70d7a9d365399e0f3
 F src/btree.h 0250a0a577a98cc64ddf1582d50c08b8d2451650
 F src/build.c 2e21d425328e7c8bd6ade235e9eef51bf6fa870f
 F src/delete.c 5d93a21c1388cfb1359bda01c072f25583a2f4f2
-F src/expr.c 53515a7ba787bf4f0b3f73be30eb86aadb6f1b90
+F src/expr.c 6b25c5bb1e750af2e2217c0134a7aa1fc0b11444
 F src/hash.c 6f1a7712ae3aac8351662969aec5693740a2fbf7
 F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
 F src/insert.c 3526be771a01035198bef28d8f370cbcab94f46d
@@ -37,7 +37,7 @@ F src/parse.y 5295f393f41ea89958287e5738e6c12c7cd67482
 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
 F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
 F src/select.c fa1c7144a9ad7ce3f16373b443bc25e764af4be7
-F src/shell.c 18e9f1cac7ec8af763f8fc71dfd81e2edee24008
+F src/shell.c 175f4e942286bcafefc5bd44346deb94394615b1
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 934de9112747ad8d8e7d5fec44876246b24ca5a3
 F src/sqliteInt.h 1d812fd1eed0008d31f7e31293f058bb6dbe3f09
@@ -48,21 +48,21 @@ F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
 F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
 F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
 F src/update.c 365f6fafe75f6816a598e76031b0a757d91c003d
-F src/util.c 265cff871a6079b95878c738bc2da3420cca1375
+F src/util.c 13dcd870ee0e424f5427e8178480ca1b1833a706
 F src/vdbe.c f1afb7a82016be2cb4cea24cf98dbb5af0ea7214
 F src/vdbe.h cd4c8647051a0c22c0e133c375f1cd17bb8b1e06
 F src/where.c 05d27a01e53c20b8cd10589b7e789b2a64367988
 F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
-F test/bigrow.test 1f098f85586d2117bdb3412d27eba45252bc8a6e
+F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
 F test/btree.test 6ab4dc5f595905a276ef588fad3c9236dc07a47b
 F test/btree2.test 08e9485619265cbaf5d11bd71f357cdc26bb87e0
 F test/btree3.test 9caa9e22491dd8cd8aa36d7ac3b48b089817c895
 F test/copy.test 768e6f1701a07d08090e1ca7f7dcce0a7a72b43e
 F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
-F test/expr.test b4171c84b767f7b7e94dbce4824ba8e981a1c72f
+F test/expr.test d350ef5b21cc26599357fb93d15b8a5f7b524769
 F test/func.test 9012f7fc5369422c890e93549aa61d762e0c8bb3
 F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
-F test/index.test c2c3088648d106a5a612a14cb346998a4ff77bfa
+F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
 F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
 F test/insert2.test d6901ca931e308fea7fca8c95ebe7dc957cc9fc2
 F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
@@ -104,11 +104,12 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
 F www/arch.tcl 03b521d252575f93b9c52f7c8b0007011512fcfb
 F www/c_interface.tcl d446234c1d3ed747fcefd30e972a19f2b2fc0e05
-F www/changes.tcl f1a09dfa633183121d7d4255f4cadadc84dc034d
+F www/changes.tcl 0a54872839461f49b7300b36571d342f0ef0d4fb
 F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
 F www/download.tcl 3e51c9ff1326b0a182846134987301310dff7d60
 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
-F www/index.tcl fa0ee4b5343fd216ee5db0285501e45484189484
+F www/faq.tcl 55c7fbb5490d045a3e8223e41b51d8b93310b52c
+F www/index.tcl 7e1afccc37548b7107f666105749bfe7d99d267b
 F www/lang.tcl f0e953bfeaaba4c33117ec4bca639dd71ba0e13e
 F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
 F www/opcode.tcl 7989ed328316454c7030dcdb60f09ae1e017286d
@@ -116,7 +117,7 @@ F www/speed.tcl 212a91d555384e01873160d6a189f1490c791bc2
 F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
 F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
 F www/vdbe.tcl eb4e1768cffa266cbbb7133488022a7a6cb278d9
-P 8a984667113564f2bac7412165b6ff8b7e3e8f70
-R c4b924c66bb520eb6ed8e5503bdf1605
+P f14835df32b4a16c840b8827f0c17f0e6d526312
+R 4107b50dd67a5b31593969d21ca32f97
 U drh
-Z 1a9449aaa1a79f5e52fef176b1356165
+Z 70fea61a18707bc0d908d9bbb2153332
index 8837d3cfdd2051d04f349d4276a7289471d7a914..72d566e31441fc106b9527d37e0f64689945acd7 100644 (file)
@@ -1 +1 @@
-f14835df32b4a16c840b8827f0c17f0e6d526312
\ No newline at end of file
+fc2aae04578c305304a45ec6b76d3ab216cc7526
\ No newline at end of file
index 8e2045bf87c161714c67466d22b748813f105bce..fc7e7f83e867b33eeba2ce457d562afe3a8965b0 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.33 2001/11/08 00:45:21 drh Exp $
+** $Id: expr.c,v 1.34 2001/11/24 00:31:46 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -511,8 +511,8 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
       break;
     }
     case TK_INTEGER: {
-      int i = atoi(pExpr->token.z);
-      sqliteVdbeAddOp(v, OP_Integer, i, 0);
+      sqliteVdbeAddOp(v, OP_String, 0, 0);
+      sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
       break;
     }
     case TK_FLOAT: {
@@ -576,11 +576,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
     }
     case TK_UMINUS: {
       assert( pExpr->pLeft );
-      if( pExpr->pLeft->op==TK_INTEGER ){
-        int i = atoi(pExpr->pLeft->token.z);
-        sqliteVdbeAddOp(v, OP_Integer, -i, 0);
-        break;
-      }else if( pExpr->pLeft->op==TK_FLOAT ){
+      if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){
         Token *p = &pExpr->pLeft->token;
         char *z = sqliteMalloc( p->n + 2 );
         sprintf(z, "-%.*s", p->n, p->z);
index e9fc69845572f24dcecf9ffab8766c0db240a691..4db83d7b7718c7a6671f0a7b1762ecea295a0b13 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.38 2001/11/09 22:41:45 drh Exp $
+** $Id: shell.c,v 1.39 2001/11/24 00:31:46 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -556,9 +556,9 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
     p->showHeader = 1;
     p->colWidth[0] = 4;
     p->colWidth[1] = 12;
-    p->colWidth[2] = 5;
-    p->colWidth[3] = 5;
-    p->colWidth[4] = 40;
+    p->colWidth[2] = 10;
+    p->colWidth[3] = 10;
+    p->colWidth[4] = 35;
   }else
 
   if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
index ddb7cfa96b7591512324a9a17664a60a653bc6d8..166660a1e12caab2ab67b11659600fc4f3a51f07 100644 (file)
@@ -14,7 +14,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.32 2001/11/21 02:21:12 drh Exp $
+** $Id: util.c,v 1.33 2001/11/24 00:31:46 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -426,13 +426,18 @@ int sqliteStrNICmp(const char *zLeft, const char *zRight, int N){
   return N<0 ? 0 : *a - *b;
 }
 
-/* Notes on string comparisions.
+/* 
+** The sortStrCmp() function below is used to order elements according
+** to the ORDER BY clause of a SELECT.  The sort order is a little different
+** from what one might expect.  This note attempts to describe what is
+** going on.
 **
 ** We want the main string comparision function used for sorting to
 ** sort both numbers and alphanumeric words into the correct sequence.
 ** The same routine should do both without prior knowledge of which
 ** type of text the input represents.  It should even work for strings
-** which are a mixture of text and numbers.
+** which are a mixture of text and numbers.  (It does not work for
+** numeric substrings in exponential notation, however.)
 **
 ** To accomplish this, we keep track of a state number while scanning
 ** the two strings.  The states are as follows:
@@ -525,9 +530,10 @@ static const unsigned char stateMachine[] = {
 };
 
 /* This routine does a comparison of two strings.  Case is used only
-** if useCase!=0.  Numbers compare in numerical order.
+** if useCase!=0.  Numeric substrings compare in numerical order for the
+** most part but this routine does not understand exponential notation.
 */
-static int privateStrCmp(const char *atext, const char *btext, int useCase){
+static int sortStrCmp(const char *atext, const char *btext, int useCase){
   register unsigned char *a, *b, *map, ca, cb;
   int result;
   register int cclass = 0;
@@ -599,129 +605,69 @@ static int privateStrCmp(const char *atext, const char *btext, int useCase){
 }
 
 /*
-** Do a comparison of pure numerics.  If either string is not a pure
-** numeric, then return 0.  Otherwise return 1 and set *pResult to be
-** negative, zero or positive if the first string are numerially less than
-** equal to, or greater than the second.
+** Return TRUE if z is a pure numeric string.  Return FALSE if the
+** string contains any character which is not part of a number.
+**
+** Am empty string is considered numeric.
 */
-static int privateCompareNum(const char *a, const char *b, int *pResult){
-  char *endPtr;
-  double rA, rB;
-  int isNumA, isNumB;
-  if( isdigit(*a) || ((*a=='-' || *a=='+') && isdigit(a[1])) ){
-    rA = strtod(a, &endPtr);
-    isNumA = *endPtr==0;
-  }else{
-    isNumA = 0;
+static int isNum(const char *z){
+  if( *z=='-' || *z=='+' ) z++;
+  if( !isdigit(*z) ){
+    return *z==0;
   }
-  if( isdigit(*b) || ((*b=='-' || *b=='+') && isdigit(b[1])) ){
-    rB = strtod(b, &endPtr);
-    isNumB = *endPtr==0;
-  }else{
-    isNumB = 0;
-  }
-  if( isNumB==0 && isNumA==0 ) return 0;
-  if( isNumA!=isNumB ){
-    *pResult =  isNumA - isNumB;
-  }else if( rA<rB ){
-    *pResult = -1;
-  }else if( rA>rB ){
-    *pResult = 1;
-  }else{
-    *pResult = 0;
+  z++;
+  while( isdigit(*z) ){ z++; }
+  if( *z=='.' ){
+    z++;
+    if( !isdigit(*z) ) return 0;
+    while( isdigit(*z) ){ z++; }
+    if( *z=='e' || *z=='E' ){
+      z++;
+      if( *z=='+' || *z=='-' ) z++;
+      if( !isdigit(*z) ) return 0;
+      while( isdigit(*z) ){ z++; }
+    }
   }
-  return 1;
+  return *z==0;
 }
 
 /* This comparison routine is what we use for comparison operations
-** in an SQL expression.  (Ex:  name<'Hello' or value<5).  Compare two
-** strings.  Use case only as a tie-breaker.  Numbers compare in
-** numerical order.
+** in an SQL expression.  (Ex:  name<'Hello' or value<5). 
+**
+** Numerical strings compare in numerical order.  Numerical strings
+** are always less than non-numeric strings.  Non-numeric strings
+** compare in lexigraphical order (the same order as strcmp()).
+**
+** This is NOT the comparison function used for sorting.  The sort
+** order is a little bit different.  See sqliteSortCompare below
+** for additional information.
 */
 int sqliteCompare(const char *atext, const char *btext){
   int result;
-  if( !privateCompareNum(atext, btext, &result) || result==0 ){
-    result = privateStrCmp(atext, btext, 0);
-    if( result==0 ) result = privateStrCmp(atext, btext, 1);
-  }
-  return result;
-}
-
-/*
-** If you compile just this one file with the -DTEST_COMPARE=1 option,
-** it generates a program to test the comparisons routines.  
-*/
-#ifdef TEST_COMPARE
-#include <stdlib.h>
-#include <stdio.h>
-int sortCmp(const char **a, const char **b){
-  return sqliteCompare(*a, *b);
-}
-int main(int argc, char **argv){
-  int i, j, k, n, cnt;
-  static char *azStr[] = {
-     "abc", "aBc", "abcd", "aBcd", 
-     "123", "124", "1234", "-123", "-124", "-1234", "+124",
-     "123.45", "123.456", "123.46", "-123.45", "-123.46", "-123.456", 
-     "x9", "x10", "x-9", "x-10", "X9", "X10",
-     "1.234e+02", "+123", "1.23E2", "1.2345e+2", "-1.2345e2", "+w"
-  };
-  n = sizeof(azStr)/sizeof(azStr[0]);
-  qsort(azStr, n, sizeof(azStr[0]), sortCmp);
-  for(i=0; i<n; i++){
-    printf("%s\n", azStr[i]);
-  }
-  printf("Sanity1...");
-  fflush(stdout);
-  cnt = 0;
-  for(i=0; i<n-1; i++){
-    char *a = azStr[i];
-    for(j=i+1; j<n; j++){
-      char *b = azStr[j];
-      if( sqliteCompare(a,b) != -sqliteCompare(b,a) ){
-        printf("Failed!  \"%s\" vs \"%s\"\n", a, b);
-        i = j = n;
-      }
-      cnt++;
-    }
-  }
-  if( i<n ){
-    printf(" OK (%d)\n", cnt);
-  }
-  printf("Sanity2...");
-  fflush(stdout);
-  cnt = 0;
-  for(i=0; i<n; i++){
-    char *a = azStr[i];
-    for(j=0; j<n; j++){
-      char *b = azStr[j];
-      for(k=0; k<n; k++){
-        char *c = azStr[k];
-        int x1, x2, x3, success;
-        x1 = sqliteCompare(a,b);
-        x2 = sqliteCompare(b,c);
-        x3 = sqliteCompare(a,c);
-        if( x1==0 ){
-          success = x2==x3;
-        }else if( x1<0 ){
-          success = (x2<=0 && x3<=0) || x2>0;
-        }else{
-          success = (x2>=0 && x3>=0) || x2<0;
-        }
-        if( !success ){
-          printf("Failed!  \"%s\" vs \"%s\" vs \"%s\"\n", a, b, c);
-          i = j = k = n+1;
-        }
-        cnt++;
+  int isNumA = isNum(atext);
+  int isNumB = isNum(btext);
+  if( isNumA ){
+    if( !isNumB ){
+      result = -1;
+    }else{
+      double rA, rB;
+      rA = atof(atext);
+      rB = atof(btext);
+      if( rA<rB ){
+        result = -1;
+      }else if( rA>rB ){
+        result = +1;
+      }else{
+        result = 0;
       }
     }
+  }else if( isNumB ){
+    result = +1;
+  }else {
+    result = strcmp(atext, btext);
   }
-  if( i<n+1 ){
-    printf(" OK (%d)\n", cnt);
-  }
-  return 0;
+  return result; 
 }
-#endif
 
 /*
 ** This routine is used for sorting.  Each key is a list of one or more
@@ -737,26 +683,67 @@ int main(int argc, char **argv){
 ** Every string begins with either a "+" or "-" character.  If the
 ** character is "-" then the return value is negated.  This is done
 ** to implement a sort in descending order.
+**
+** For sorting purposes, pur numeric strings (strings for which the
+** isNum() function above returns TRUE) always compare less than strings
+** that are not pure numerics.  Within non-numeric strings, substrings
+** of digits compare in numerical order.  Finally, case is used only
+** to break a tie.
+**
+** Note that the sort order imposed by the rules above is different
+** from the ordering defined by the "<", "<=", ">", and ">=" operators
+** of expressions.  The operators compare non-numeric strings in
+** lexigraphical order.  This routine does the additional processing
+** to sort substrings of digits into numerical order and to use case
+** only as a tie-breaker.
 */
 int sqliteSortCompare(const char *a, const char *b){
   int len;
   int res = 0;
+  int isNumA, isNumB;
 
   while( res==0 && *a && *b ){
-    res = sqliteCompare(&a[1], &b[1]);
-    if( res==0 ){
-      len = strlen(a) + 1;
-      a += len;
-      b += len;
+    isNumA = isNum(&a[1]);
+    isNumB = isNum(&b[1]);
+    if( isNumA ){
+      double rA, rB;
+      if( !isNumB ){
+        res = -1;
+        break;
+      }
+      rA = atof(&a[1]);
+      rB = atof(&b[1]);
+      if( rA<rB ){
+        res = -1;
+        break;
+      }
+      if( rA>rB ){
+        res = +1;
+        break;
+      }
+    }else if( isNumB ){
+      res = +1;
+      break;
+    }else{
+      res = sortStrCmp(&a[1],&b[1],0);
+      if( res==0 ){
+        res = sortStrCmp(&a[1],&b[1],1);
+      }
+      if( res!=0 ){
+        break;
+      }
     }
+    len = strlen(&a[1]) + 2;
+    a += len;
+    b += len;
   }
   if( *a=='-' ) res = -res;
   return res;
 }
 
 /*
-** Some powers of 64.  These numbers and their recipricals should
-** all have exact representations in the floating point format.
+** Some powers of 64.  These constants are needed in the
+** sqliteRealToSortable() routine below.
 */
 #define _64e3  (64.0 * 64.0 * 64.0)
 #define _64e4  (64.0 * 64.0 * 64.0 * 64.0)
index ce1150c44b3f582532f6a889c74a985953ab8b36..7a7d9ccaeb0c870283e02a0c6f3d9d9df758f647 100644 (file)
@@ -12,7 +12,7 @@
 # focus of this file is stressing the library by putting large amounts
 # of data in a single row of a table.
 #
-# $Id: bigrow.test,v 1.3 2001/11/12 13:10:53 drh Exp $
+# $Id: bigrow.test,v 1.4 2001/11/24 00:31:47 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -90,7 +90,7 @@ do_test bigrow-1.8 {
 } {abc}
 do_test bigrow-1.9 {
   execsql "SELECT b FROM t1 WHERE a!='$::big1' ORDER BY a"
-} {B 2}
+} {2 B}
 
 # Try doing some indexing on big columns
 #
index c275e4a4d99ad213a2d3765047d072b7e5b4922d..23c92fa1033ba7e821d753d2b2a068d840c20eb1 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing expressions.
 #
-# $Id: expr.test,v 1.16 2001/10/13 02:59:09 drh Exp $
+# $Id: expr.test,v 1.17 2001/11/24 00:31:47 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -73,6 +73,15 @@ test_expr expr-1.43 {i1=1, i2=2} {i1&i2} {0}
 test_expr expr-1.44 {i1=1} {~i1} {-2}
 test_expr expr-1.45 {i1=1, i2=3} {i1<<i2} {8}
 test_expr expr-1.46 {i1=32, i2=3} {i1>>i2} {4}
+test_expr expr-1.47 {i1=9999999999, i2=8888888888} {i1<i2} 0
+test_expr expr-1.48 {i1=9999999999, i2=8888888888} {i1=i2} 0
+test_expr expr-1.49 {i1=9999999999, i2=8888888888} {i1>i2} 1
+test_expr expr-1.50 {i1=99999999999, i2=99999999998} {i1<i2} 0
+test_expr expr-1.51 {i1=99999999999, i2=99999999998} {i1=i2} 0
+test_expr expr-1.52 {i1=99999999999, i2=99999999998} {i1>i2} 1
+test_expr expr-1.53 {i1=099999999999, i2=99999999999} {i1<i2} 0
+test_expr expr-1.54 {i1=099999999999, i2=99999999999} {i1=i2} 1
+test_expr expr-1.55 {i1=099999999999, i2=99999999999} {i1>i2} 0
 
 test_expr expr-2.1 {r1=1.23, r2=2.34} {r1+r2} 3.57
 test_expr expr-2.2 {r1=1.23, r2=2.34} {r1-r2} -1.11
@@ -123,9 +132,11 @@ test_expr expr-3.22 {t1='abc', t2='xyz'} {t1!=t2} 1
 test_expr expr-3.23 {t1='xyz', t2='abc'} {t1!=t2} 1
 test_expr expr-3.24 {t1='abc', t2='abc'} {t1!=t2} 0
 test_expr expr-3.25 {t1=NULL, t2='hi'} {t1 isnull} 1
+test_expr expr-3.25b {t1=NULL, t2='hi'} {t1 is null} 1
 test_expr expr-3.26 {t1=NULL, t2='hi'} {t2 isnull} 0
 test_expr expr-3.27 {t1=NULL, t2='hi'} {t1 notnull} 0
 test_expr expr-3.28 {t1=NULL, t2='hi'} {t2 notnull} 1
+test_expr expr-3.28b {t1=NULL, t2='hi'} {t2 is not null} 1
 test_expr expr-3.29 {t1='xyz', t2='abc'} {t1||t2} {xyzabc}
 test_expr expr-3.30 {t1=NULL, t2='abc'} {t1||t2} {abc}
 test_expr expr-3.31 {t1='xyz', t2=NULL} {t1||t2} {xyz}
@@ -133,8 +144,14 @@ test_expr expr-3.32 {t1='xyz', t2='abc'} {t1||' hi '||t2} {{xyz hi abc}}
 
 test_expr expr-4.1 {t1='abc', t2='Abc'} {t1<t2} 0
 test_expr expr-4.2 {t1='abc', t2='Abc'} {t1>t2} 1
-test_expr expr-4.3 {t1='abc', t2='Bbc'} {t1<t2} 1
-test_expr expr-4.4 {t1='abc', t2='Bbc'} {t1>t2} 0
+test_expr expr-4.3 {t1='abc', t2='Bbc'} {t1<t2} 0
+test_expr expr-4.4 {t1='abc', t2='Bbc'} {t1>t2} 1
+test_expr expr-4.5 {t1='0', t2='0.0'} {t1==t2} 1
+test_expr expr-4.6 {t1='0.000', t2='0.0'} {t1==t2} 1
+test_expr expr-4.7 {t1=' 0.000', t2=' 0.0'} {t1==t2} 0
+test_expr expr-4.8 {t1='0.0', t2='abc'} {t1<t2} 1
+test_expr expr-4.9 {t1='0.0', t2='abc'} {t1==t2} 0
+test_expr expr-4.10 {t1='0.0', t2='abc'} {t1>t2} 0
 
 test_expr expr-5.1 {t1='abc', t2='xyz'} {t1 LIKE t2} 0
 test_expr expr-5.2 {t1='abc', t2='ABC'} {t1 LIKE t2} 1
index 359c821d41ab2b5cd5a7d3a3ff933dd808724155..43a39ef15db69d4c16dcd41f66dbcddbc7fbb918 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the CREATE INDEX statement.
 #
-# $Id: index.test,v 1.16 2001/11/23 00:24:12 drh Exp $
+# $Id: index.test,v 1.17 2001/11/24 00:31:47 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -331,4 +331,54 @@ do_test index-11.1 {
   concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count
 } {0.10 3}
 
+# Numeric strings should compare as if they were numbers.  So even if the
+# strings are not character-by-character the same, if they represent the
+# same number they should compare equal to one another.  Verify that this
+# is true in indices.
+#
+do_test index-12.1 {
+  execsql {
+    CREATE TABLE t4(a,b);
+    INSERT INTO t4 VALUES('0.0',1);
+    INSERT INTO t4 VALUES('0.00',2);
+    INSERT INTO t4 VALUES('abc',3);
+    INSERT INTO t4 VALUES('-1.0',4);
+    INSERT INTO t4 VALUES('+1.0',5);
+    INSERT INTO t4 VALUES('0',6);
+    INSERT INTO t4 VALUES('00000',7);
+    SELECT a FROM t4 ORDER BY b;
+  }
+} {0.0 0.00 abc -1.0 +1.0 0 00000}
+do_test index-12.2 {
+  execsql {
+    SELECT a FROM t4 WHERE a==0 ORDER BY b
+  }
+} {0.0 0.00 0 00000}
+do_test index-12.3 {
+  execsql {
+    SELECT a FROM t4 WHERE a<0.5 ORDER BY b
+  }
+} {0.0 0.00 -1.0 0 00000}
+do_test index-12.4 {
+  execsql {
+    SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
+  }
+} {0.0 0.00 abc +1.0 0 00000}
+do_test index-12.5 {
+  execsql {
+    CREATE INDEX t4i1 ON t4(a);
+    SELECT a FROM t4 WHERE a==0 ORDER BY b
+  }
+} {0.0 0.00 0 00000}
+do_test index-12.6 {
+  execsql {
+    SELECT a FROM t4 WHERE a<0.5 ORDER BY b
+  }
+} {0.0 0.00 -1.0 0 00000}
+do_test index-12.7 {
+  execsql {
+    SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
+  }
+} {0.0 0.00 abc +1.0 0 00000}
+
 finish_test
index 9b19247fe41f6d7eb75ae3ae818327e59c6c07ac..c76ad91bcd01359574d44c4ee1f680acf4ac87cb 100644 (file)
@@ -17,6 +17,14 @@ proc chng {date desc} {
   puts "<DD><P><UL>$desc</UL></P></DD>"
 }
 
+chng {2001 Nov 23 (2.1.3)} {
+<li>Fix the behavior of comparison operators 
+    (ex: "<b>&lt</b>", "<b>==</b>", etc.)
+    so that they are consistent with the order of entries in an index.</li>
+<li>Correct handling of integers in SQL expressions that are larger than
+    what can be represented by the machine integer.</li>
+}
+
 chng {2001 Nov 22 (2.1.2)} {
 <li>Changes to support 64-bit architectures.</li>
 <li>Fix a bug in the locking protocol.</li>
diff --git a/www/faq.tcl b/www/faq.tcl
new file mode 100644 (file)
index 0000000..d300a7a
--- /dev/null
@@ -0,0 +1,165 @@
+#
+# Run this script to generated a faq.html output file
+#
+puts {<html>
+<head>
+  <title>SQLite Frequently Asked Questions</title>
+</head>
+<body bgcolor="white">
+<h1 align="center">Frequently Asked Questions</h1>
+}
+
+set cnt 1
+proc faq {question answer} {
+  set ::faq($::cnt) [list [string trim $question] [string trim $answer]]
+  incr ::cnt
+}
+
+#############
+# Enter questions and answers here.
+
+faq {
+  How do I create an AUTOINCREMENT field.
+} {
+  SQLite does not support AUTOINCREMENT.  If you need a unique key for
+  a new entry in a table, you can create an auxiliary table
+  with a single entry that holds the next available value for that key.
+  Like this:
+<blockquote><pre>
+CREATE TABLE counter(cnt);
+INSERT INTO counter VALUES(1);
+</pre></blockquote>
+  Once you have a counter set up, you can generate a unique key as follows:
+<blockquote><pre>
+BEGIN TRANSACTION;
+SELECT cnt FROM counter;
+UPDATE counter SET cnt=cnt+1;
+COMMIT;
+</pre></blockquote>
+  There are other ways of simulating the effect of AUTOINCREMENT but
+  this approach seems to be the easiest and most efficient.
+}
+
+faq {
+  SQLite lets me insert a string into a database column of type integer!
+} {
+  <p>This is a feature, not a bug.  SQLite is typeless.  Any data can be
+  inserted into any column.  You can put arbitrary length strings into
+  integer columns, floating point numbers in boolean columns, or dates
+  in character columns.  The datatype you assign to a column in the
+  CREATE TABLE command is (mostly) ignored.  Every column is able to hold
+  an arbitrary length string.</p>
+
+  <p>Because SQLite ignores data types, you can omit the data type definition
+  from columns in CREATE TABLE statements.  For example, instead of saying
+<blockquote><pre>
+CREATE TABLE t1(
+  f1 int,
+  f2 varchar(10),
+  f3 boolean
+);
+</pre></blockquote>
+  You can save yourself a lot of typing and formatting by omitting the
+  data type declarations, like this:
+<blockquote><pre>
+CREATE TABLE t1(f1,f2,f3);
+</pre></blockquote>
+  </p>
+}
+
+faq {
+  Why does SQLite think that the expression '0'=='00' is TRUE?
+} {
+  <p>This is a consequence of SQLite being typeless.  All data is stored
+  internally as a null-terminated string.  There is no concept of
+  separate data types for strings and numbers.</p>
+
+  <p>When doing a comparison, SQLite looks at the string on both sides of
+  the comparison operator.  If both strings look like pure numeric
+  values (with no extra punctuation or spacing) then the strings are
+  converted to floating point numbers using <b>atof()</b> and the results
+  are compared.  The results of <b>atof("0")</b> and <b>atof("00")</b>
+  are both 0.0, so those two strings are considered to be equal.</p>
+
+  <p>If only one string in a comparison is a pure numeric, then that string
+  is assumed to be less than the other.  Of neither string is a pure numeric,
+  then <b>strcmp()</b> is used for the comparison.</p>
+}
+
+faq {
+  The second INSERT in the following sequence of commands returns with 
+  constraint error.
+  <blockquote>
+     CREATE TABLE t(s varchar(10) primary key);<br>
+     INSERT INTO t VALUES('0');<br>
+     INSERT INTO t VALUES('0.0');<br>
+  </blockquote>
+  Why is this?
+} {
+  <p>Because column <b>s</b> is a primary key, all values of <b>s</b> must
+  be unique.  But SQLite thinks that <b>'0'</b> and <b>'0.0'</b> are the
+  same value because they compare equal to one another numerically.
+  (See the previous question.)  Hence the values are not unique and the
+  constraint fails.</p>
+
+  <p>You can work around this issue in several ways:</p>
+  <ol>
+  <li><p>Remove the <b>primary key</b> clause from the CREATE TABLE so that
+         <b>s</b> can contain more than one entry with the same value. 
+         If you need an index on the <b>s</b> column then create it separately.
+         </p></li>
+  <li><p>Prepend a space to the beginning of every <b>s</b> value.  The initial
+         space will mean that the entries are not pure numerics and hence
+         will be compared as strings using <b>strcmp()</b>.</p></li>
+  </ol>
+}
+        
+faq {
+  My linux box is not able to read an SQLite database that was created
+  on my SparcStation.
+} {
+  <p>The x86 processor on your windows box is little-endian (meaning that
+  the least signification byte of integers comes first) but the Sparc is
+  big-endian (the most significant bytes comes first).  SQLite databases
+  created on a little-endian architecture cannot be used on a big-endian
+  machine and vice versa.</p>
+
+  <p>If you need to move the database from one machine to another, you'll
+  have to do an ASCII dump of the database on the source machine and then
+  reconstruct the database at the destination machine.  The following is
+  a typical command for transferring an SQLite databases between two
+  machines:
+<blockquote><pre>
+echo .dump | sqlite from.db | ssh sparc 'sqlite to.db'
+</pre></blockquote>
+  The command above assumes the name of the destination machine is
+  <b>sparc</b> and that you have SSH running on both the source and
+  destination.  An alternative approach is to save the output of the first
+  <b>sqlite</b> command in a temporary file, move the temporary file
+  to the destination machine, then run the second <b>sqlite</b> command
+  while redirecting input from the temporary file.</p>
+}
+
+# End of questions and answers.
+#############
+
+puts {<DL COMPACT>}
+for {set i 1} {$i<$cnt} {incr i} {
+  puts "  <DT><A HREF=\"#q$i\">($i)</A></DT>"
+  puts "  <DD>[lindex $faq($i) 0]</DD>"
+}
+puts {</DL><HR />}
+
+for {set i 1} {$i<$cnt} {incr i} {
+  puts "<A NAME=\"q$i\">"
+  puts "<P><B>($i) [lindex $faq($i) 0]</B></P>\n"
+  puts "<BLOCKQUOTE>[lindex $faq($i) 1]</BLOCKQUOTE>\n"
+}
+
+puts {
+<p><hr /></p>
+<p><a href="index.html"><img src="/goback.jpg" border=0 />
+Back to the SQLite Home Page</a>
+</p>
+
+</body></html>}
index 4dd9c9b30963d58763bbb120f8112d5bef031840..d7718da09633786933c6d1127355323cb9896f1c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this TCL script to generate HTML for the index.html file.
 #
-set rcsid {$Id: index.tcl,v 1.47 2001/11/12 12:43:22 drh Exp $}
+set rcsid {$Id: index.tcl,v 1.48 2001/11/24 00:31:47 drh Exp $}
 
 puts {<html>
 <head><title>SQLite: An SQL Database Engine In A C Library</title></head>
@@ -105,6 +105,7 @@ newer versions of SQLite.
 <p>The following documentation is currently available:</p>
 
 <p><ul>
+<li><a href="faq.html">Frequently Asked Questions</a> are available online.</li>
 <li>Information on the <a href="sqlite.html">sqlite</a>
     command-line utility.</li>
 <li>The <a href="lang.html">SQL Language</a> subset understood by SQLite.</li>