]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add internal support for collating sequences. This breaks 244 tests. (CVS 1420)
authordrh <drh@noemail.net>
Thu, 20 May 2004 22:16:29 +0000 (22:16 +0000)
committerdrh <drh@noemail.net>
Thu, 20 May 2004 22:16:29 +0000 (22:16 +0000)
FossilOrigin-Name: a6cb09d7af537726acc87b9133f68c81e839e047

20 files changed:
manifest
manifest.uuid
src/btree.c
src/build.c
src/expr.c
src/insert.c
src/main.c
src/parse.y
src/pragma.c
src/select.c
src/sqliteInt.h
src/test1.c
src/update.c
src/vdbe.c
src/vdbe.h
src/vdbeInt.h
src/vdbeaux.c
src/where.c
test/btree6.test
test/tester.tcl

index 135e363efda063a8c5edd4619ce02a3eda026735..a0c8b388f4e7fe3e280e1017d5cb18f2a777a6a2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C sqlite3MemCompare\snow\stakes\sa\sCollSeq*\sargument.\s(CVS\s1419)
-D 2004-05-20T13:54:54
+C Add\sinternal\ssupport\sfor\scollating\ssequences.\s\sThis\sbreaks\s244\stests.\s(CVS\s1420)
+D 2004-05-20T22:16:29
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -24,51 +24,51 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
 F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
 F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5
 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
-F src/btree.c 7abf1261c204e23aeeef12ec1bf75f5eca57d469
+F src/btree.c 68f8e0f6271afd31551abf0b48de9667c5f7368b
 F src/btree.h b65140b5ae891f30d2a39e64b9f0343225553545
 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
-F src/build.c 7310eb68de59281c6dbfe49b728200e3d89b91dd
+F src/build.c ec02b35d542d647ab22f31387733759ee0538826
 F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29
 F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
 F src/delete.c 2e1dda38345416a1ea1c0a6468589a7472334dac
 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
-F src/expr.c 22ee818d11c6dec2a4d1e8117b42c59928995e49
+F src/expr.c cba2b8c089ef03de307f028ac51eb53f583700d6
 F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a
 F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
 F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
-F src/insert.c 04865f0a8a5cbc81eab7ca7406498d5356ef0763
-F src/main.c 1bbb26e37c167443ee4c6c27b9150744be01ba81
+F src/insert.c e510d62d23b4de4d901e7ccbbe7833b7fb3b9570
+F src/main.c bb0e84eda9beb447bff109b061a82e6c9b3dc811
 F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
 F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
 F src/os.h 6e446a17cbeb6c2ce470683a0bb8d9c63abe8607
 F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5
 F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253
-F src/parse.y 4ed66f12583796dd4d5fff6860dc7e16f1d15cae
-F src/pragma.c 2332e7fa9d7cd4b21f30583a696bee36628404ca
+F src/parse.y 7c8eb3a305292fb4a0a9cee8c80ff68fdc1a1011
+F src/pragma.c aeeba7dc5bc32a6f0980e6516cb2a48a50973fab
 F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c 2510f0f16bf28108d89ba6e5680a9f090adc31b7
+F src/select.c 97c78398a825553f58139abaa0dd122c6834baca
 F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21
 F src/sqlite.h.in 8c000826a517ac7302dc2e1c483e71cd06eaf0de
-F src/sqliteInt.h 50ec7fb9635403ee71698d9fe0867564b915c52a
+F src/sqliteInt.h cdde94b620596f39d7b7a4835a8e9ff8d42ed1ec
 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
 F src/tclsqlite.c fbf0fac73624ae246551a6c671f1de0235b5faa1
-F src/test1.c cc6061579f0d9f1e952ad746394c34afd66a64f2
+F src/test1.c 5ba6352c8d63eae9eb98e6ae5bfe24a448b3bcb7
 F src/test2.c 6195a1ca2c8d0d2d93644e86da3289b403486872
 F src/test3.c 5e4a6d596f982f6f47a5f9f75ede9b4a3b739968
 F src/test4.c b3fab9aea7a8940a8a7386ce1c7e2157b09bd296
 F src/test5.c c92dca7028b19b9c8319d55e0a5037fc183640a6
 F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847
 F src/trigger.c 11afe9abfba13a2ba142944c797c952e162d117f
-F src/update.c 1f6687f8d1085f896a24c0fa13d802223ed55539
+F src/update.c 1a5e9182596f3ea8c7a141e308a3d2a7e5689fee
 F src/utf.c c27c4f1120f7aaef00cd6942b3d9e3f4ca4fe0e4
 F src/util.c 5cbeb452da09cfc7248de9948c15b14d840723f7
 F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
-F src/vdbe.c 4aedca4e37bd4762c1ad7f90e0ababf4ad52aa29
-F src/vdbe.h e75fe13aff16cc6e840371f473762615239264e4
-F src/vdbeInt.h 69a7dd040f0656e211d4e20b3cafdcee8461107e
-F src/vdbeaux.c b770802151f30589bd063f434174d230aa043406
-F src/where.c 626b2cbc4290d8be6c04ad7c8395f46d4e21d0d8
+F src/vdbe.c 09ba3911b8cab84604fa2019cfc252f175b74938
+F src/vdbe.h 5bf4ad99fcb5eee0fb72239775e85ef0d70911cf
+F src/vdbeInt.h cea492c1fcd85fb78f031e274d1844885d5222e2
+F src/vdbeaux.c 4446afcd568d4002cf2020691d38cdf2c799bc9b
+F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
 F test/attach2.test 7c388dee63a4c1997695c3d41957f32ce784ac56
@@ -80,7 +80,7 @@ F test/btree.test 08e4093c78d2bc1d54e27266f8d17fed14751125
 F test/btree2.test aa4a6d05b1ea90b1acaf83ba89039dd302a88635
 F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4
 F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
-F test/btree6.test b7524d7165faff496a767dfa2c78a1ae4d8ba09a
+F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
 F test/capi2.test ec96e0e235d87b53cbaef3d8e3e0f8ccf32c71ca
 F test/capi3.test acc3919c0f37e85ac3561fc33d6abf7183e1aee1
 F test/conflict.test 0911bb2f079046914a6e9c3341b36658c4e2103e
@@ -137,7 +137,7 @@ F test/table.test 50e4534552d0385a0e59b3a6d7dde059ced02f83
 F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1
 F test/tclsqlite.test a684fc191b81e6cded8a81263663d5a130fbb013
 F test/temptable.test a770ba6308d7f7332fce985086b8e06bed6430c2
-F test/tester.tcl 4b7e254be6b3f817d992f42391a73465d7330f16
+F test/tester.tcl 4f7d3ec86d86d9e6ce6939ad6dba4438d8375fba
 F test/thread1.test 53f050d5be6932d9430df7756edd379366508ff6
 F test/threadtest1.c f7f896e62ed46feae1dc411114a48c15a0f82ee2
 F test/threadtest2.c d94ca4114fd1504f7e0ae724bcd83d4b40931d86
@@ -195,7 +195,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 8411718f0ac17e9c2376fdf8b5fa0cc5fc88be9b
-R 0120dca1e321b23f5d0817fb2f4d18f3
+P 5c1e47a25244eacc69b688f5f4e62cec9f09665a
+R ce21bc93f28abe94d7cac8a777c1f594
 U drh
-Z 85c2c075127be3f9e1f00b69921810df
+Z 85f85a1caf6d7ec42aba1c203751fff5
index e70de3aee0d5927624ef149afcf931c9a6e3586d..26a76249a40b7e213680ecc6211c6adcc5a2af61 100644 (file)
@@ -1 +1 @@
-5c1e47a25244eacc69b688f5f4e62cec9f09665a
\ No newline at end of file
+a6cb09d7af537726acc87b9133f68c81e839e047
\ No newline at end of file
index 8ee854e354cf6e1d274b1662e72bf227d8d91070..481bf2e6454e0aca9c120f994d6d1023ea2bd41f 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.144 2004/05/20 02:01:27 drh Exp $
+** $Id: btree.c,v 1.145 2004/05/20 22:16:29 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -1406,10 +1406,13 @@ create_cursor_exception:
   return rc;
 }
 
+/*
+** Change the value of the comparison function used by a cursor.
+*/
 void sqlite3BtreeSetCompare(
-  BtCursor *pCur,
-  int(* xCmp)(void*,int,const void*,int,const void*),
-  void *pArg
+  BtCursor *pCur,     /* The cursor to whose comparison function is changed */
+  int(*xCmp)(void*,int,const void*,int,const void*), /* New comparison func */
+  void *pArg          /* First argument to xCmp() */
 ){
   pCur->xCompare = xCmp ? xCmp : dfltCompare;
   pCur->pArg = pArg;
index cd9bac81b2cccd5b0fbe07399b2020bae54c737f..84cd83026c73649880e51fd1ec022f2f94c3cc4f 100644 (file)
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.189 2004/05/20 12:41:20 drh Exp $
+** $Id: build.c,v 1.190 2004/05/20 22:16:29 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -591,6 +591,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
   ** will be called next to set pCol->affinity correctly.
   */
   pCol->affinity = SQLITE_AFF_NUMERIC;
+  pCol->pColl = pParse->db->pDfltColl;
   p->nCol++;
 }
 
@@ -703,7 +704,9 @@ void sqlite3AddPrimaryKey(Parse *pParse, IdList *pList, int onError){
   }else{
     for(i=0; i<pList->nId; i++){
       for(iCol=0; iCol<pTab->nCol; iCol++){
-        if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ) break;
+        if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){
+          break;
+        }
       }
       if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
     }
@@ -726,44 +729,73 @@ primary_key_exit:
 }
 
 /*
-** Return the appropriate collating type given a type name.
-**
-** The collation type is text (SQLITE_SO_TEXT) if the type
-** name contains the character stream "text" or "blob" or
-** "clob".  Any other type name is collated as numeric
-** (SQLITE_SO_NUM).
+** Return a pointer to CollSeq given the name of a collating sequence.
+** If the collating sequence did not previously exist, create it but
+** assign it an NULL comparison function.
 */
-int sqlite3CollateType(const char *zType, int nType){
-  int i;
-  for(i=0; i<nType-3; i++){
-    int c = *(zType++) | 0x60;
-    if( (c=='b' || c=='c') && sqlite3StrNICmp(zType, "lob", 3)==0 ){
-      return SQLITE_SO_TEXT;
-    }
-    if( c=='c' && sqlite3StrNICmp(zType, "har", 3)==0 ){
-      return SQLITE_SO_TEXT;
-    }
-    if( c=='t' && sqlite3StrNICmp(zType, "ext", 3)==0 ){
-      return SQLITE_SO_TEXT;
-    }
+CollSeq *sqlite3CollateType(Parse *pParse, const char *zType, int nType){
+  CollSeq *pColl;
+  sqlite *db = pParse->db;
+
+  pColl = sqlite3HashFind(&db->aCollSeq, zType, nType);
+  if( pColl==0 ){
+    sqlite3ChangeCollatingFunction(db, zType, nType, 0, 0);
+    pColl = sqlite3HashFind(&db->aCollSeq, zType, nType);
   }
-  return SQLITE_SO_NUM;
+  return pColl;
 }
 
 /*
-** This routine is called by the parser while in the middle of
-** parsing a CREATE TABLE statement.  A "COLLATE" clause has
-** been seen on a column.  This routine sets the Column.sortOrder on
-** the column currently under construction.
+** Set the collation function of the most recently parsed table column
+** to the CollSeq given.
 */
-void sqlite3AddCollateType(Parse *pParse, int collType){
+void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
   Table *p;
-  int i;
+  CollSeq *pColl;
+  sqlite *db = pParse->db;
+
   if( (p = pParse->pNewTable)==0 ) return;
-  i = p->nCol-1;
+  pColl = sqlite3HashFind(&db->aCollSeq, zType, nType);
+  if( pColl==0 ){
+    pColl = sqlite3ChangeCollatingFunction(db, zType, nType, 0, 0);
+  }
+  if( pColl ){
+    p->aCol[p->nCol-1].pColl = pColl;
+  }
+}
 
-  /* FIX ME */
-  /* if( i>=0 ) p->aCol[i].sortOrder = collType; */
+/*
+** Create or modify a collating sequence entry in the sqlite.aCollSeq
+** table.
+**
+** Once an entry is added to the sqlite.aCollSeq table, it can never
+** be removed, though is comparison function or user data can be changed.
+**
+** Return a pointer to the collating function that was created or modified.
+*/
+CollSeq *sqlite3ChangeCollatingFunction(
+  sqlite *db,             /* Database into which to insert the collation */
+  const char *zName,      /* Name of the collation */
+  int nName,              /* Number of characters in zName */
+  void *pUser,            /* First argument to xCmp */
+  int (*xCmp)(void*,int,const void*,int,const void*) /* Comparison function */
+){
+  CollSeq *pColl;
+
+  pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
+  if( pColl==0 ){
+    pColl = sqliteMallocRaw( sizeof(*pColl) + nName + 1 );
+    if( pColl==0 ){
+      return 0;
+    }
+    pColl->zName = (char*)&pColl[1];
+    pColl->reverseOrder = 0;
+    memcpy(pColl->zName, zName, nName+1);
+    sqlite3HashInsert(&db->aCollSeq, pColl->zName, nName, pColl);
+  }
+  pColl->pUser = pUser;
+  pColl->xCmp = xCmp;
+  return pColl;
 }
 
 /*
@@ -1606,9 +1638,9 @@ void sqlite3CreateIndex(
   ** Allocate the index structure. 
   */
   pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
-                        sizeof(int)*pList->nId );
+                        (sizeof(int) + sizeof(CollSeq*))*pList->nId );
   if( pIndex==0 ) goto exit_create_index;
-  pIndex->aiColumn = (int*)&pIndex[1];
+  pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nId];
   pIndex->zName = (char*)&pIndex->aiColumn[pList->nId];
   strcpy(pIndex->zName, zName);
   pIndex->pTable = pTab;
@@ -1632,7 +1664,9 @@ void sqlite3CreateIndex(
       goto exit_create_index;
     }
     pIndex->aiColumn[i] = j;
+    pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
   }
+  pIndex->keyInfo.nField = pList->nId;
 
   /* Link the new Index structure to its table and to the other
   ** in-memory database structures. 
@@ -1713,8 +1747,9 @@ void sqlite3CreateIndex(
       sqlite3VdbeCode(v,
           OP_Dup,       0,      0,
           OP_Integer,   isTemp, 0,
-          OP_OpenWrite, 1,      0,
       0);
+      sqlite3VdbeOp3(v, OP_OpenWrite, 1, 0,
+                     (char*)&pIndex->keyInfo, P3_KEYINFO);
     }
     addr = sqlite3VdbeAddOp(v, OP_String, 0, 0);
     if( pStart && pEnd ){
@@ -1725,7 +1760,8 @@ void sqlite3CreateIndex(
     sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
     if( pTable ){
       sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
-      sqlite3VdbeOp3(v, OP_OpenRead, 2, pTab->tnum, pTab->zName, 0);
+      sqlite3VdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
+      /* VdbeComment((v, "%s", pTab->zName)); */
       sqlite3VdbeAddOp(v, OP_SetNumColumns, 2, pTab->nCol);
       lbl2 = sqlite3VdbeMakeLabel(v);
       sqlite3VdbeAddOp(v, OP_Rewind, 2, lbl2);
index 1987169e0b9fc279cb6bdc964c07a2112546c62b..f1776e065b5e7b02e293febadd02956179ed2b45 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.124 2004/05/20 13:54:54 drh Exp $
+** $Id: expr.c,v 1.125 2004/05/20 22:16:29 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -588,10 +588,6 @@ static int lookupName(
         /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
         pExpr->iColumn = j==pTab->iPKey ? -1 : j;
         pExpr->affinity = pTab->aCol[j].affinity;
-
-        /* FIX ME: Expr::dataType will be removed... */
-        pExpr->dataType =
-            (pCol->affinity==SQLITE_AFF_TEXT?SQLITE_SO_TEXT:SQLITE_SO_NUM);
         break;
       }
     }
@@ -624,9 +620,6 @@ static int lookupName(
           cnt++;
           pExpr->iColumn = j==pTab->iPKey ? -1 : j;
           pExpr->affinity = pTab->aCol[j].affinity;
-          /* FIX ME: Expr::dataType will be removed... */
-          pExpr->dataType =
-              (pCol->affinity==SQLITE_AFF_TEXT?SQLITE_SO_TEXT:SQLITE_SO_NUM);
           break;
         }
       }
@@ -639,7 +632,6 @@ static int lookupName(
   if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){
     cnt = 1;
     pExpr->iColumn = -1;
-    pExpr->dataType = SQLITE_SO_NUM;
     pExpr->affinity = SQLITE_AFF_INTEGER;
   }
 
@@ -805,6 +797,8 @@ int sqlite3ExprResolveIds(
     case TK_IN: {
       char affinity;
       Vdbe *v = sqlite3GetVdbe(pParse);
+      KeyInfo keyInfo;
+
       if( v==0 ) return 1;
       if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
         return 1;
@@ -825,7 +819,11 @@ int sqlite3ExprResolveIds(
       ** is used.
       */
       pExpr->iTable = pParse->nTab++;
-      sqlite3VdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 1);
+      memset(&keyInfo, 0, sizeof(keyInfo));
+      keyInfo.nField = 1;
+      keyInfo.aColl[0] = pParse->db->pDfltColl;
+      sqlite3VdbeOp3(v, OP_OpenTemp, pExpr->iTable, 0, \
+           (char*)&keyInfo, P3_KEYINFO);
 
       if( pExpr->pSelect ){
         /* Case 1:     expr IN (SELECT ...)
@@ -1002,28 +1000,8 @@ int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
         nErr = sqlite3ExprCheck(pParse, pExpr->pList->a[i].pExpr,
                                allowAgg && !is_agg, pIsAgg);
       }
-      if( pDef==0 ){
-        /* Already reported an error */
-      }else if( pDef->dataType>=0 ){
-        if( pDef->dataType<n ){
-          pExpr->dataType = 
-             sqlite3ExprType(pExpr->pList->a[pDef->dataType].pExpr);
-        }else{
-          pExpr->dataType = SQLITE_SO_NUM;
-        }
-      }else if( pDef->dataType==SQLITE_ARGS ){
-        pDef->dataType = SQLITE_SO_TEXT;
-        for(i=0; i<n; i++){
-          if( sqlite3ExprType(pExpr->pList->a[i].pExpr)==SQLITE_SO_NUM ){
-            pExpr->dataType = SQLITE_SO_NUM;
-            break;
-          }
-        }
-      }else if( pDef->dataType==SQLITE_NUMERIC ){
-        pExpr->dataType = SQLITE_SO_NUM;
-      }else{
-        pExpr->dataType = SQLITE_SO_TEXT;
-      }
+      /** TODO:  Compute pExpr->affinity based on the expected return
+      ** type of the function */
     }
     default: {
       if( pExpr->pLeft ){
@@ -1047,95 +1025,37 @@ int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
 }
 
 /*
-** Return either SQLITE_SO_NUM or SQLITE_SO_TEXT to indicate whether the
-** given expression should sort as numeric values or as text.
+** Return one of the SQLITE_AFF_* affinity types that indicates the likely
+** data type of the result of the given expression.
+**
+** Not every expression has a fixed type.  If the type cannot be determined
+** at compile-time, then try to return the type affinity if the expression
+** is a column.  Otherwise just return SQLITE_AFF_NONE.
 **
 ** The sqlite3ExprResolveIds() and sqlite3ExprCheck() routines must have
 ** both been called on the expression before it is passed to this routine.
 */
 int sqlite3ExprType(Expr *p){
-  if( p==0 ) return SQLITE_SO_NUM;
+  if( p==0 ) return SQLITE_AFF_NONE;
   while( p ) switch( p->op ){
-    case TK_PLUS:
-    case TK_MINUS:
-    case TK_STAR:
-    case TK_SLASH:
-    case TK_AND:
-    case TK_OR:
-    case TK_ISNULL:
-    case TK_NOTNULL:
-    case TK_NOT:
-    case TK_UMINUS:
-    case TK_UPLUS:
-    case TK_BITAND:
-    case TK_BITOR:
-    case TK_BITNOT:
-    case TK_LSHIFT:
-    case TK_RSHIFT:
-    case TK_REM:
-    case TK_INTEGER:
-    case TK_FLOAT:
-    case TK_IN:
-    case TK_BETWEEN:
-    case TK_GLOB:
-    case TK_LIKE:
-      return SQLITE_SO_NUM;
-
-    case TK_STRING:
-    case TK_NULL:
     case TK_CONCAT:
-    case TK_VARIABLE:
-      return SQLITE_SO_TEXT;
-
-    case TK_LT:
-    case TK_LE:
-    case TK_GT:
-    case TK_GE:
-    case TK_NE:
-    case TK_EQ:
-      if( sqlite3ExprType(p->pLeft)==SQLITE_SO_NUM ){
-        return SQLITE_SO_NUM;
-      }
-      p = p->pRight;
-      break;
+      return SQLITE_AFF_TEXT;
 
     case TK_AS:
       p = p->pLeft;
       break;
 
-    case TK_COLUMN:
-    case TK_FUNCTION:
-    case TK_AGG_FUNCTION:
-      return p->dataType;
-
-    case TK_SELECT:
-      assert( p->pSelect );
-      assert( p->pSelect->pEList );
-      assert( p->pSelect->pEList->nExpr>0 );
-      p = p->pSelect->pEList->a[0].pExpr;
-      break;
+    case TK_NULL:
+      return SQLITE_AFF_NONE;
 
-    case TK_CASE: {
-      if( p->pRight && sqlite3ExprType(p->pRight)==SQLITE_SO_NUM ){
-        return SQLITE_SO_NUM;
-      }
-      if( p->pList ){
-        int i;
-        ExprList *pList = p->pList;
-        for(i=1; i<pList->nExpr; i+=2){
-          if( sqlite3ExprType(pList->a[i].pExpr)==SQLITE_SO_NUM ){
-            return SQLITE_SO_NUM;
-          }
-        }
-      }
-      return SQLITE_SO_TEXT;
-    }
+    case TK_SELECT:   /*** FIX ME ****/
+    case TK_COLUMN:   /*** FIX ME ****/
+    case TK_CASE:     /*** FIX ME ****/
 
     default:
-      assert( p->op==TK_ABORT );  /* Can't Happen */
-      break;
+      return SQLITE_AFF_NUMERIC;
   }
-  return SQLITE_SO_NUM;
+  return SQLITE_AFF_NONE;
 }
 
 /*
@@ -1444,9 +1364,8 @@ int sqlite3ExprCodeExprList(
   for(pItem=pList->a, i=0; i<n; i++, pItem++){
     sqlite3ExprCode(pParse, pItem->pExpr);
     if( includeTypes ){
-      sqlite3VdbeOp3(v, OP_String, 0, 0, 
-         sqlite3ExprType(pItem->pExpr)==SQLITE_SO_NUM ? "numeric" : "text",
-         P3_STATIC);
+      /** DEPRECATED.  This will go away with the new function interface **/
+      sqlite3VdbeOp3(v, OP_String, 0, 0, "numeric", P3_STATIC);
     }
   }
   return includeTypes ? n*2 : n;
index d105ad19529e616d250fc808c23616c28d580684..c122643d4df535d8b69389daf0a5b35b6d84f4b3 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.104 2004/05/20 02:42:16 drh Exp $
+** $Id: insert.c,v 1.105 2004/05/20 22:16:29 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -1002,11 +1002,12 @@ int sqlite3OpenTableAndIndices(Parse *pParse, Table *pTab, int base){
   Vdbe *v = sqlite3GetVdbe(pParse);
   assert( v!=0 );
   sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
-  sqlite3VdbeOp3(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, P3_STATIC);
+  sqlite3VdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
   sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol);
   for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
     sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
-    sqlite3VdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, pIdx->zName, P3_STATIC);
+    sqlite3VdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum,
+                   (char*)&pIdx->keyInfo, P3_KEYINFO);
   }
   return i;
 }
index d0e7297ce4f27119bc87eb670cb892966a4e5753..84c4d96edca19872e6e410bbd3adab59f44c2269 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.177 2004/05/20 11:00:52 danielk1977 Exp $
+** $Id: main.c,v 1.178 2004/05/20 22:16:29 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -375,6 +375,24 @@ const char sqlite3_encoding[] = "UTF-8";
 const char sqlite3_encoding[] = "iso8859";
 #endif
 
+/*
+** This is the default collating function named "BINARY" which is always
+** available.
+*/
+static int binaryCollatingFunc(
+  void *NotUsed,
+  int nKey1, const void *pKey1,
+  int nKey2, const void *pKey2
+){
+  int rc, n;
+  n = nKey1<nKey2 ? nKey1 : nKey2;
+  rc = memcmp(pKey1, pKey2, n);
+  if( rc==0 ){
+    rc = nKey1 - nKey2;
+  }
+  return rc;
+}
+
 /*
 ** Open a new SQLite database.  Construct an "sqlite" structure to define
 ** the state of this database and return a pointer to that structure.
@@ -399,12 +417,15 @@ sqlite *sqlite3_open(const char *zFilename, int mode, char **pzErrMsg){
   db->aDb = db->aDbStatic;
   /* db->flags |= SQLITE_ShortColNames; */
   sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
+  sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
   for(i=0; i<db->nDb; i++){
     sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
     sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
     sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
     sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
   }
+  db->pDfltColl =
+     sqlite3ChangeCollatingFunction(db, "BINARY", 6, 0, binaryCollatingFunc);
   
   /* Open the backend database driver */
   if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){
index c4dad6906c8101feb6a5176fcd5985d5e8e5a612..4bfa6a81b04cd0be41025690b2ba7066de5335d9 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.115 2004/05/20 12:41:20 drh Exp $
+** @(#) $Id: parse.y,v 1.116 2004/05/20 22:16:29 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -193,9 +193,7 @@ ccons ::= CHECK LP expr RP onconf.
 ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
                                 {sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
 ccons ::= defer_subclause(D).   {sqlite3DeferForeignKey(pParse,D);}
-ccons ::= COLLATE id(C).  {
-   sqlite3AddCollateType(pParse, sqlite3CollateType(C.z, C.n));
-}
+ccons ::= COLLATE id(C).  {sqlite3AddCollateType(pParse, C.z, C.n);}
 
 // The next group of rules parses the arguments to a REFERENCES clause
 // that determine if the referential integrity checking is deferred or
@@ -437,23 +435,23 @@ using_opt(U) ::= .                        {U = 0;}
 orderby_opt(A) ::= .                          {A = 0;}
 orderby_opt(A) ::= ORDER BY sortlist(X).      {A = X;}
 sortlist(A) ::= sortlist(X) COMMA sortitem(Y) collate(C) sortorder(Z). {
-  A = sqlite3ExprListAppend(X,Y,0);
-  if( A ) A->a[A->nExpr-1].sortOrder = C+Z;
+  A = sqlite3ExprListAppend(X,Y,&C);
+  if( A ) A->a[A->nExpr-1].sortOrder = Z;
 }
 sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). {
-  A = sqlite3ExprListAppend(0,Y,0);
-  if( A ) A->a[0].sortOrder = C+Z;
+  A = sqlite3ExprListAppend(0,Y,&C);
+  if( A ) A->a[0].sortOrder = Z;
 }
 sortitem(A) ::= expr(X).   {A = X;}
 
 %type sortorder {int}
-%type collate {int}
+%type collate {Token}
 
 sortorder(A) ::= ASC.           {A = SQLITE_SO_ASC;}
 sortorder(A) ::= DESC.          {A = SQLITE_SO_DESC;}
 sortorder(A) ::= .              {A = SQLITE_SO_ASC;}
-collate(C) ::= .                {C = SQLITE_SO_UNK;}
-collate(C) ::= COLLATE id(X).   {C = sqlite3CollateType(X.z, X.n);}
+collate(C) ::= .                {C.z = 0; C.n = 0;}
+collate(C) ::= COLLATE id(X).   {C = X;}
 
 %type groupby_opt {ExprList*}
 %destructor groupby_opt {sqlite3ExprListDelete($$);}
index c167ec004438a0d887ee922348d9c435268ba85d..47b0a172780240152c607b5e3200bf163ee94232 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the PRAGMA command.
 **
-** $Id: pragma.c,v 1.26 2004/05/18 22:17:46 drh Exp $
+** $Id: pragma.c,v 1.27 2004/05/20 22:16:29 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -638,12 +638,13 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
 
         if( pTab->pIndex==0 ) continue;
         sqlite3VdbeAddOp(v, OP_Integer, i, 0);
-        sqlite3VdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0);
+        sqlite3VdbeAddOp(v, OP_OpenRead, 1, pTab->tnum);
         sqlite3VdbeAddOp(v, OP_SetNumColumns, 1, pTab->nCol);
         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
           if( pIdx->tnum==0 ) continue;
           sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
-          sqlite3VdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0);
+          sqlite3VdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, 
+                         (char*)&pIdx->keyInfo, P3_KEYINFO);
         }
         sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
         sqlite3VdbeAddOp(v, OP_MemStore, 1, 1);
index 633dca59aa0d8eae1dd54546fa278d9bd6f0abd5..7565804c7d1053b767867774d3942c32e2947f39 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.170 2004/05/20 03:02:47 drh Exp $
+** $Id: select.c,v 1.171 2004/05/20 22:16:29 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -324,19 +324,11 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
   if( zSortOrder==0 ) return;
   for(i=0; i<pOrderBy->nExpr; i++){
     int order = pOrderBy->a[i].sortOrder;
-    int type;
     int c;
-    if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){
-      type = SQLITE_SO_TEXT;
-    }else if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_NUM ){
-      type = SQLITE_SO_NUM;
+    if( order==SQLITE_SO_ASC ){
+      c = 'A';
     }else{
-      type = sqlite3ExprType(pOrderBy->a[i].pExpr);
-    }
-    if( (order & SQLITE_SO_DIRMASK)==SQLITE_SO_ASC ){
-      c = type==SQLITE_SO_TEXT ? 'A' : '+';
-    }else{
-      c = type==SQLITE_SO_TEXT ? 'D' : '-';
+      c = 'D';
     }
     zSortOrder[i] = c;
     sqlite3ExprCode(pParse, pOrderBy->a[i].pExpr);
@@ -346,28 +338,6 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
   sqlite3VdbeAddOp(v, OP_SortPut, 0, 0);
 }
 
-/*
-** This routine adds a P3 argument to the last VDBE opcode that was
-** inserted. The P3 argument added is a string suitable for the 
-** OP_MakeKey or OP_MakeIdxKey opcodes.  The string consists of
-** characters 't' or 'n' depending on whether or not the various
-** fields of the key to be generated should be treated as numeric
-** or as text.  See the OP_MakeKey and OP_MakeIdxKey opcode
-** documentation for additional information about the P3 string.
-** See also the sqlite3AddIdxKeyType() routine.
-*/
-void sqlite3AddKeyType(Vdbe *v, ExprList *pEList){
-  int nColumn = pEList->nExpr;
-  char *zType = sqliteMalloc( nColumn+1 );
-  int i;
-  if( zType==0 ) return;
-  for(i=0; i<nColumn; i++){
-    zType[i] = sqlite3ExprType(pEList->a[i].pExpr)==SQLITE_SO_NUM ? 'n' : 't';
-  }
-  zType[i] = 0;
-  sqlite3VdbeChangeP3(v, -1, zType, P3_DYNAMIC);
-}
-
 /*
 ** This routine generates the code for the inside of the inner loop
 ** of a SELECT.
@@ -432,8 +402,8 @@ static int selectInnerLoop(
 #if NULL_ALWAYS_DISTINCT
     sqlite3VdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqlite3VdbeCurrentAddr(v)+7);
 #endif
+    /* Deliberately leave the affinity string off of the following OP_MakeKey */
     sqlite3VdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1);
-    sqlite3AddKeyType(v, pEList);
     sqlite3VdbeAddOp(v, OP_Distinct, distinct, sqlite3VdbeCurrentAddr(v)+3);
     sqlite3VdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0);
     sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
@@ -682,11 +652,9 @@ static void generateColumnTypes(
         zType = pTab->aCol[iCol].zType;
       }
     }else{
-      if( sqlite3ExprType(p)==SQLITE_SO_TEXT ){
-        zType = "TEXT";
-      }else{
-        zType = "NUMERIC";
-      }
+      zType = "ANY";
+      /** TODO:  Perhaps something related to the affinity of the 
+      ** exprsssion? */
     }
     sqlite3VdbeOp3(v, OP_ColumnName, i + pEList->nExpr, 0, zType, 0);
   }
@@ -1079,13 +1047,6 @@ void sqlite3SelectUnbind(Select *p){
 **
 ** Any entry that does not match is flagged as an error.  The number
 ** of errors is returned.
-**
-** This routine does NOT correctly initialize the Expr.dataType  field
-** of the ORDER BY expressions.  The multiSelectSortOrder() routine
-** must be called to do that after the individual select statements
-** have all been analyzed.  This routine is unable to compute Expr.dataType
-** because it must be called before the individual select statements
-** have been analyzed.
 */
 static int matchOrderbyToColumn(
   Parse *pParse,          /* A place to leave error messages */
@@ -1170,55 +1131,7 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){
   return v;
 }
 
-/*
-** This routine sets the Expr.dataType field on all elements of
-** the pOrderBy expression list.  The pOrderBy list will have been
-** set up by matchOrderbyToColumn().  Hence each expression has
-** a TK_COLUMN as its root node.  The Expr.iColumn refers to a 
-** column in the result set.   The datatype is set to SQLITE_SO_TEXT
-** if the corresponding column in p and every SELECT to the left of
-** p has a datatype of SQLITE_SO_TEXT.  If the cooressponding column
-** in p or any of the left SELECTs is SQLITE_SO_NUM, then the datatype
-** of the order-by expression is set to SQLITE_SO_NUM.
-**
-** Examples:
-**
-**     CREATE TABLE one(a INTEGER, b TEXT);
-**     CREATE TABLE two(c VARCHAR(5), d FLOAT);
-**
-**     SELECT b, b FROM one UNION SELECT d, c FROM two ORDER BY 1, 2;
-**
-** The primary sort key will use SQLITE_SO_NUM because the "d" in
-** the second SELECT is numeric.  The 1st column of the first SELECT
-** is text but that does not matter because a numeric always overrides
-** a text.
-**
-** The secondary key will use the SQLITE_SO_TEXT sort order because
-** both the (second) "b" in the first SELECT and the "c" in the second
-** SELECT have a datatype of text.
-*/ 
-static void multiSelectSortOrder(Select *p, ExprList *pOrderBy){
-  int i;
-  ExprList *pEList;
-  if( pOrderBy==0 ) return;
-  if( p==0 ){
-    for(i=0; i<pOrderBy->nExpr; i++){
-      pOrderBy->a[i].pExpr->dataType = SQLITE_SO_TEXT;
-    }
-    return;
-  }
-  multiSelectSortOrder(p->pPrior, pOrderBy);
-  pEList = p->pEList;
-  for(i=0; i<pOrderBy->nExpr; i++){
-    Expr *pE = pOrderBy->a[i].pExpr;
-    if( pE->dataType==SQLITE_SO_NUM ) continue;
-    assert( pE->iColumn>=0 );
-    if( pEList->nExpr>pE->iColumn ){
-      pE->dataType = sqlite3ExprType(pEList->a[pE->iColumn].pExpr);
-    }
-  }
-}
-
+#if 0  /***** This routine needs deleting *****/
 static void multiSelectAffinity(Select *p, char *zAff){
   int i;
 
@@ -1231,6 +1144,7 @@ static void multiSelectAffinity(Select *p, char *zAff){
     }
   }
 }
+#endif
 
 /*
 ** Compute the iLimit and iOffset fields of the SELECT based on the
@@ -1278,6 +1192,35 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
   }
 }
 
+/*
+** Generate VDBE instructions that will open a transient table that
+** will be used for an index or to store keyed results for a compound
+** select.  In other words, open a transient table that needs a
+** KeyInfo structure.  The number of columns in the KeyInfo is determined
+** by the result set of the SELECT statement in the second argument.
+**
+** Make the new table a KeyAsData table if keyAsData is true.
+*/
+static void openTempIndex(Parse *pParse, Select *p, int iTab, int keyAsData){
+  KeyInfo *pKeyInfo;
+  int nColumn = p->pEList->nExpr;
+  sqlite *db = pParse->db;
+  int i;
+  Vdbe *v = pParse->pVdbe;
+
+  pKeyInfo = sqliteMalloc( sizeof(*pKeyInfo)+nColumn*sizeof(CollSeq*) );
+  if( pKeyInfo==0 ) return;
+  pKeyInfo->nField = nColumn;
+  for(i=0; i<nColumn; i++){
+    pKeyInfo->aColl[i] = db->pDfltColl;
+  }
+  sqlite3VdbeOp3(v, OP_OpenTemp, iTab, 0, (char*)pKeyInfo, P3_KEYINFO);
+  sqliteFree(pKeyInfo);
+  if( keyAsData ){
+    sqlite3VdbeAddOp(v, OP_KeyAsData, iTab, 1);
+  }
+}
+
 /*
 ** This routine is called to process a query that is really the union
 ** or intersection of two or more separate queries.
@@ -1320,6 +1263,7 @@ static int multiSelect(
   Vdbe *v;            /* Generate code to this VDBE */
   char *affStr = 0;
 
+#if 0 /* NOT USED */
   if( !aff ){
     int len;
     rc = fillInColumnList(pParse, p);
@@ -1335,6 +1279,7 @@ static int multiSelect(
     memset(affStr, (int)SQLITE_AFF_NUMERIC, len-1);
     aff = affStr;
   }
+#endif
 
   /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs.  Only
   ** the last SELECT in the series may have an ORDER BY or LIMIT.
@@ -1424,8 +1369,7 @@ static int multiSelect(
           goto multi_select_end;
         }
         if( p->op!=TK_ALL ){
-          sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 1);
-          sqlite3VdbeAddOp(v, OP_KeyAsData, unionTab, 1);
+          openTempIndex(pParse, p, unionTab, 1);
         }else{
           sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 0);
         }
@@ -1481,7 +1425,6 @@ static int multiSelect(
         sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak);
         computeLimitRegisters(pParse, p);
         iStart = sqlite3VdbeCurrentAddr(v);
-        multiSelectSortOrder(p, p->pOrderBy);
         rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
                              p->pOrderBy, -1, eDest, iParm, 
                              iCont, iBreak, 0);
@@ -1514,8 +1457,7 @@ static int multiSelect(
         rc = 1;
         goto multi_select_end;
       }
-      sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 1);
-      sqlite3VdbeAddOp(v, OP_KeyAsData, tab1, 1);
+      openTempIndex(pParse, p, tab1, 1);
       assert( p->pEList );
 
       /* Code the SELECTs to our left into temporary table "tab1".
@@ -1527,8 +1469,7 @@ static int multiSelect(
 
       /* Code the current SELECT into temporary table "tab2"
       */
-      sqlite3VdbeAddOp(v, OP_OpenTemp, tab2, 1);
-      sqlite3VdbeAddOp(v, OP_KeyAsData, tab2, 1);
+      openTempIndex(pParse, p, tab2, 1);
       p->pPrior = 0;
       nLimit = p->nLimit;
       p->nLimit = -1;
@@ -1556,7 +1497,6 @@ static int multiSelect(
       computeLimitRegisters(pParse, p);
       iStart = sqlite3VdbeAddOp(v, OP_FullKey, tab1, 0);
       sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);
-      multiSelectSortOrder(p, p->pOrderBy);
       rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
                              p->pOrderBy, -1, eDest, iParm, 
                              iCont, iBreak, 0);
@@ -1584,6 +1524,7 @@ static int multiSelect(
   }
 
 multi_select_end:
+#if 0  /*** NOT USED ****/
   if( affStr ){
     if( rc!=SQLITE_OK ){
       sqliteFree(affStr);
@@ -1592,6 +1533,7 @@ multi_select_end:
       sqlite3VdbeOp3(v, OP_Noop, 0, 0, affStr, P3_DYNAMIC);
     }
   }
+#endif
   return rc;
 }
 
@@ -1621,7 +1563,6 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
       pNew = pEList->a[pExpr->iColumn].pExpr;
       assert( pNew!=0 );
       pExpr->op = pNew->op;
-      pExpr->dataType = pNew->dataType;
       assert( pExpr->pLeft==0 );
       pExpr->pLeft = sqlite3ExprDup(pNew->pLeft);
       assert( pExpr->pRight==0 );
@@ -2011,7 +1952,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
   computeLimitRegisters(pParse, p);
   if( pSrc->a[0].pSelect==0 ){
     sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
-    sqlite3VdbeOp3(v, OP_OpenRead, base, pTab->tnum, pTab->zName, 0);
+    sqlite3VdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
     sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol);
   }
   cont = sqlite3VdbeMakeLabel(v);
@@ -2019,7 +1960,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
     sqlite3VdbeAddOp(v, seekOp, base, 0);
   }else{
     sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
-    sqlite3VdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum, pIdx->zName, P3_STATIC);
+    sqlite3VdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum,
+                   (char*)&pIdx->keyInfo, P3_KEYINFO);
     sqlite3VdbeAddOp(v, seekOp, base+1, 0);
     sqlite3VdbeAddOp(v, OP_IdxRecno, base+1, 0);
     sqlite3VdbeAddOp(v, OP_Close, base+1, 0);
@@ -2274,6 +2216,7 @@ int sqlite3Select(
     generateColumnNames(pParse, pTabList, pEList);
   }
 
+#if 1  /* I do not think we need the following code any more.... */
   /* If the destination is SRT_Union, then set the number of columns in
   ** the records that will be inserted into the temporary table. The caller
   ** couldn't do this, in case the select statement is of the form 
@@ -2288,6 +2231,7 @@ int sqlite3Select(
   if( eDest==SRT_Union ){
     sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr);
   }
+#endif
 
   /* Generate code for all sub-queries in the FROM clause
   */
@@ -2416,7 +2360,7 @@ int sqlite3Select(
   */
   if( isDistinct ){
     distinct = pParse->nTab++;
-    sqlite3VdbeAddOp(v, OP_OpenTemp, distinct, 1);
+    openTempIndex(pParse, p, distinct, 0);
   }else{
     distinct = -1;
   }
@@ -2447,8 +2391,9 @@ int sqlite3Select(
       for(i=0; i<pGroupBy->nExpr; i++){
         sqlite3ExprCode(pParse, pGroupBy->a[i].pExpr);
       }
+      /* No affinity string is attached to the following OP_MakeKey 
+      ** because we do not need to do any coercion of datatypes. */
       sqlite3VdbeAddOp(v, OP_MakeKey, pGroupBy->nExpr, 0);
-      sqlite3AddKeyType(v, pGroupBy);
       lbl1 = sqlite3VdbeMakeLabel(v);
       sqlite3VdbeAddOp(v, OP_AggFocus, 0, lbl1);
       for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
index da971596463d2a06bdc57e3792fa34b7e03678f3..3c3d9aa70541cb28511fdd65afaec725c016279f 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.240 2004/05/20 11:00:52 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.241 2004/05/20 22:16:30 drh Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -260,6 +260,8 @@ typedef struct Db Db;
 typedef struct AuthContext AuthContext;
 typedef struct KeyClass KeyClass;
 typedef struct CollSeq CollSeq;
+typedef struct KeyInfo KeyInfo;
+
 
 /*
 ** Each database file to be accessed by the system is an instance
@@ -376,7 +378,7 @@ struct sqlite {
   int (*xCommitCallback)(void*);/* Invoked at every commit. */
   Hash aFunc;                   /* All functions that can be in SQL exprs */
   Hash aCollSeq;                /* All collating sequences */
-  CollSeq *pDfltColl;           /* The default collating sequence (memcmp) */
+  CollSeq *pDfltColl;           /* The default collating sequence (BINARY) */
   i64 lastRowid;                /* ROWID of most recent insert (see above) */
   i64 priorNewRowid;            /* Last randomly generated ROWID */
   int magic;                    /* Magic number for detect library misuse */
@@ -491,18 +493,10 @@ struct CollSeq {
 };
 
 /*
-** The allowed sort orders.
-**
-** The TEXT and NUM values use bits that do not overlap with DESC and ASC.
-** That way the two can be combined into a single number.
+** A sort order can be either ASC or DESC.
 */
-#define SQLITE_SO_UNK       0  /* Use the default collating type.  (SCT_NUM) */
-#define SQLITE_SO_TEXT      2  /* Sort using memcmp() */
-#define SQLITE_SO_NUM       4  /* Sort using sqlite3Compare() */
-#define SQLITE_SO_TYPEMASK  6  /* Mask to extract the collating sequence */
 #define SQLITE_SO_ASC       0  /* Sort in ascending order */
-#define SQLITE_SO_DESC      1  /* Sort in descending order */
-#define SQLITE_SO_DIRMASK   1  /* Mask to extract the sort direction */
+#define SQLITE_SO_DESC      1  /* Sort in ascending order */
 
 /*
 ** Column affinity types.
@@ -641,6 +635,21 @@ struct FKey {
 
 #define OE_Default  99  /* Do whatever the default action is */
 
+
+/*
+** An instance of the following structure is passed as the first
+** argument to sqlite3VdbeKeyCompare and is used to control the 
+** comparison of the two index keys.
+**
+** If the KeyInfo.incrKey value is true and the comparison would
+** otherwise be equal, then return a result as if the second key larger.
+*/
+struct KeyInfo {
+  u8 incrKey;         /* Increase 2nd key by epsilon before comparison */
+  int nField;         /* Number of entries in aColl[] */
+  CollSeq *aColl[1];  /* Collating sequence for each term of the key */
+};
+
 /*
 ** Each SQL index is represented in memory by an
 ** instance of the following structure.
@@ -678,6 +687,7 @@ struct Index {
   u8 iDb;          /* Index in sqlite.aDb[] of where this index is stored */
   char *zColAff;   /* String defining the affinity of each column */
   Index *pNext;    /* The next index associated with the same table */
+  KeyInfo keyInfo; /* Info on how to order keys.  MUST BE LAST */
 };
 
 /*
@@ -732,7 +742,6 @@ struct Token {
 */
 struct Expr {
   u8 op;                 /* Operation performed by this node */
-  u8 dataType;           /* Either SQLITE_SO_TEXT or SQLITE_SO_NUM */
   char affinity;         /* The affinity of the column or 0 if not a column */
   u8 iDb;                /* Database referenced by this expression */
   u8 flags;              /* Various flags.  See below */
@@ -1200,8 +1209,9 @@ void sqlite3AddNotNull(Parse*, int);
 void sqlite3AddPrimaryKey(Parse*, IdList*, int);
 void sqlite3AddColumnType(Parse*,Token*,Token*);
 void sqlite3AddDefaultValue(Parse*,Token*,int);
-int sqlite3CollateType(const char*, int);
-void sqlite3AddCollateType(Parse*, int);
+void sqlite3AddCollateType(Parse*, const char*, int);
+CollSeq *sqlite3ChangeCollatingFunction(sqlite*,const char*,int,
+                  void*, int(*)(void*,int,const void*,int,const void*));
 void sqlite3EndTable(Parse*,Token*,Select*);
 void sqlite3CreateView(Parse*,Token*,Token*,Select*,int);
 int sqlite3ViewGetColumnNames(Parse*,Table*);
@@ -1343,4 +1353,3 @@ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
 char sqlite3ExprAffinity(Expr *pExpr);
 int sqlite3atoi64(const char*, i64*);
 void sqlite3Error(sqlite *, int, const char*,...);
-
index bff18c97f76213f9d7787616f55373144df74737..3636d81d2da1a3db1b829f10ee02566666f8ad73 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.42 2004/05/20 11:00:52 danielk1977 Exp $
+** $Id: test1.c,v 1.43 2004/05/20 22:16:30 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -1407,6 +1407,49 @@ static int test_prepare16(
   return TCL_OK;
 }
 
+
+/*
+** This is a collating function named "REVERSE" which sorts text
+** in reverse order.
+*/
+static int reverseCollatingFunc(
+  void *NotUsed,
+  int nKey1, const void *pKey1,
+  int nKey2, const void *pKey2
+){
+  int rc, n;
+  n = nKey1<nKey2 ? nKey1 : nKey2;
+  rc = memcmp(pKey1, pKey2, n);
+  if( rc==0 ){
+    rc = nKey1 - nKey2;
+  }
+  return -rc;
+}
+
+/*
+** Usage: add_reverse_collating_func DB 
+**
+** This routine adds a collation named "REVERSE" to database given.
+** REVERSE is used for testing only.
+*/
+static int reverse_collfunc(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  sqlite3 *db;
+
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "DB");
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+  sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc);
+  return TCL_OK;
+}
+
+
 /*
 ** Register commands with the TCL interpreter.
 */
@@ -1419,31 +1462,31 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      char *zName;
      Tcl_CmdProc *xProc;
   } aCmd[] = {
-     { "sqlite3_mprintf_int",             (Tcl_CmdProc*)sqlite3_mprintf_int    },
-     { "sqlite3_mprintf_str",             (Tcl_CmdProc*)sqlite3_mprintf_str    },
-     { "sqlite3_mprintf_double",          (Tcl_CmdProc*)sqlite3_mprintf_double },
-     { "sqlite3_mprintf_scaled",          (Tcl_CmdProc*)sqlite3_mprintf_scaled },
-     { "sqlite3_mprintf_z_test",          (Tcl_CmdProc*)test_mprintf_z        },
-     { "sqlite3_open",                    (Tcl_CmdProc*)sqlite_test_open      },
-     { "sqlite3_last_insert_rowid",       (Tcl_CmdProc*)test_last_rowid       },
-     { "sqlite3_exec_printf",             (Tcl_CmdProc*)test_exec_printf      },
-     { "sqlite3_get_table_printf",        (Tcl_CmdProc*)test_get_table_printf },
-     { "sqlite3_close",                   (Tcl_CmdProc*)sqlite_test_close     },
-     { "sqlite3_create_function",         (Tcl_CmdProc*)test_create_function  },
-     { "sqlite3_create_aggregate",        (Tcl_CmdProc*)test_create_aggregate },
-     { "sqlite_register_test_function",  (Tcl_CmdProc*)test_register_func    },
-     { "sqlite_abort",                   (Tcl_CmdProc*)sqlite_abort          },
-     { "sqlite_datatypes",               (Tcl_CmdProc*)sqlite_datatypes      },
+     { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
+     { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
+     { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
+     { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
+     { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
+     { "sqlite3_open",                  (Tcl_CmdProc*)sqlite_test_open      },
+     { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
+     { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
+     { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
+     { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
+     { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
+     { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
+     { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
+     { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
+     { "sqlite_datatypes",              (Tcl_CmdProc*)sqlite_datatypes      },
 #ifdef MEMORY_DEBUG
-     { "sqlite_malloc_fail",             (Tcl_CmdProc*)sqlite_malloc_fail    },
-     { "sqlite_malloc_stat",             (Tcl_CmdProc*)sqlite_malloc_stat    },
+     { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
+     { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
 #endif
-     { "sqlite_compile",                 (Tcl_CmdProc*)test_compile          },
-     { "sqlite_step",                    (Tcl_CmdProc*)test_step             },
-     { "sqlite_finalize",                (Tcl_CmdProc*)test_finalize         },
-     { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
-     { "sqlite_reset",                   (Tcl_CmdProc*)test_reset            },
-     { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
+     { "sqlite_compile",                (Tcl_CmdProc*)test_compile          },
+     { "sqlite_step",                   (Tcl_CmdProc*)test_step             },
+     { "sqlite_finalize",               (Tcl_CmdProc*)test_finalize         },
+     { "sqlite_bind",                   (Tcl_CmdProc*)test_bind             },
+     { "sqlite_reset",                  (Tcl_CmdProc*)test_reset            },
+     { "breakpoint",                    (Tcl_CmdProc*)test_breakpoint       },
   };
   static struct {
      char *zName;
@@ -1461,6 +1504,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      { "sqlite3_errmsg16",              (Tcl_ObjCmdProc*)test_errmsg16      },
      { "sqlite3_prepare",               (Tcl_ObjCmdProc*)test_prepare       },
      { "sqlite3_prepare16",             (Tcl_ObjCmdProc*)test_prepare16     },
+     { "add_reverse_collating_func",    (Tcl_ObjCmdProc*)reverse_collfunc   },
   };
   int i;
 
@@ -1482,5 +1526,3 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
   return TCL_OK;
 }
-
-
index e35ee4c87d918ebc0c19e8545a17e9246d568b40..449f396cb06a9b1382020ed51b4746718766ead8 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.77 2004/05/19 14:56:57 drh Exp $
+** $Id: update.c,v 1.78 2004/05/20 22:16:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -331,7 +331,8 @@ void sqlite3Update(
     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
       if( openAll || aIdxUsed[i] ){
         sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
-        sqlite3VdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum);
+        sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
+                       (char*)&pIdx->keyInfo, P3_KEYINFO);
         assert( pParse->nTab>iCur+i+1 );
       }
     }
index ee12fc4cceddfb1bfb2cc0673112cfd1fbd053a1..daa1528f84e24cc6b280d942f43495cc31efc17c 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.308 2004/05/20 13:54:54 drh Exp $
+** $Id: vdbe.c,v 1.309 2004/05/20 22:16:30 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -2187,7 +2187,7 @@ case OP_MakeRecord: {
 **  't'            TEXT
 **  'o'            NONE
 **
-** If P3 is NULL then all index fields have the affinity NUMERIC.
+** If P3 is NULL then datatype coercion occurs.
 */
 case OP_MakeKey:
 case OP_MakeIdxKey: {
@@ -2202,8 +2202,8 @@ case OP_MakeIdxKey: {
   int offset = 0;
   char *zAffinity = pOp->p3;
  
-  assert( zAffinity );
   nField = pOp->p1;
+  assert( zAffinity==0 || strlen(zAffinity)>=nField );
   pData0 = &pTos[1-nField];
   assert( pData0>=p->aStack );
 
@@ -2223,7 +2223,9 @@ case OP_MakeIdxKey: {
   */
   for(pRec=pData0; pRec<=pTos; pRec++){
     u64 serial_type;
-    applyAffinity(pRec, zAffinity[pRec-pData0]);
+    if( zAffinity ){
+      applyAffinity(pRec, zAffinity[pRec-pData0]);
+    }
     if( pRec->flags&MEM_Null ){
       containsNull = 1;
     }
@@ -2513,10 +2515,9 @@ case OP_VerifyCookie: {
 ** to get a read lock but fails, the script terminates with an
 ** SQLITE_BUSY error code.
 **
-** The P3 value is the name of the table or index being opened.
-** The P3 value is not actually used by this opcode and may be
-** omitted.  But the code generator usually inserts the index or
-** table name into P3 to make the code easier to read.
+** The P3 value is a pointer to a KeyInfo structure that defines the
+** content and collating sequence of indices.  P3 is NULL for cursors
+** that are not pointing to indices.
 **
 ** See also OpenWrite.
 */
@@ -2525,10 +2526,9 @@ case OP_VerifyCookie: {
 ** Open a read/write cursor named P1 on the table or index whose root
 ** page is P2.  If P2==0 then take the root page number from the stack.
 **
-** The P3 value is the name of the table or index being opened.
-** The P3 value is not actually used by this opcode and may be
-** omitted.  But the code generator usually inserts the index or
-** table name into P3 to make the code easier to read.
+** The P3 value is a pointer to a KeyInfo structure that defines the
+** content and collating sequence of indices.  P3 is NULL for cursors
+** that are not pointing to indices.
 **
 ** This instruction works just like OpenRead except that it opens the cursor
 ** in read/write mode.  For a given table, there can be one or more read-only
@@ -2576,8 +2576,15 @@ case OP_OpenWrite: {
     ** sqlite3VdbeKeyCompare(). If the table being opened is of type
     ** INTKEY, the btree layer won't call the comparison function anyway.
     */
-    rc = sqlite3BtreeCursor(pX, p2, wrFlag, sqlite3VdbeKeyCompare, pCur,
-        &pCur->pCursor);
+    rc = sqlite3BtreeCursor(pX, p2, wrFlag,
+             sqlite3VdbeKeyCompare, pOp->p3,
+             &pCur->pCursor);
+    pCur->pKeyInfo = (KeyInfo*)pOp->p3;
+    if( pCur->pKeyInfo ){
+      pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
+    }else{
+      pCur->pIncrKey = &pCur->bogusIncrKey;
+    }
     switch( rc ){
       case SQLITE_BUSY: {
         if( db->xBusyCallback==0 ){
@@ -2611,16 +2618,16 @@ case OP_OpenWrite: {
   break;
 }
 
-/* Opcode: OpenTemp P1 P2 *
+/* Opcode: OpenTemp P1 * P3
 **
 ** Open a new cursor to a transient table.
 ** The transient cursor is always opened read/write even if 
 ** the main database is read-only.  The transient table is deleted
 ** automatically when the cursor is closed.
 **
-** The cursor points to a BTree table if P2==0 and to a BTree index
-** if P2==1.  A BTree table must have an integer key and can have arbitrary
-** data.  A BTree index has no data but can have an arbitrary key.
+** The cursor points to a BTree table if P3==0 and to a BTree index
+** if P3 is not 0.  If P3 is not NULL, it points to a KeyInfo structure
+** that defines the format of keys in the index.
 **
 ** This opcode is used for tables that exist for the duration of a single
 ** SQL statement only.  Tables created using CREATE TEMPORARY TABLE
@@ -2649,17 +2656,21 @@ case OP_OpenTemp: {
     ** opening it. If a transient table is required, just use the
     ** automatically created table with root-page 1 (an INTKEY table).
     */
-    if( pOp->p2 ){
+    if( pOp->p3 ){
       int pgno;
+      assert( pOp->p3type==P3_KEYINFO );
       rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA); 
       if( rc==SQLITE_OK ){
         assert( pgno==MASTER_ROOT+1 );
         rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeKeyCompare,
-            pCx, &pCx->pCursor);
+            pOp->p3, &pCx->pCursor);
+        pCx->pKeyInfo = (KeyInfo*)pOp->p3;
+        pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
       }
     }else{
       rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, 0, &pCx->pCursor);
       pCx->intKey = 1;
+      pCx->pIncrKey = &pCx->bogusIncrKey;
     }
   }
   break;
@@ -2685,6 +2696,7 @@ case OP_OpenPseudo: {
   memset(pCx, 0, sizeof(*pCx));
   pCx->nullRow = 1;
   pCx->pseudoTable = 1;
+  pCx->pIncrKey = &pCx->bogusIncrKey;
   break;
 }
 
@@ -2755,7 +2767,7 @@ case OP_MoveGt: {
     int res, oc;
     oc = pOp->opcode;
     pC->nullRow = 0;
-    pC->incrKey = oc==OP_MoveGt || oc==OP_MoveLe;
+    *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe;
     if( pC->intKey ){
       i64 iKey;
       assert( !pOp->p3 );
@@ -2772,17 +2784,13 @@ case OP_MoveGt: {
       pC->lastRecno = pTos->i;
       pC->recnoIsValid = res==0;
     }else{
-      if( pOp->p3 ){
-        pC->incrKey = 1;
-      }
       Stringify(pTos);
       sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
-      pC->incrKey = 0;
       pC->recnoIsValid = 0;
     }
     pC->deferredMoveto = 0;
     pC->cacheValid = 0;
-    pC->incrKey = 0;
+    *pC->pIncrKey = 0;
     sqlite3_search_count++;
     if( oc==OP_MoveGe || oc==OP_MoveGt ){
       if( res<0 ){
@@ -3282,7 +3290,7 @@ case OP_KeyAsData: {
   assert( i>=0 && i<p->nCursor );
   pC = p->apCsr[i];
   pC->keyAsData = pOp->p2;
-  sqlite3BtreeSetCompare(pC->pCursor, sqlite3VdbeRowCompare, pC);
+  sqlite3BtreeSetCompare(pC->pCursor, sqlite3VdbeRowCompare, pC->pKeyInfo);
   break;
 }
 
@@ -3811,10 +3819,10 @@ case OP_IdxGE: {
  
     Stringify(pTos);
     assert( pC->deferredMoveto==0 );
-    pC->incrKey = pOp->p3!=0;
+    *pC->pIncrKey = pOp->p3!=0;
     assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT );
     rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, &res);
-    pC->incrKey = 0;
+    *pC->pIncrKey = 0;
     if( rc!=SQLITE_OK ){
       break;
     }
index b997ce98fb730eb184558452e40506ed84665689..c368ccda46070babce194f525273935ef9954637 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.78 2004/05/20 13:54:54 drh Exp $
+** $Id: vdbe.h,v 1.79 2004/05/20 22:16:30 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -39,6 +39,9 @@ struct VdbeOp {
   int p2;             /* Second parameter (often the jump destination) */
   char *p3;           /* Third parameter */
   int p3type;         /* P3_STATIC, P3_DYNAMIC or P3_POINTER */
+#ifndef NDEBUG
+  char *zComment;     /* Comments explaining what this opcode does */
+#endif
 #ifdef VDBE_PROFILE
   int cnt;            /* Number of times this instruction was executed */
   long long cycles;   /* Total time spend executing this instruction */
@@ -66,6 +69,7 @@ typedef struct VdbeOpList VdbeOpList;
 #define P3_STATIC   (-2)  /* Pointer to a static string */
 #define P3_POINTER  (-3)  /* P3 is a pointer to some structure or object */
 #define P3_COLLSEQ  (-4)  /* P3 is a pointer to a CollSeq structure */
+#define P3_KEYINFO  (-5)  /* P3 is a pointer to a KeyInfo structure */
 
 /*
 ** The following macro converts a relative address in the p2 field
@@ -81,22 +85,6 @@ typedef struct VdbeOpList VdbeOpList;
 */
 #include "opcodes.h"
 
-/*
-** An instance of the following structure is passed as the first
-** argument to sqlite3VdbeKeyCompare and is used to control the 
-** comparison of the two keys.
-**
-** If the KeyInfo.incrKey value is true and the comparison would
-** otherwise be equal, then return a result as if the second key larger.
-*/
-typedef struct KeyInfo KeyInfo;
-struct KeyInfo {
-  u8 incrKey;           /* Increase value of 2nd key by epsilon */
-  u8 reverseOrder;      /* If true, reverse the comparison order */
-  int nField;           /* Number of entries in aColl[] */
-  struct CollSeq *aColl[1];  /* Collating sequence for each term of the key */
-};
-
 /*
 ** Prototypes for the VDBE interface.  See comments on the implementation
 ** for a description of what each of these routines does.
@@ -126,4 +114,11 @@ void sqlite3VdbeCompressSpace(Vdbe*,int);
 int sqlite3VdbeReset(Vdbe*,char **);
 int sqliteVdbeSetVariables(Vdbe*,int,const char**);
 
+#ifndef NDEBUG
+  void sqlite3VdbeComment(Vdbe*, const char*, ...);
+# define VdbeComment(X)  sqlite3VdbeComment X
+#else
+# define VdbeComment(X)
+#endif
+
 #endif
index 3751126aac50b15a7d5eaa8344cd451bb4aea062..38de81981617c4a1484a8ec9aee75513369981d7 100644 (file)
@@ -72,12 +72,14 @@ struct Cursor {
   Bool deferredMoveto;  /* A call to sqlite3BtreeMoveto() is needed */
   Bool intKey;          /* True if the table requires integer keys */
   Bool zeroData;        /* True if table contains keys only - no data */
-  Bool incrKey;         /* Searches on the table simulate OP_IncrKey */
+  u8 bogusIncrKey;      /* Something for pIncrKey to point to if pKeyInfo==0 */
   i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */
   Btree *pBt;           /* Separate file holding temporary table */
   int nData;            /* Number of bytes in pData */
   char *pData;          /* Data for a NEW or OLD pseudo-table */
   i64 iKey;             /* Key for the NEW or OLD pseudo-table row */
+  u8 *pIncrKey;         /* Pointer to pKeyInfo->incrKey */
+  KeyInfo *pKeyInfo;    /* Info about index keys needed by index cursors */
 
   /* Cached information about the header for the data record that the
   ** cursor is currently pointing to */
index 45c104bb3cd6bdfc1773637f41907173b99d00e5..d92c067cc4fefcdb98f566f2f2b9a55d30133ff0 100644 (file)
@@ -100,6 +100,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
   pOp->p3 = 0;
   pOp->p3type = P3_NOTUSED;
 #ifndef NDEBUG
+  pOp->zComment = 0;
   if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
 #endif
   return i;
@@ -226,6 +227,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
       pOut->p3 = pIn->p3;
       pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
 #ifndef NDEBUG
+      pOut->zComment = 0;
       if( sqlite3_vdbe_addop_trace ){
         sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
       }
@@ -274,7 +276,10 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
 **
 ** If n==P3_STATIC  it means that zP3 is a pointer to a constant static
 ** string and we can just copy the pointer.  n==P3_POINTER means zP3 is
-** a pointer to some object other than a string.
+** a pointer to some object other than a string.  n==P3_COLLSEQ and
+** n==P3_KEYINFO mean that zP3 is a pointer to a CollSeq or KeyInfo
+** structure.  A copy is made of KeyInfo structures into memory obtained
+** from sqliteMalloc.
 **
 ** If addr<0 then change P3 on the most recently inserted instruction.
 */
@@ -294,6 +299,19 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
   if( zP3==0 ){
     pOp->p3 = 0;
     pOp->p3type = P3_NOTUSED;
+  }else if( n==P3_KEYINFO ){
+    KeyInfo *pKeyInfo;
+    int nField, nByte;
+    nField = ((KeyInfo*)zP3)->nField;
+    nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]);
+    pKeyInfo = sqliteMalloc( nByte );
+    pOp->p3 = (char*)pKeyInfo;
+    if( pKeyInfo ){
+      memcpy(pKeyInfo, zP3, nByte);
+      pOp->p3type = P3_KEYINFO;
+    }else{
+      pOp->p3type = P3_NOTUSED;
+    }
   }else if( n<0 ){
     pOp->p3 = (char*)zP3;
     pOp->p3type = n;
@@ -322,11 +340,11 @@ void sqlite3VdbeDequoteP3(Vdbe *p, int addr){
   }
   pOp = &p->aOp[addr];
   if( pOp->p3==0 || pOp->p3[0]==0 ) return;
-  if( pOp->p3type==P3_POINTER ) return;
-  if( pOp->p3type!=P3_DYNAMIC ){
+  if( pOp->p3type==P3_STATIC ){
     pOp->p3 = sqliteStrDup(pOp->p3);
     pOp->p3type = P3_DYNAMIC;
   }
+  assert( pOp->p3type==P3_DYNAMIC );
   sqlite3Dequote(pOp->p3);
 }
 
@@ -342,13 +360,11 @@ void sqlite3VdbeCompressSpace(Vdbe *p, int addr){
   assert( p->magic==VDBE_MAGIC_INIT );
   if( p->aOp==0 || addr<0 || addr>=p->nOp ) return;
   pOp = &p->aOp[addr];
-  if( pOp->p3type==P3_POINTER ){
-    return;
-  }
-  if( pOp->p3type!=P3_DYNAMIC ){
+  if( pOp->p3type==P3_STATIC ){
     pOp->p3 = sqliteStrDup(pOp->p3);
     pOp->p3type = P3_DYNAMIC;
   }
+  assert( pOp->p3type==P3_DYNAMIC );
   z = (unsigned char*)pOp->p3;
   if( z==0 ) return;
   i = j = 0;
@@ -365,6 +381,23 @@ void sqlite3VdbeCompressSpace(Vdbe *p, int addr){
   z[j] = 0;
 }
 
+#ifndef NDEBUG
+/*
+** Add comment text to the most recently inserted opcode
+*/
+void sqlite3VdbeAddComment(Vdbe *p, const char *zFormat, ...){
+  va_list ap;
+  VdbeOp *pOp;
+  char *zText;
+  va_start(ap, zFormat);
+  zText = sqlite3_vmprintf(zFormat, ap);
+  va_end(ap);
+  pOp = &p->aOp[p->nOp-1];
+  sqliteFree(pOp->zComment);
+  pOp->zComment = zText;
+}
+#endif
+
 /*
 ** Search the current program starting at instruction addr for the given
 ** opcode and P2 value.  Return the address plus 1 if found and 0 if not
@@ -504,22 +537,85 @@ int sqlite3_aggregate_count(sqlite_func *p){
   return p->cnt;
 }
 
+/*
+** Compute a string that describes the P3 parameter for an opcode.
+** Use zTemp for any required temporary buffer space.
+*/
+static char *displayP3(Op *pOp, char *zTemp, int nTemp){
+  char *zP3;
+  assert( nTemp>=20 );
+  switch( pOp->p3type ){
+    case P3_POINTER: {
+      sprintf(zTemp, "ptr(%#x)", (int)pOp->p3);
+      zP3 = zTemp;
+      break;
+    }
+    case P3_KEYINFO: {
+      int i, j;
+      KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
+      sprintf(zTemp, "keyinfo(%d", pKeyInfo->nField);
+      i = strlen(zTemp);
+      for(j=0; j<pKeyInfo->nField; j++){
+        CollSeq *pColl = pKeyInfo->aColl[j];
+        if( pColl ){
+          int n = strlen(pColl->zName);
+          if( i+n>nTemp-6 ){
+            strcpy(&zTemp[i],",...");
+            break;
+          }
+          zTemp[i++] = ',';
+          if( pColl->reverseOrder ){
+            zTemp[i++] = '-';
+          }
+          strcpy(&zTemp[i], pColl->zName);
+          i += n;
+        }else if( i+4<nTemp-6 ){
+          strcpy(&zTemp[i],",nil");
+          i += 4;
+        }
+      }
+      zTemp[i++] = ')';
+      zTemp[i] = 0;
+      assert( i<nTemp );
+      zP3 = zTemp;
+      break;
+    }
+    case P3_COLLSEQ: {
+      CollSeq *pColl = (CollSeq*)pOp->p3;
+      sprintf(zTemp, "collseq(%s%.20s)", 
+         pColl->reverseOrder ? "-" : "", pColl->zName);
+      zP3 = zTemp;
+      break;
+    }
+    default: {
+      zP3 = pOp->p3;
+      if( zP3==0 ){
+        zP3 = "";
+      }
+    }
+  }
+  return zP3;
+}
+
+
 #if !defined(NDEBUG) || defined(VDBE_PROFILE)
 /*
 ** Print a single opcode.  This routine is used for debugging only.
 */
 void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
   char *zP3;
-  char zPtr[40];
-  if( pOp->p3type==P3_POINTER ){
-    sprintf(zPtr, "ptr(%#x)", (int)pOp->p3);
-    zP3 = zPtr;
-  }else{
-    zP3 = pOp->p3;
-  }
+  char zPtr[50];
+  static const char *zFormat1 = "%4d %-13s %4d %4d %s\n";
+  static const char *zFormat2 = "%4d %-13s %4d %4d %-20s -- %s\n";
   if( pOut==0 ) pOut = stdout;
-  fprintf(pOut,"%4d %-12s %4d %4d %s\n",
-      pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : "");
+  zP3 = displayP3(pOp, zPtr, sizeof(zPtr));
+#ifdef NDEBUG
+  fprintf(pOut, zFormat1,
+      pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3);
+#else
+  fprintf(pOut, pOp->zComment ? zFormat2 : zFormat1,
+      pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3,pOp->zComment);
+#endif
   fflush(pOut);
 }
 #endif
@@ -562,16 +658,13 @@ int sqlite3VdbeList(
     rc = SQLITE_ERROR;
     sqlite3SetString(&p->zErrMsg, sqlite3_error_string(p->rc), (char*)0);
   }else{
+    Op *pOp = &p->aOp[i];
     sprintf(p->zArgv[0],"%d",i);
-    sprintf(p->zArgv[2],"%d", p->aOp[i].p1);
-    sprintf(p->zArgv[3],"%d", p->aOp[i].p2);
-    if( p->aOp[i].p3type==P3_POINTER ){
-      sprintf(p->aStack[4].zShort, "ptr(%#x)", (int)p->aOp[i].p3);
-      p->zArgv[4] = p->aStack[4].zShort;
-    }else{
-      p->zArgv[4] = p->aOp[i].p3;
-    }
-    p->zArgv[1] = sqlite3OpcodeNames[p->aOp[i].opcode];
+    sprintf(p->zArgv[2],"%d", pOp->p1);
+    sprintf(p->zArgv[3],"%d", pOp->p2);
+    p->zArgv[4] =
+          displayP3(pOp, p->aStack[4].zShort, sizeof(p->aStack[4].zShort));
+    p->zArgv[1] = sqlite3OpcodeNames[pOp->opcode];
     p->pc = i+1;
     p->azResColumn = p->zArgv;
     p->nResColumn = 5;
@@ -1165,9 +1258,13 @@ void sqlite3VdbeDelete(Vdbe *p){
     p->nOp = 0;
   }
   for(i=0; i<p->nOp; i++){
-    if( p->aOp[i].p3type==P3_DYNAMIC ){
-      sqliteFree(p->aOp[i].p3);
+    Op *pOp = &p->aOp[i];
+    if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){
+      sqliteFree(pOp->p3);
     }
+#ifndef NDEBUG
+    sqliteFree(pOp->zComment);
+#endif
   }
   for(i=0; i<p->nVar; i++){
     if( p->apVar[i].flags&MEM_Dyn ){
@@ -1196,7 +1293,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
     }else{
       sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,sizeof(i64),&res);
     }
-    p->incrKey = 0;
+    *p->pIncrKey = 0;
     p->lastRecno = keyToInt(p->movetoTarget);
     p->recnoIsValid = res==0;
     if( res<0 ){
@@ -1421,8 +1518,8 @@ int sqlite3VdbeSerialGet(const unsigned char *buf, u64 serial_type, Mem *pMem){
 ** Compare the values contained by the two memory cells, returning
 ** negative, zero or positive if pMem1 is less than, equal to, or greater
 ** than pMem2. Sorting order is NULL's first, followed by numbers (integers
-** and reals) sorted numerically, followed by text ordered by memcmp() and
-** finally blob's ordered by memcmp().
+** and reals) sorted numerically, followed by text ordered by the collating
+** sequence pColl and finally blob's ordered by memcmp().
 **
 ** Two NULL values are considered equal by this function.
 */
@@ -1531,12 +1628,14 @@ int sqlite3VdbeKeyCompare(
   int nKey1, const void *pKey1, 
   int nKey2, const void *pKey2
 ){
-  Cursor *pC = (Cursor *)userData;
+  KeyInfo *pKeyInfo = (KeyInfo*)userData;
   int offset1 = 0;
   int offset2 = 0;
+  int i = 0;
   const unsigned char *aKey1 = (const unsigned char *)pKey1;
   const unsigned char *aKey2 = (const unsigned char *)pKey2;
   
+  assert( pKeyInfo!=0 );
   while( offset1<nKey1 && offset2<nKey2 ){
     Mem mem1;
     Mem mem2;
@@ -1555,12 +1654,13 @@ int sqlite3VdbeKeyCompare(
     */
     if( !serial_type1 || !serial_type2 ){
       assert( !serial_type1 && !serial_type2 );
-      assert( !pC || !pC->incrKey );
       sqlite3GetVarint(&aKey1[offset1], &serial_type1);
       sqlite3GetVarint(&aKey2[offset2], &serial_type2);
       return ( (i64)serial_type1 - (i64)serial_type2 );
     }
 
+    assert( i<pKeyInfo->nField );
+
     /* Assert that there is enough space left in each key for the blob of
     ** data to go with the serial type just read. This assert may fail if
     ** the file is corrupted.  Then read the value from each key into mem1
@@ -1569,7 +1669,7 @@ int sqlite3VdbeKeyCompare(
     offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1);
     offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2);
 
-    rc = sqlite3MemCompare(&mem1, &mem2, 0);
+    rc = sqlite3MemCompare(&mem1, &mem2, pKeyInfo->aColl[i]);
     if( mem1.flags&MEM_Dyn ){
       sqliteFree(mem1.z);
     }
@@ -1579,13 +1679,14 @@ int sqlite3VdbeKeyCompare(
     if( rc!=0 ){
       return rc;
     }
+    i++;
   }
 
   /* One of the keys ran out of fields, but all the fields up to that point
   ** were equal. If the incrKey flag is true, then the second key is
   ** treated as larger.
   */
-  if( pC && pC->incrKey ){
+  if( pKeyInfo->incrKey ){
     assert( offset2==nKey2 );
     return -1;
   }
@@ -1615,7 +1716,7 @@ int sqlite3VdbeRowCompare(
   int nKey1, const void *pKey1, 
   int nKey2, const void *pKey2
 ){
-  Cursor *pC = (Cursor *)userData;
+  KeyInfo *pKeyInfo = (KeyInfo*)userData;
   int offset1 = 0;
   int offset2 = 0;
   int toffset1 = 0;
@@ -1624,16 +1725,16 @@ int sqlite3VdbeRowCompare(
   const unsigned char *aKey1 = (const unsigned char *)pKey1;
   const unsigned char *aKey2 = (const unsigned char *)pKey2;
 
-  assert( pC );
-  assert( pC->nField>0 );
+  assert( pKeyInfo );
+  assert( pKeyInfo->nField>0 );
 
-  for( i=0; i<pC->nField; i++ ){
+  for( i=0; i<pKeyInfo->nField; i++ ){
     u64 dummy;
     offset1 += sqlite3GetVarint(&aKey1[offset1], &dummy);
     offset2 += sqlite3GetVarint(&aKey1[offset1], &dummy);
   }
 
-  for( i=0; i<pC->nField; i++ ){
+  for( i=0; i<pKeyInfo->nField; i++ ){
     Mem mem1;
     Mem mem2;
     u64 serial_type1;
@@ -1654,7 +1755,7 @@ int sqlite3VdbeRowCompare(
     offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1);
     offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2);
 
-    rc = sqlite3MemCompare(&mem1, &mem2, 0);
+    rc = sqlite3MemCompare(&mem1, &mem2, pKeyInfo->aColl[i]);
     if( mem1.flags&MEM_Dyn ){
       sqliteFree(mem1.z);
     }
@@ -1712,10 +1813,12 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
 }
 
 /*
-** Compare the key of index entry that cursor pC is point to against
+** Compare the key of the index entry that cursor pC is point to against
 ** the key string in pKey (of length nKey).  Write into *pRes a number
 ** that is negative, zero, or positive if pC is less than, equal to,
 ** or greater than pKey.  Return SQLITE_OK on success.
+**
+** pKey might contain fewer terms than the cursor.
 */
 int sqlite3VdbeIdxKeyCompare(
   Cursor *pC,                 /* The cursor to compare against */
@@ -1752,7 +1855,7 @@ int sqlite3VdbeIdxKeyCompare(
   len = nCellKey-2;
   while( pCellKey[len] && --len );
 
-  *res = sqlite3VdbeKeyCompare(pC, len, pCellKey, nKey, pKey);
+  *res = sqlite3VdbeKeyCompare(pC->pKeyInfo, len, pCellKey, nKey, pKey);
   
   if( freeCellKey ){
     sqliteFree(pCellKey);
index af4fa53a90c719df03fae6452f843fac863e6f78..29143aff6d45978cbd5d8a05f2b532dc93b2a0ef 100644 (file)
@@ -12,7 +12,7 @@
 ** This module contains C code that generates VDBE code used to process
 ** the WHERE clause of SQL statements.
 **
-** $Id: where.c,v 1.99 2004/05/19 20:41:04 drh Exp $
+** $Id: where.c,v 1.100 2004/05/20 22:16:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -222,15 +222,15 @@ static Index *findSortingIndex(
 
   assert( pOrderBy!=0 );
   assert( pOrderBy->nExpr>0 );
-  sortOrder = pOrderBy->a[0].sortOrder & SQLITE_SO_DIRMASK;
+  sortOrder = pOrderBy->a[0].sortOrder;
   for(i=0; i<pOrderBy->nExpr; i++){
     Expr *p;
-    if( (pOrderBy->a[i].sortOrder & SQLITE_SO_DIRMASK)!=sortOrder ){
+    if( pOrderBy->a[i].sortOrder!=sortOrder ){
       /* Indices can only be used if all ORDER BY terms are either
       ** DESC or ASC.  Indices cannot be used on a mixture. */
       return 0;
     }
-    if( (pOrderBy->a[i].sortOrder & SQLITE_SO_TYPEMASK)!=SQLITE_SO_UNK ){
+    if( pOrderBy->a[i].zName!=0 ){
       /* Do not sort by index if there is a COLLATE clause */
       return 0;
     }
@@ -678,13 +678,13 @@ WhereInfo *sqlite3WhereBegin(
     pTab = pTabList->a[i].pTab;
     if( pTab->isTransient || pTab->pSelect ) continue;
     sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
-    sqlite3VdbeOp3(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum,
-                     pTab->zName, P3_STATIC);
+    sqlite3VdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum);
     sqlite3VdbeAddOp(v, OP_SetNumColumns, pTabList->a[i].iCursor, pTab->nCol);
     sqlite3CodeVerifySchema(pParse, pTab->iDb);
     if( (pIx = pWInfo->a[i].pIdx)!=0 ){
       sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);
-      sqlite3VdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum,pIx->zName,0);
+      sqlite3VdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum,
+                     (char*)&pIx->keyInfo, P3_KEYINFO);
     }
   }
 
index 2591c9147775f2d89d4aa8646fed5465ef4ce69f..2d311577b612d7755b4eed0e4d267a582e51a717 100644 (file)
@@ -13,7 +13,7 @@
 # the B+tree tables.  B+trees store all data on the leaves rather
 # that storing data with keys on interior nodes.
 #
-# $Id: btree6.test,v 1.3 2004/05/13 11:34:17 danielk1977 Exp $
+# $Id: btree6.test,v 1.4 2004/05/20 22:16:31 drh Exp $
 
 
 set testdir [file dirname $argv0]
@@ -102,7 +102,7 @@ expr srand(1)
 # Do the tests.
 #
 set cnt 0
-for {set i 1} {$i<=100} {incr i} {
+for {set i 1} {$i<=40} {incr i} {
   do_test btree6-1.$i.1 {
     random_inserts $cur 200
     incr cnt 200
index 33014ccb66f577cc27a97db2ed3ff779e9b4b48d..cc09d9593bedcabc778ae1b4bda0642f1b80a5d6 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements some common TCL routines used for regression
 # testing the SQLite library
 #
-# $Id: tester.tcl,v 1.32 2004/05/12 11:24:03 danielk1977 Exp $
+# $Id: tester.tcl,v 1.33 2004/05/20 22:16:31 drh Exp $
 
 # Make sure tclsqlite was compiled correctly.  Abort now with an
 # error message if not.
@@ -74,11 +74,12 @@ set nTest 0
 set nProb 0
 set skip_test 0
 set failList {}
+set maxErr 1000
 
 # Invoke the do_test procedure to run a single test 
 #
 proc do_test {name cmd expected} {
-  global argv nErr nTest skip_test
+  global argv nErr nTest skip_test maxErr
   if {$skip_test} {
     set skip_test 0
     return
@@ -102,12 +103,12 @@ proc do_test {name cmd expected} {
     puts "\nError: $result"
     incr nErr
     lappend ::failList $name
-    if {$nErr>100} {puts "*** Giving up..."; finalize_testing}
+    if {$nErr>$maxErr} {puts "*** Giving up..."; finalize_testing}
   } elseif {[string compare $result $expected]} {
     puts "\nExpected: \[$expected\]\n     Got: \[$result\]"
     incr nErr
     lappend ::failList $name
-    if {$nErr>=100} {puts "*** Giving up..."; finalize_testing}
+    if {$nErr>=$maxErr} {puts "*** Giving up..."; finalize_testing}
   } else {
     puts " Ok"
   }