]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix for ticket #107: Fix a design defect in indices that was causing queries
authordrh <drh@noemail.net>
Thu, 18 Jul 2002 00:34:09 +0000 (00:34 +0000)
committerdrh <drh@noemail.net>
Thu, 18 Jul 2002 00:34:09 +0000 (00:34 +0000)
to fail when using an index on a column containing an empty string.  This
fix is an incompatible file-format change. (CVS 681)

FossilOrigin-Name: 20d152fcddb4fa53556a9c93c7a869600a7c5183

12 files changed:
VERSION
manifest
manifest.uuid
src/build.c
src/delete.c
src/expr.c
src/insert.c
src/main.c
src/select.c
src/sqliteInt.h
src/vdbe.c
test/index.test

diff --git a/VERSION b/VERSION
index da6b0a8f16f5c36ee10dbd5e56f432a85f0bd6c4..e70b4523ae7ffe8aa3cac8ecd1b093fba5a98737 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.5.6
+2.6.0
index 170316e6e96bcfb9b71e21a09811a0c510fcaf1c..65e3a042ee81fb3570ffe71d4e268b8673293c9a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Fix\sfor\sticket\s#105:\sFix\sthe\sUPDATE\scommand\sso\sthat\sit\sworks\sproperly\swith\nindexed\stables\swhen\sthere\sis\sa\ssubquery\sin\sthe\sWHERE\sclause.\s\sAdd\stests\nto\sverify\scorrect\soperation.\s(CVS\s680)
-D 2002-07-16T17:22:51
+C Fix\sfor\sticket\s#107:\sFix\sa\sdesign\sdefect\sin\sindices\sthat\swas\scausing\squeries\nto\sfail\swhen\susing\san\sindex\son\sa\scolumn\scontaining\san\sempty\sstring.\s\sThis\nfix\sis\san\sincompatible\sfile-format\schange.\s(CVS\s681)
+D 2002-07-18T00:34:10
 F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
 F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
-F VERSION 0afb45a36f2b97c8455247659f1155967b8bb883
+F VERSION b36b90fdfe67f5f38d70b444e4430701df184330
 F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
 F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
 F config.sub f14b07d544ca26b5d698259045136b783e18fc7f
@@ -20,15 +20,15 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c db8cd1bd46cd30a1763c3cc80602571d1b30a329
 F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
-F src/build.c 81d0f42ae58af35d6331402e71a4fb2d2898586c
-F src/delete.c 215492ffcea4262a993e55f3c4a67dc9fea4da9c
+F src/build.c 2f81c837284840448f21c90ef7c9c6c6c0d4d8a0
+F src/delete.c bc35d6aa7e7b2a4f88510a17e060abb355a53bd6
 F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
-F src/expr.c 5c3b241a680dff98afdf5f0ba6e14a3b19669914
+F src/expr.c 8a6b669ba5d6cd2810e8671f918ddb0fac3dd1b1
 F src/func.c e45cd908b9b723d9b91473d09e12c23f786b3fc2
 F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
-F src/insert.c 4511e06abce1688664ce90cbf09fa13433b82c43
-F src/main.c d9ff20d7412b20cb97c21a65e13c1c174653b50d
+F src/insert.c 9bc794863ea2988a7b8667ef010b3c46b26dba38
+F src/main.c dbe691d2b6e0b2b0e0e87ca42c04506ead1c0550
 F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
 F src/os.c edb22daad525f49681f41c76683a16c1d39755c7
 F src/os.h 5b9a69875c880d1665ae040cbca1f7b9c82198ab
@@ -37,11 +37,11 @@ F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
 F src/parse.y 5307e1a7b26241991934d4b50ae70980f3f2aca9
 F src/printf.c 06f4c8725063e0faf0e34824ab70feace7146bf7
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c f4e7221a319da25f549a434a6c664eedcbce4dec
+F src/select.c a43eabfc2e3e4d67660027f016889935f706deab
 F src/shell.c 37a8405aec5740726c4ee18826c1ff5fd2c29b96
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 75c5bbb066d0faf34424b7d1babf8b44d5b31af2
-F src/sqliteInt.h d18d098aa9121d2415a9c0d1d3e09a10dde39385
+F src/sqliteInt.h 0d0b7b7b2b6829eb5c2f63489b11c44ba966fc75
 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
 F src/tclsqlite.c c502819c209011659e1bbb428cbac5670cce7f79
 F src/test1.c 456cb080db85056be723e770435d9509afc3a83a
@@ -52,7 +52,7 @@ F src/tokenize.c b5500e193a82b5b9888fbf947efd90d3b4858178
 F src/trigger.c d88ab4d68d68955c217b38fb6717e090fbbf54a4
 F src/update.c ddba82d1b0d1cb34d862d8ad943012f88e2b8495
 F src/util.c 7a99e754c44dd220e881122e30581c08b6d6adef
-F src/vdbe.c 0169270bb73e8dec4174b90dffc7070c4cabe039
+F src/vdbe.c 7433a7811fbbb7cfec4f12c142913b4d8a02231e
 F src/vdbe.h a9292f2b5fcecef924fa255fb74609e9cbc776c2
 F src/where.c 6a43aa6c80eab12221eeca754cba852a9ecd1e13
 F test/all.test f296d27fff6aca72348af15092154f879d1fc7d4
@@ -66,7 +66,7 @@ F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
 F test/expr.test 5fadd0bc87c223b424ce6752b576c1df346abf1f
 F test/func.test cae5f27e09736cfdcc978c3719ac1345405b848c
 F test/in.test e59461f1702b7387880bf08a0ce6bb777925d282
-F test/index.test 1a69532e7868eddac61c679fd03f46b5666214da
+F test/index.test 7503d903c4dffecbb415010298720720db8618e0
 F test/insert.test a122afb86911e77c181d912348866a5b1a61eeab
 F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f
 F test/intpkey.test 69a6a9b41e541f27a2ffcd20264fb35adc3c2680
@@ -141,7 +141,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 93710f7ed7e1baa6acbf4bc32982e046f61ffa44
-R a496b407b95e3e3391653a1442fdf78c
+P bbca16f88d00cd33ac7229edf3ee4623eff6e62f
+R 3b401eb81b101736a092f34a44910d1f
 U drh
-Z af2183151817c8e8381633943b4d70fd
+Z 3a1e3e849570ce46d4051f5d0915780a
index db31b261c9709b8749212baa0ed10c85d8e13b21..7de7eb61454bb2ef746e483241ea0fd66a943617 100644 (file)
@@ -1 +1 @@
-bbca16f88d00cd33ac7229edf3ee4623eff6e62f
\ No newline at end of file
+20d152fcddb4fa53556a9c93c7a869600a7c5183
\ No newline at end of file
index 999acf33bfe340e0ae96659764022803115c77ba..3b2d3bf89e918ce02134606f151997bbed963bf7 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.105 2002/07/13 17:23:21 drh Exp $
+** $Id: build.c,v 1.106 2002/07/18 00:34:11 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1398,7 +1398,7 @@ void sqliteCreateIndex(
         sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i]);
       }
       sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
-      if( db->file_format>=3 ) sqliteAddIdxKeyType(v, pIndex);
+      if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIndex);
       sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->onError!=OE_None);
       sqliteVdbeAddOp(v, OP_Next, 2, lbl1);
       sqliteVdbeResolveLabel(v, lbl2);
index 8e91e25eed21b0a726a85af163da5156899d9ede..393b9480c5079aa50bd226640e5999ea1986adb6 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.39 2002/07/05 21:42:37 drh Exp $
+** $Id: delete.c,v 1.40 2002/07/18 00:34:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -381,7 +381,7 @@ void sqliteGenerateRowIndexDelete(
       }
     }
     sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-    if( db->file_format>=3 ) sqliteAddIdxKeyType(v, pIdx);
+    if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
     sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
   }
 }
index 4798ddb3b80c64bb9702d9721721349b75c8206f..43b4f7ee0dcbad026dfc6b537d853db0a83eb8a8 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.78 2002/07/16 02:05:44 drh Exp $
+** $Id: expr.c,v 1.79 2002/07/18 00:34:12 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -999,7 +999,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
     case TK_GE:
     case TK_NE:
     case TK_EQ: {
-      if( pParse->db->file_format>=3 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
+      if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
         op += 6;  /* Convert numeric opcodes to text opcodes */
       }
       /* Fall through into the next case */
@@ -1232,7 +1232,7 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
     case TK_EQ: {
       sqliteExprCode(pParse, pExpr->pLeft);
       sqliteExprCode(pParse, pExpr->pRight);
-      if( pParse->db->file_format>=3 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
+      if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
         op += 6;  /* Convert numeric opcodes to text opcodes */
       }
       sqliteVdbeAddOp(v, op, jumpIfNull, dest);
@@ -1325,7 +1325,7 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
     case TK_GE:
     case TK_NE:
     case TK_EQ: {
-      if( pParse->db->file_format>=3 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
+      if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
         op += 6;  /* Convert numeric opcodes to text opcodes */
       }
       sqliteExprCode(pParse, pExpr->pLeft);
index a6b2e858ed9c609fea4962356e07668a9a8ccdda..d2e8d71268b9a5996d5d5492bc780c85d21d371b 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.63 2002/07/05 21:42:37 drh Exp $
+** $Id: insert.c,v 1.64 2002/07/18 00:34:12 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -616,7 +616,7 @@ void sqliteGenerateConstraintChecks(
       }
     }
     jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-    if( pParse->db->file_format>=3 ) sqliteAddIdxKeyType(v, pIdx);
+    if( pParse->db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
     onError = pIdx->onError;
     if( onError==OE_None ) continue;
     if( overrideError!=OE_Default ){
index 28b98d9cc430362bf834201df1d5b9174bc61db9..6db127f83f8725987edbe8d35d0d21ec9feeaae5 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.86 2002/07/13 17:23:21 drh Exp $
+** $Id: main.c,v 1.87 2002/07/18 00:34:12 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -89,6 +89,31 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
   return nErr;
 }
 
+/*
+** This is a callback procedure used to reconstruct a table.  The
+** name of the table to be reconstructed is passed in as argv[0].
+**
+** This routine is used to automatically upgrade a database from
+** format version 1 or 2 to version 3.  The correct operation of
+** this routine relys on the fact that no indices are used when
+** copying a table out to a temporary file.
+*/
+static int 
+upgrade_3_callback(void *pDb, int argc, char **argv, char **NotUsed){
+  sqlite *db = (sqlite*)pDb;
+  int rc;
+
+  rc = sqlite_exec_printf(db,
+    "CREATE TEMP TABLE sqlite_x AS SELECT * FROM '%q'; "
+    "DELETE FROM '%q'; "
+    "INSERT INTO '%q' SELECT * FROM sqlite_x; "
+    "DROP TABLE sqlite_x;",
+    0, 0, 0, argv[0], argv[0], argv[0]);
+  return rc!=SQLITE_OK;
+}
+
+
+
 /*
 ** Attempt to read the database schema and initialize internal
 ** data structures.  Return one of the SQLITE_ error codes to
@@ -206,12 +231,14 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
   /*
   **     file_format==1    Version 2.1.0.
   **     file_format==2    Version 2.2.0. Add support for INTEGER PRIMARY KEY.
-  **     file_format==3    Version 2.6.0. Add support for separate numeric and
+  **     file_format==3    Version 2.6.0. Fix empty-string index bug.
+  **     file_format==4    Version 2.7.0. Add support for separate numeric and
   **                       text datatypes.
   */
   if( db->file_format==0 ){
-    db->file_format = 2;
-  }else if( db->file_format>2 ){
+    /* This happens if the database was initially empty */
+    db->file_format = 3;
+  }else if( db->file_format>3 ){
     sqliteBtreeCloseCursor(curMain);
     sqliteSetString(pzErrMsg, "unsupported file format", 0);
     rc = SQLITE_ERROR;
@@ -313,6 +340,40 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
     sqliteFree(*pzErrMsg);
     *pzErrMsg = 0;
   }
+
+  /* If the database is in formats 1 or 2, then upgrade it to
+  ** version 3.  This will reconstruct all indices.  If the
+  ** upgrade fails for any reason (ex: out of disk space, database
+  ** is read only, interrupt receive, etc.) then refuse to open.
+  */
+  if( db->file_format<3 ){
+    char *zErr;
+    int meta[SQLITE_N_BTREE_META];
+
+    db->file_format = 3;
+    rc = sqlite_exec(db,
+      "BEGIN; SELECT name FROM sqlite_master WHERE type='table';",
+      upgrade_3_callback,
+      db,
+      &zErr);
+    if( rc==SQLITE_OK ){
+      sqliteBtreeGetMeta(db->pBe, meta);
+      meta[2] = 3;
+      sqliteBtreeUpdateMeta(db->pBe, meta);
+      sqlite_exec(db, "COMMIT", 0, 0, 0);
+    }
+    if( rc!=SQLITE_OK ){
+      sqliteSetString(pzErrMsg, 
+        "unable to upgrade database to the version 2.6 format",
+        zErr ? ": " : 0, zErr, 0);
+      sqliteFree(zErr);
+      sqliteStrRealloc(pzErrMsg);
+      sqlite_close(db);
+      return 0;
+    }
+  }
+
+  /* Return a pointer to the newly opened database structure */
   return db;
 
 no_mem_on_open:
@@ -502,6 +563,11 @@ int sqlite_exec(
       return rc;
     }
   }
+  if( db->file_format<3 ){
+    sqliteSafetyOff(db);
+    sqliteSetString(pzErrMsg, "obsolete database file format", 0);
+    return SQLITE_ERROR;
+  }
   if( db->recursionDepth==0 ){ db->nChange = 0; }
   db->recursionDepth++;
   memset(&sParse, 0, sizeof(sParse));
index 61be40e9c1f9cad0b37a2cd46b77f1316528f4c4..89511db34d905d5b0d55124d86d8d941ae380ab9 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.105 2002/07/11 12:18:17 drh Exp $
+** $Id: select.c,v 1.106 2002/07/18 00:34:12 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -322,7 +322,7 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
       type = SQLITE_SO_TEXT;
     }else if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_NUM ){
       type = SQLITE_SO_NUM;
-    }else if( pParse->db->file_format>=3 ){
+    }else if( pParse->db->file_format>=4 ){
       type = sqliteExprType(pOrderBy->a[i].pExpr);
     }else{
       type = SQLITE_SO_NUM;
@@ -429,7 +429,7 @@ static int selectInnerLoop(
     sqliteVdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqliteVdbeCurrentAddr(v)+7);
 #endif
     sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1);
-    if( pParse->db->file_format>=3 ) sqliteAddKeyType(v, pEList);
+    if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pEList);
     sqliteVdbeAddOp(v, OP_Distinct, distinct, sqliteVdbeCurrentAddr(v)+3);
     sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0);
     sqliteVdbeAddOp(v, OP_Goto, 0, iContinue);
@@ -1968,7 +1968,7 @@ int sqliteSelect(
         sqliteExprCode(pParse, pGroupBy->a[i].pExpr);
       }
       sqliteVdbeAddOp(v, OP_MakeKey, pGroupBy->nExpr, 0);
-      if( pParse->db->file_format>=3 ) sqliteAddKeyType(v, pGroupBy);
+      if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pGroupBy);
       lbl1 = sqliteVdbeMakeLabel(v);
       sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1);
       for(i=0; i<pParse->nAgg; i++){
index 16b271ef38633fed7f6895802d592a18bf65793d..4b48ecc5294f9404bd009e80f6583495720e3577 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.138 2002/07/13 17:23:21 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.139 2002/07/18 00:34:12 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -187,7 +187,8 @@ typedef struct TriggerStack TriggerStack;
 **
 **     file_format==1    Version 2.1.0.
 **     file_format==2    Version 2.2.0. Add support for INTEGER PRIMARY KEY.
-**     file_format==3    Version 2.6.0. Add support for separate numeric and
+**     file_format==3    Version 2.6.0. Fix empty-string index bug.
+**     file_format==4    Version 2.7.0. Add support for separate numeric and
 **                       text datatypes.
 */
 struct sqlite {
index 3700a4baa6a73e603d79bc7853ea73d40d78035f..9e6161b821b084f35baa4ff8e4b79a0d8cc7e672 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.164 2002/07/05 21:42:37 drh Exp $
+** $Id: vdbe.c,v 1.165 2002/07/18 00:34:12 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -2634,6 +2634,20 @@ case OP_MakeRecord: {
 ** text.  The first character corresponds to the lowest element on the
 ** stack.  If P3 is NULL then all arguments are assumed to be numeric.
 **
+** The key is a concatenation of fields.  Each field is terminated by
+** a single 0x00 character.  A NULL field is introduced by an 'a' and
+** is followed immediately by its 0x00 terminator.  A numeric field is
+** introduced by a single character 'b' and is followed by a sequence
+** of characters that represent the number such that a comparison of
+** the character string using memcpy() sorts the numbers in numerical
+** order.  The character strings for numbers are generated using the
+** sqliteRealToSortable() function.  A text field is introduced by a
+** 'c' character and is followed by the exact text of the field.  The
+** use of an 'a', 'b', or 'c' character at the beginning of each field
+** guarantees that NULL sort before numbers and that numbers sort
+** before text.  0x00 characters do not occur except as separators
+** between fields.
+**
 ** See also: MakeIdxKey, SortMakeKey
 */
 /* Opcode: MakeIdxKey P1 P2 P3
@@ -2687,41 +2701,24 @@ case OP_MakeKey: {
       containsNull = 1;
     }else if( pOp->p3 && pOp->p3[j]=='t' ){
       Stringify(p, i);
-    }else if( flags & STK_Real ){
-      z = aStack[i].z;
-      sqliteRealToSortable(aStack[i].r, &z[1]);
-      z[0] = 0;
+      aStack[i].flags &= ~(STK_Int|STK_Real);
+      nByte += aStack[i].n+1;
+    }else if( (flags & (STK_Real|STK_Int))!=0 || isNumber(zStack[i]) ){
+      if( (flags & (STK_Real|STK_Int))==STK_Int ){
+        aStack[i].r = aStack[i].i;
+      }else if( (flags & (STK_Real|STK_Int))==0 ){
+        aStack[i].r = atof(zStack[i]);
+      }
       Release(p, i);
-      len = strlen(&z[1]);
-      zStack[i] = 0;
-      aStack[i].flags = STK_Real;
-      aStack[i].n = len+2;
-      nByte += aStack[i].n;
-    }else if( flags & STK_Int ){
       z = aStack[i].z;
-      aStack[i].r = aStack[i].i;
-      sqliteRealToSortable(aStack[i].r, &z[1]);
-      z[0] = 0;
-      Release(p, i);
-      len = strlen(&z[1]);
+      sqliteRealToSortable(aStack[i].r, z);
+      len = strlen(z);
       zStack[i] = 0;
-      aStack[i].flags = STK_Int;
-      aStack[i].n = len+2;
-      nByte += aStack[i].n;
+      aStack[i].flags = STK_Real;
+      aStack[i].n = len+1;
+      nByte += aStack[i].n+1;
     }else{
-      assert( flags & STK_Str );
-      if( isNumber(zStack[i]) ){
-        aStack[i].r = atof(zStack[i]);
-        Release(p, i);
-        z = aStack[i].z;
-        sqliteRealToSortable(aStack[i].r, &z[1]);
-        z[0] = 0;
-        len = strlen(&z[1]);
-        zStack[i] = 0;
-        aStack[i].flags = STK_Real;
-        aStack[i].n = len+2;
-      }
-      nByte += aStack[i].n;
+      nByte += aStack[i].n+1;
     }
   }
   if( nByte+sizeof(u32)>MAX_BYTES_PER_ROW ){
@@ -2734,9 +2731,14 @@ case OP_MakeKey: {
   j = 0;
   for(i=p->tos-nField+1; i<=p->tos; i++){
     if( aStack[i].flags & STK_Null ){
-      zNewKey[j++] = 0;
+      zNewKey[j++] = 'a';
       zNewKey[j++] = 0;
     }else{
+      if( aStack[i].flags & (STK_Int|STK_Real) ){
+        zNewKey[j++] = 'b';
+      }else{
+        zNewKey[j++] = 'c';
+      }
       memcpy(&zNewKey[j], zStack[i] ? zStack[i] : aStack[i].z, aStack[i].n);
       j += aStack[i].n;
     }
index d4ca515e00ab77174b6746344ad6de8132ea9c52..10e65618e2f10d5a598b489ce3a8e565a7f39b21 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.18 2002/07/13 03:11:54 drh Exp $
+# $Id: index.test,v 1.19 2002/07/18 00:34:13 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -415,4 +415,70 @@ do_test index-13.4 {
   }
 } {1 2 3 a b c}
 
+# Check the sort order of data in an index.
+#
+do_test index-14.1 {
+  execsql {
+    CREATE TABLE t6(a,b,c);
+    CREATE INDEX t6i1 ON t6(a,b);
+    INSERT INTO t6 VALUES('','',1);
+    INSERT INTO t6 VALUES('',NULL,2);
+    INSERT INTO t6 VALUES(NULL,'',3);
+    INSERT INTO t6 VALUES('abc',123,4);
+    INSERT INTO t6 VALUES(123,'abc',5);
+    SELECT c FROM t6 ORDER BY a,b;
+  }
+} {3 5 2 1 4}
+do_test index-14.2 {
+  execsql {
+    SELECT c FROM t6 WHERE a='';
+  }
+} {2 1}
+do_test index-14.3 {
+  execsql {
+    SELECT c FROM t6 WHERE b='';
+  }
+} {1 3}
+do_test index-14.4 {
+  execsql {
+    SELECT c FROM t6 WHERE a>'';
+  }
+} {4}
+do_test index-14.5 {
+  execsql {
+    SELECT c FROM t6 WHERE a>='';
+  }
+} {2 1 4}
+do_test index-14.6 {
+  execsql {
+    SELECT c FROM t6 WHERE a>123;
+  }
+} {2 1 4}
+do_test index-14.7 {
+  execsql {
+    SELECT c FROM t6 WHERE a>=123;
+  }
+} {5 2 1 4}
+do_test index-14.8 {
+  execsql {
+    SELECT c FROM t6 WHERE a<'abc';
+  }
+} {3 5 2 1}
+do_test index-14.9 {
+  execsql {
+    SELECT c FROM t6 WHERE a<='abc';
+  }
+} {3 5 2 1 4}
+do_test index-14.10 {
+  execsql {
+    SELECT c FROM t6 WHERE a<='';
+  }
+} {3 5 2 1}
+do_test index-14.11 {
+  execsql {
+    SELECT c FROM t6 WHERE a<'';
+  }
+} {3 5}
+
+
 finish_test