]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Implement type affinity for table and index records (CVS 1375)
authordanielk1977 <danielk1977@noemail.net>
Fri, 14 May 2004 11:00:53 +0000 (11:00 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Fri, 14 May 2004 11:00:53 +0000 (11:00 +0000)
FossilOrigin-Name: dbfe6e93166d9557d66cab9dca7977baa3501e5e

20 files changed:
manifest
manifest.uuid
src/build.c
src/date.c
src/func.c
src/insert.c
src/shell.c
src/sqliteInt.h
src/update.c
src/util.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
src/where.c
test/func.test
test/index.test
test/quick.test
test/select2.test
test/select4.test
test/sort.test

index 82bd3388984af15ee2225d628a50be8feaf7d312..18e3a64474aecd8adfbee329db7ac5f7b5239654 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Changes\sto\sbtree\sand\spager\sin\spreparation\sfor\smoving\sto\srun-time\spage\nsize\sdetermination.\s(CVS\s1374)
-D 2004-05-14T01:58:12
+C Implement\stype\saffinity\sfor\stable\sand\sindex\srecords\s(CVS\s1375)
+D 2004-05-14T11:00:53
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -26,16 +26,16 @@ F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
 F src/btree.c 2b85dc8f6b169bbe6bc0dab1730757f77d72811b
 F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050
 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
-F src/build.c f25e4ac9f102efd70188bc09a459c2b461fe2135
+F src/build.c e93f443a20eab57ffb77ff6244b1e09a1f7d9390
 F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29
-F src/date.c 1564caa119511a1bb23dd0b1530ad38ed8c3349b
+F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
 F src/delete.c 30c8c4375e75e811c3668abf3f78970fe549f375
 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
 F src/expr.c a3aed7057bafb3a01e8af98a5f74a102621b7a91
-F src/func.c 4b3147e841a4db9bf41768d79aaa46e6655b239a
+F src/func.c 4053dc2141ea46e8e35df089d87bfcbab54320bc
 F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
 F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
-F src/insert.c 1e63d2774c4d893363e0c072f19d4c92a4ab982d
+F src/insert.c 5d4d1a59f66b558213984391985a418efc1c2797
 F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d
 F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
 F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
@@ -47,9 +47,9 @@ F src/pragma.c 2ab2a12b62ec5370b9221f44b4743a633a90bfa8
 F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
 F src/select.c ca99ae4db14a45a436ec51d3e6bd48d44a3efb3c
-F src/shell.c 255b8b9023cb5274f56d87df437e8ce6ef810b91
+F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21
 F src/sqlite.h.in 799c5e726296ec7bc20e6407cdf4df0e0bc00c0c
-F src/sqliteInt.h 168f441f72f5d1ab476ea85ac544712fe57f31c0
+F src/sqliteInt.h 3b593addbd54228a545ec3ea4f7689c261ae5fa1
 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
 F src/tclsqlite.c fbf0fac73624ae246551a6c671f1de0235b5faa1
 F src/test1.c 12ef76b8aaba4408422f21f269256b630d4dd627
@@ -59,15 +59,15 @@ F src/test4.c b3fab9aea7a8940a8a7386ce1c7e2157b09bd296
 F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
 F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847
 F src/trigger.c 8df308e09113410bb895e88a2db65b55490268db
-F src/update.c 6ca82fc4a0fb4d7f134e961921c906f6f3c8bc74
+F src/update.c 0441f8b64d616ef244583449e66c984e536c6c9b
 F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f
-F src/util.c 778a8cd03ad6e52778602d20a3132c7d2d1b0a0c
+F src/util.c 58407b133dfe0b21af23e0aa89c058a2b3d8cb0f
 F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
-F src/vdbe.c a6ba83386f8137cb5aff7980a519c1529052849a
+F src/vdbe.c a6e1bfe1188f16783260a1fdc391ecc2c6a1dab6
 F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8
-F src/vdbeInt.h d53f38078ca4727c5f2851bc47ad648645bfab82
-F src/vdbeaux.c 8bf71f7ba91a208c5e0a8bcf5da03889bc858041
-F src/where.c 487e55b1f64c8fbf0f46a9a90c2247fc45ae6a9a
+F src/vdbeInt.h 03f4c3642482570a697a42a9bbb12908c6535bbe
+F src/vdbeaux.c d8dc16e7bfb6201a2e2e4c020ba813e295de717f
+F src/where.c 292f3d3d056d69197573eceb5578d7ba905725df
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
 F test/attach2.test 7c388dee63a4c1997695c3d41957f32ce784ac56
@@ -89,10 +89,10 @@ F test/delete.test 92256384f1801760180ded129f7427884cf28886
 F test/expr.test 8b62f3fcac64fbd5c3d43d7a7984245743dcbe65
 F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7
 F test/format3.test 149cc166c97923fa60def047e90dd3fb32bba916
-F test/func.test 000515779001ac6899eec4b54e65c6e2501279d4
+F test/func.test e77f46af34c23081c3aacb84f25238b808bd7202
 F test/hook.test 1a67ce0cd64a6455d016962542f2822458dccc49
 F test/in.test 0de39b02ceeca90993b096822fb5a884661c5b47
-F test/index.test 9295deefbdb6dedbe01be8905f0c448fe5bd4079
+F test/index.test 231ff7a4c9d4d002c07d8383dc44184dad06e6ec
 F test/insert.test 6ec324659656f4a86e4abfcf1a1fd2795ba6b603
 F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f
 F test/interrupt.test 9142ce4448605127640eda5e283952f75f67ed91
@@ -120,16 +120,16 @@ F test/pager2.test 7ff175a28484fd324df9315dfe35f6fb159910ec
 F test/pragma.test 06c4e51998dd68115ef7a60abeeff7accf198f83
 F test/printf.test 46b3d07d59d871d0831b4a657f6dfcafe0574850
 F test/progress.test 701b6115c2613128ececdfe1398a1bd0e1a4cfb3 x
-F test/quick.test b9dc7ad37e96da28f7d0c5e9e154024307ef568b
+F test/quick.test fa37bb9bf8f6a531b33f852284fa03f89a407697
 F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
 F test/rowid.test 863e6e75878cccf03d166fe52023f20e09508683
 F test/select1.test 3bfcccd2eadcddbb07f1f5da6550aee8484ea4fb
-F test/select2.test 2115d8f7a34fcb5c0cbe8491f441830bc44d3398
+F test/select2.test bafe576b76616f101c06a780a8155d5a6c363127
 F test/select3.test 445a1a3dde4e2fd32541b311f55da5e2f8079d76
-F test/select4.test 804b48d637aeee5e952333a997cfba316b489a3a
+F test/select4.test d2443e558c5013b22eaa25533fa22ef0ff0b1095
 F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
 F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf
-F test/sort.test ba07b107c16070208e6aab3cadea66ba079d85ba
+F test/sort.test 63e1b0e982f08f0ff5b55d420db31f6f8c0d4c1c
 F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
 F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4
 F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1
@@ -191,7 +191,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 790226c94493a6d58a7e52fd3ed35ef495fab11e
-R 1732d9617f45de2d10dd8c0de779aa14
-U drh
-Z 4d4be7c36b4d139bc06baaeae3481d2d
+P f63fb6dd4e8e33d4c1983396b1a0305836ee4df7
+R 063a4d7caa30f9e2870f52d893366e1a
+U danielk1977
+Z 458386d9c0f0338b7a617dad680da64b
index cfe1845b60c8d4ca7d25a2c5da6891c3c0766a89..be01826201a0f22e59042aaefb16569332327e4e 100644 (file)
@@ -1 +1 @@
-f63fb6dd4e8e33d4c1983396b1a0305836ee4df7
\ No newline at end of file
+dbfe6e93166d9557d66cab9dca7977baa3501e5e
\ No newline at end of file
index b6724494921a726a872b1b4b6aa2f62d2dc20d1b..1881aba2496759ed13df0a01c61ca458132ba6ca 100644 (file)
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.182 2004/05/12 11:24:03 danielk1977 Exp $
+** $Id: build.c,v 1.183 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -350,6 +350,9 @@ void sqlite3DeleteTable(sqlite *db, Table *pTable){
   }
   sqliteFree(pTable->zName);
   sqliteFree(pTable->aCol);
+  if( pTable->zColAff ){
+    sqliteFree(pTable->zColAff);
+  }
   sqlite3SelectDelete(pTable->pSelect);
   sqliteFree(pTable);
 }
index 0c332abe5108e04f25edb6a9e7de5cdbb814a262..824f2732ebdcef167cd4d5e8f5937343bf9832eb 100644 (file)
@@ -16,7 +16,7 @@
 ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
 ** All other code has file scope.
 **
-** $Id: date.c,v 1.18 2004/05/10 10:34:35 danielk1977 Exp $
+** $Id: date.c,v 1.19 2004/05/14 11:00:53 danielk1977 Exp $
 **
 ** NOTES:
 **
@@ -321,7 +321,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
       return 0;
     }
     return 1;
-  }else if( sqlite3IsNumber(zDate) ){
+  }else if( sqlite3IsNumber(zDate, 0) ){
     p->rJD = sqlite3AtoF(zDate, 0);
     p->validJD = 1;
     return 0;
index 5d95ca0cd308885679eee084815fd043aa66506e..5a4a46147dd41042c6a35cf3a3adcd9899c82509 100644 (file)
@@ -16,7 +16,7 @@
 ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
 ** All other code has file scope.
 **
-** $Id: func.c,v 1.46 2004/05/13 11:34:16 danielk1977 Exp $
+** $Id: func.c,v 1.47 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include <ctype.h>
 #include <math.h>
@@ -295,7 +295,7 @@ static void quoteFunc(sqlite_func *context, int argc, const char **argv){
   if( argc<1 ) return;
   if( argv[0]==0 ){
     sqlite3_set_result_string(context, "NULL", 4);
-  }else if( sqlite3IsNumber(argv[0]) ){
+  }else if( sqlite3IsNumber(argv[0], 0) ){
     sqlite3_set_result_string(context, argv[0], -1);
   }else{
     int i,j,n;
index 06785ed33642129e603d21b9416ab3bdd68f8e49..86c2fcc2ed9d7712b08f63d3b4270d7f079f9de1 100644 (file)
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.97 2004/05/11 07:11:53 danielk1977 Exp $
+** $Id: insert.c,v 1.98 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
+/*
+** Set P3 of the most recently inserted opcode to a column affinity
+** string for table pTab. A column affinity string has one character
+** for each column in the table, according to the affinity of the column:
+**
+**  Character      Column affinity
+**  ------------------------------
+**  'n'            NUMERIC
+**  'i'            INTEGER
+**  't'            TEXT
+**  'o'            NONE
+*/
+int sqlite3AddRecordType(Vdbe *v, Table *pTab){
+  assert( pTab );
+  /* The first time a column affinity string for a particular table
+  ** is required, it is allocated and populated here. It is then 
+  ** stored as a member of the Table structure for subsequent use.
+  **
+  ** The column affinity string will eventually be deleted by
+  ** sqlite3DeleteTable() when the Table structure itself is cleaned up.
+  */
+  if( !pTab->zColAff ){
+    char *zColAff;
+    int i;
+
+    zColAff = sqliteMalloc(pTab->nCol+1);
+    if( !zColAff ){
+      return SQLITE_NOMEM;
+    }
+
+    for(i=0; i<pTab->nCol; i++){
+      if( pTab->aCol[i].sortOrder&SQLITE_SO_TEXT ){
+        zColAff[i] = 't';
+      }else{
+        zColAff[i] = 'n';
+      }
+    }
+    zColAff[pTab->nCol] = '\0';
+
+    pTab->zColAff = zColAff;
+  }
+
+  /* Set the memory management at the vdbe to P3_STATIC, as the column
+  ** affinity string is managed as part of the Table structure.
+  */
+  sqlite3VdbeChangeP3(v, -1, pTab->zColAff, P3_STATIC);
+  return SQLITE_OK;
+}
+
+
 /*
 ** This routine is call to handle SQL of the following forms:
 **
@@ -216,6 +267,7 @@ void sqlite3Insert(
       srcTab = pParse->nTab++;
       sqlite3VdbeResolveLabel(v, iInsertBlock);
       sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+      sqlite3AddRecordType(v, pTab);
       sqlite3VdbeAddOp(v, OP_NewRecno, srcTab, 0);
       sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
       sqlite3VdbeAddOp(v, OP_PutIntKey, srcTab, 0);
@@ -394,6 +446,7 @@ void sqlite3Insert(
       }
     }
     sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
+    sqlite3AddRecordType(v, pTab);
     sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
 
     /* Fire BEFORE or INSTEAD OF triggers */
@@ -883,6 +936,7 @@ void sqlite3CompleteInsertion(
     sqlite3VdbeAddOp(v, OP_IdxPut, base+i+1, 0);
   }
   sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
+  sqlite3AddRecordType(v, pTab);
   if( newIdx>=0 ){
     sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
     sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
index 648a9bbec849af34114b15ef46f296321c11f0cb..ef853dc7ff900ef0fdad79bd0095840bc486f41b 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.95 2004/05/10 10:34:52 danielk1977 Exp $
+** $Id: shell.c,v 1.96 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -80,7 +80,7 @@ static char continuePrompt[20]; /* Continuation prompt. default: "   ...> " */
 /*
 ** Determines if a string is a number of not.
 */
-extern int sqlite3IsNumber(const char*);
+extern int sqlite3IsNumber(const char*, int*);
 
 /*
 ** This routine reads a line of text from standard input, stores
@@ -392,7 +392,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
         char *zSep = i>0 ? ",": "";
         if( azArg[i]==0 ){
           fprintf(p->out,"%sNULL",zSep);
-        }else if( sqlite3IsNumber(azArg[i]) ){
+        }else if( sqlite3IsNumber(azArg[i], 0) ){
           fprintf(p->out,"%s%s",zSep, azArg[i]);
         }else{
           if( zSep[0] ) fprintf(p->out,"%s",zSep);
index 5f264faf6ccd6e46d433104bf72458426b38fa6c..e29a4c9863a50aaea09308c9d396028b3aae60f7 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.231 2004/05/12 11:24:03 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.232 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -520,6 +520,7 @@ struct Table {
   u8 keyConf;      /* What to do in case of uniqueness conflict on iPKey */
   Trigger *pTrigger; /* List of SQL triggers on this table */
   FKey *pFKey;       /* Linked list of all foreign keys in this table */
+  char *zColAff;     /* String defining the affinity of each column */
 };
 
 /*
@@ -1110,7 +1111,7 @@ extern int always_code_trigger_setup;
 int sqlite3StrICmp(const char *, const char *);
 int sqlite3StrNICmp(const char *, const char *, int);
 int sqlite3HashNoCase(const char *, int);
-int sqlite3IsNumber(const char*);
+int sqlite3IsNumber(const char*, int*);
 int sqlite3Compare(const char *, const char *);
 int sqlite3SortCompare(const char *, const char *);
 void sqlite3RealToSortable(double r, char *);
@@ -1289,5 +1290,6 @@ void sqlite3utf16to16be(void *pData, int N);
 int sqlite3PutVarint(unsigned char *, u64);
 int sqlite3GetVarint(const unsigned char *, u64 *);
 int sqlite3VarintLen(u64 v);
+int sqlite3AddRecordType(Vdbe*, Table*);
 
 
index 71d89389957be64b6e497f8e3b41c69566935463..2c3c3c300d082e53494b66aef3c78f03e44f92fe 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.72 2004/05/10 10:35:00 danielk1977 Exp $
+** $Id: update.c,v 1.73 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -287,6 +287,7 @@ void sqlite3Update(
       }
     }
     sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
+    sqlite3AddRecordType(v, pTab);
     sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
     if( !isView ){
       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
index 5524245d944d0cd84249c46f1b3adb2e3bb724b9..07bb1b99aa1f334d0b0c519cc2250f33cbbcc6ad 100644 (file)
@@ -14,7 +14,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.80 2004/05/11 06:17:22 danielk1977 Exp $
+** $Id: util.c,v 1.81 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -516,27 +516,32 @@ int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){
 
 /*
 ** Return TRUE if z is a pure numeric string.  Return FALSE if the
-** string contains any character which is not part of a number.
+** string contains any character which is not part of a number. If
+** the string is numeric and contains the '.' character, set *realnum
+** to TRUE (otherwise FALSE).
 **
 ** Am empty string is considered non-numeric.
 */
-int sqlite3IsNumber(const char *z){
+int sqlite3IsNumber(const char *z, int *realnum){
   if( *z=='-' || *z=='+' ) z++;
   if( !isdigit(*z) ){
     return 0;
   }
   z++;
+  if( realnum ) *realnum = 0;
   while( isdigit(*z) ){ z++; }
   if( *z=='.' ){
     z++;
     if( !isdigit(*z) ) return 0;
     while( isdigit(*z) ){ z++; }
+    if( realnum ) *realnum = 1;
   }
   if( *z=='e' || *z=='E' ){
     z++;
     if( *z=='+' || *z=='-' ) z++;
     if( !isdigit(*z) ) return 0;
     while( isdigit(*z) ){ z++; }
+    if( realnum ) *realnum = 1;
   }
   return *z==0;
 }
@@ -644,8 +649,8 @@ int sqlite3Compare(const char *atext, const char *btext){
   }else if( btext==0 ){
     return 1;
   }
-  isNumA = sqlite3IsNumber(atext);
-  isNumB = sqlite3IsNumber(btext);
+  isNumA = sqlite3IsNumber(atext, 0);
+  isNumB = sqlite3IsNumber(btext, 0);
   if( isNumA ){
     if( !isNumB ){
       result = -1;
@@ -736,8 +741,8 @@ int sqlite3SortCompare(const char *a, const char *b){
       res = strcmp(&a[1],&b[1]);
       if( res ) break;
     }else{
-      isNumA = sqlite3IsNumber(&a[1]);
-      isNumB = sqlite3IsNumber(&b[1]);
+      isNumA = sqlite3IsNumber(&a[1], 0);
+      isNumB = sqlite3IsNumber(&b[1], 0);
       if( isNumA ){
         double rA, rB;
         if( !isNumB ){
index d694820202611d39f5b56d192251747d0ae98ebd..7f00e341bf74fd5110a7425fe0274d9ad4826789 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.287 2004/05/13 13:38:52 danielk1977 Exp $
+** $Id: vdbe.c,v 1.288 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -285,8 +285,8 @@ static void popStack(Mem **ppTos, int N){
 ** Under Linux (RedHat 7.2) this routine is much faster than atoi()
 ** for converting strings into integers.
 */
-static int toInt(const char *zNum, int *pNum){
-  int v = 0;
+static int toInt(const char *zNum, i64 *pNum){
+  i64 v = 0;
   int neg;
   int i, c;
   if( *zNum=='-' ){
@@ -302,7 +302,8 @@ static int toInt(const char *zNum, int *pNum){
     v = v*10 + c - '0';
   }
   *pNum = neg ? -v : v;
-  return c==0 && i>0 && (i<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0));
+  return c==0 && i>0 && 
+      (i<10 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0));
 }
 
 /*
@@ -421,6 +422,68 @@ static int expandCursorArraySize(Vdbe *p, int mxCursor){
   return 0;
 }
 
+/*
+** Apply any conversion required by the supplied column affinity to
+** memory cell pRec. affinity may be one of:
+**
+** SQLITE_AFF_NUM
+** SQLITE_AFF_TEXT
+** SQLITE_AFF_NONE
+** SQLITE_AFF_INTEGER
+**
+*/
+static void applyAffinity(Mem *pRec, int affinity){
+  switch( affinity ){
+    case SQLITE_SO_NUM:
+      if( 0==(pRec->flags&(MEM_Real|MEM_Int)) ){
+        /* pRec does not have a valid integer or real representation. 
+        ** Attempt a conversion if pRec has a string representation and
+        ** it looks like a number.
+        */
+        int realnum;
+        if( pRec->flags&MEM_Str && sqlite3IsNumber(pRec->z, &realnum) ){
+          if( realnum ){
+            Realify(pRec);
+          }else{
+            Integerify(pRec);
+          }
+        }
+      }
+      break;
+    case SQLITE_SO_TEXT:
+      /* Only attempt the conversion if there is an integer or real
+      ** representation (blob and NULL do not get converted) but no string
+      ** representation.
+      */
+      if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
+        Stringify(pRec);
+      }
+      pRec->flags &= ~(MEM_Real|MEM_Int);
+
+      break;
+
+/*
+    case SQLITE_AFF_INTEGER:
+    case SQLITE_AFF_NONE:
+      break;
+*/
+    default:
+      assert(0);
+  }
+}
+
+/*
+** This function interprets the character 'affinity' according to the 
+** following table and calls the applyAffinity() function.
+*/
+static void applyAffinityByChar(Mem *pRec, char affinity){
+  switch( affinity ){
+    case 'n': return applyAffinity(pRec, SQLITE_SO_NUM);
+    case 't': return applyAffinity(pRec, SQLITE_SO_TEXT);
+    default: assert(0);
+  }
+}
+
 #ifdef VDBE_PROFILE
 /*
 ** The following routine only works on pentium-class processors.
@@ -499,6 +562,9 @@ int sqlite3VdbeExec(
   int nProgressOps = 0;      /* Opcodes executed since progress callback. */
 #endif
 
+  /* FIX ME. */
+  expandCursorArraySize(p, 100);
+
   if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
   assert( db->magic==SQLITE_MAGIC_BUSY );
   assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
@@ -1213,7 +1279,7 @@ case OP_ForceInt: {
   int v;
   assert( pTos>=p->aStack );
   if( (pTos->flags & (MEM_Int|MEM_Real))==0
-         && ((pTos->flags & MEM_Str)==0 || sqlite3IsNumber(pTos->z)==0) ){
+         && ((pTos->flags & MEM_Str)==0 || sqlite3IsNumber(pTos->z, 0)==0) ){
     Release(pTos);
     pTos--;
     pc = pOp->p2 - 1;
@@ -1256,10 +1322,10 @@ case OP_MustBeInt: {
     }
     pTos->i = i;
   }else if( pTos->flags & MEM_Str ){
-    int v;
+    i64 v;
     if( !toInt(pTos->z, &v) ){
       double r;
-      if( !sqlite3IsNumber(pTos->z) ){
+      if( !sqlite3IsNumber(pTos->z, 0) ){
         goto mismatch;
       }
       Realify(pTos);
@@ -1406,7 +1472,7 @@ case OP_Le:
 case OP_Gt:
 case OP_Ge: {
   Mem *pNos = &pTos[-1];
-  int c, v;
+  i64 c, v;
   int ft, fn;
   assert( pNos>=p->aStack );
   ft = pTos->flags;
@@ -2023,7 +2089,7 @@ case OP_Column: {
   break;
 }
 
-/* Opcode MakeRecord3 P1 * *
+/* Opcode MakeRecord P1 * P3
 **
 ** This opcode (not yet in use) is a replacement for the current
 ** OP_MakeRecord that supports the SQLite3 manifest typing feature.
@@ -2034,6 +2100,20 @@ case OP_Column: {
 ** details of the format are irrelavant as long as the OP_Column
 ** opcode can decode the record later.  Refer to source code
 ** comments for the details of the record format.
+**
+** P3 may be a string that is P1 characters long.  The nth character of the
+** string indicates the column affinity that should be used for the nth
+** field of the index key (i.e. the first character of P3 corresponds to the
+** lowest element on the stack).
+**
+**  Character      Column affinity
+**  ------------------------------
+**  'n'            NUMERIC
+**  'i'            INTEGER
+**  't'            TEXT
+**  'o'            NONE
+**
+** If P3 is NULL then all index fields have the affinity NONE.
 */
 case OP_MakeRecord: {
   /* Assuming the record contains N fields, the record format looks
@@ -2056,18 +2136,24 @@ case OP_MakeRecord: {
   int nField = pOp->p1;
   unsigned char *zNewRecord;
   unsigned char *zCsr;
+  char *zAffinity;
   Mem *pRec;
   int nBytes;    /* Space required for this record */
 
   Mem *pData0 = &pTos[1-nField];
   assert( pData0>=p->aStack );
+  zAffinity = pOp->p3;
 
   /* Loop through the elements that will make up the record to figure
   ** out how much space is required for the new record.
   */
   nBytes = sqlite3VarintLen(nField);
   for(pRec=pData0; pRec<=pTos; pRec++){
-    u64 serial_type = sqlite3VdbeSerialType(pRec);
+    u64 serial_type;
+    if( zAffinity ){
+      applyAffinityByChar(pRec, zAffinity[pRec-pData0]);
+    }
+    serial_type = sqlite3VdbeSerialType(pRec);
     nBytes += sqlite3VdbeSerialTypeLen(serial_type);
     nBytes += sqlite3VarintLen(serial_type);
   }
@@ -2213,7 +2299,7 @@ case OP_MakeKey2: {
       Stringify(pRec);
       pRec->flags &= ~(MEM_Int|MEM_Real);
       nByte += pRec->n+1;
-    }else if( (flags & (MEM_Real|MEM_Int))!=0 || sqlite3IsNumber(pRec->z) ){
+    }else if( (flags & (MEM_Real|MEM_Int))!=0 || sqlite3IsNumber(pRec->z, 0) ){
       if( (flags & (MEM_Real|MEM_Int))==MEM_Int ){
         pRec->r = pRec->i;
       }else if( (flags & (MEM_Real|MEM_Int))==0 ){
@@ -2285,15 +2371,43 @@ case OP_MakeKey2: {
   break;
 }
 
-/* Opcode: MakeIdxKey3 P1 P2 *
+/* Opcode: MakeKey P1 P2 P3
+**
+** Convert the top P1 entries of the stack into a single entry suitable
+** for use as the key in an index. If P2 is not zero, then the original 
+** entries are popped off the stack. If P2 is zero, the original entries
+** remain on the stack.
+**
+** P3 is interpreted in the same way as for MakeIdxKey.
+*/
+/* Opcode: MakeIdxKey P1 P2 P3
 **
 ** Convert the top P1 entries of the stack into a single entry suitable
 ** for use as the key in an index.  In addition, take one additional integer
 ** off of the stack, treat that integer as an eight-byte record number, and
 ** append the integer to the key as a varint.  Thus a total of P1+1 entries
 ** are popped from the stack for this instruction and a single entry is
-** pushed back.  The first P1 entries that are popped are strings and the
-** last entry (the lowest on the stack) is an integer record number.
+** pushed back.  
+**
+** If P2 is not zero and one or more of the P1 entries that go into the
+** generated key is NULL, then jump to P2 after the new key has been
+** pushed on the stack.  In other words, jump to P2 if the key is
+** guaranteed to be unique.  This jump can be used to skip a subsequent
+** uniqueness test.
+**
+** P3 may be a string that is P1 characters long.  The nth character of the
+** string indicates the column affinity that should be used for the nth
+** field of the index key (i.e. the first character of P3 corresponds to the
+** lowest element on the stack).
+**
+**  Character      Column affinity
+**  ------------------------------
+**  'n'            NUMERIC
+**  'i'            INTEGER
+**  't'            TEXT
+**  'o'            NONE
+**
+** If P3 is NULL then all index fields have the affinity NUMERIC.
 */
 case OP_MakeKey:
 case OP_MakeIdxKey: {
@@ -2306,25 +2420,46 @@ case OP_MakeIdxKey: {
   int containsNull = 0;
   char *zKey;      /* The new key */
   int offset = 0;
+  char *zAffinity = pOp->p3;
  
+  assert( zAffinity );
   nField = pOp->p1;
   pData0 = &pTos[1-nField];
   assert( pData0>=p->aStack );
 
   addRowid = ((pOp->opcode==OP_MakeIdxKey)?1:0);
 
-  /* Calculate the number of bytes required for the new index key and
-  ** store that number in nByte. Also set rowid to the record number to
-  ** append to the index key.
+  /* Loop through the P1 elements that will make up the new index
+  ** key. Call applyAffinity() to perform any conversion required
+  ** the column affinity string P3 to modify stack elements in place.
+  ** Set containsNull to 1 if a NULL value is encountered.
+  **
+  ** Once the value has been coerced, figure out how much space is required
+  ** to store the coerced values serial-type and blob, and add this
+  ** quantity to nByte.
+  **
+  ** TODO: Figure out if the in-place coercion causes a problem for
+  ** OP_MakeKey when P2 is 0 (used by DISTINCT).
   */
   for(pRec=pData0; pRec<=pTos; pRec++){
-    u64 serial_type = sqlite3VdbeSerialType(pRec);
-    if( serial_type==0 ){
+    u64 serial_type;
+    if( zAffinity ){
+      applyAffinityByChar(pRec, zAffinity[pRec-pData0]);
+    }else{
+      applyAffinity(pRec, SQLITE_SO_NUM);
+    }
+    if( pRec->flags&MEM_Null ){
       containsNull = 1;
     }
+    serial_type = sqlite3VdbeSerialType(pRec);
     nByte += sqlite3VarintLen(serial_type);
     nByte += sqlite3VdbeSerialTypeLen(serial_type);
   }
+
+  /* If we have to append a varint rowid to this record, set 'rowid'
+  ** to the value of the rowid and increase nByte by the amount of space
+  ** required to store it and the 0x00 seperator byte.
+  */
   if( addRowid ){
     pRec = &pTos[0-nField];
     assert( pRec>=p->aStack );
@@ -2366,7 +2501,10 @@ case OP_MakeIdxKey: {
   pTos->z = zKey;
   pTos->n = nByte;
 
-  if( pOp->p2 && containsNull ){
+  /* If P2 is non-zero, and if the key contains a NULL value, and if this
+  ** was an OP_MakeIdxKey instruction, not OP_MakeKey, jump to P2.
+  */
+  if( pOp->p2 && containsNull && addRowid ){
     pc = pOp->p2 - 1;
   }
   break;
@@ -2379,6 +2517,7 @@ case OP_MakeIdxKey: {
 ** byte of that key by one.  This is used so that the MoveTo opcode
 ** will move to the first entry greater than the key rather than to
 ** the key itself.
+**
 */
 case OP_IncrKey: {
   assert( pTos>=p->aStack );
@@ -2388,6 +2527,11 @@ case OP_IncrKey: {
   ** are always free to modify the string in place.
   */
   assert( pTos->flags & (MEM_Dyn|MEM_Short) );
+  /*
+  ** FIX ME: This technique is now broken due to manifest types in index
+  ** keys.
+  */
+  assert(0);
   pTos->z[pTos->n-1]++;
   break;
 }
@@ -2684,7 +2828,7 @@ 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, 0,
+    rc = sqlite3BtreeCursor(pX, p2, wrFlag, sqlite3VdbeKeyCompare, pCur,
         &pCur->pCursor);
     switch( rc ){
       case SQLITE_BUSY: {
@@ -2817,6 +2961,11 @@ case OP_Close: {
 ** If there are no records greater than the key and P2 is not zero,
 ** then an immediate jump to P2 is made.
 **
+** If P3 is not NULL, then the cursor is left pointing at the first
+** record that is greater than the key of which the key is not a prefix.
+** This is the same effect that executing OP_IncrKey on the key value
+** before OP_MoveTo used to have.
+**
 ** See also: Found, NotFound, Distinct, MoveLt
 */
 /* Opcode: MoveLt P1 P2 *
@@ -2827,6 +2976,11 @@ case OP_Close: {
 ** If there are no records less than than the key and P2
 ** is not zero then an immediate jump to P2 is made.
 **
+** If P3 is not NULL, and keys exist in the index of which the stack key
+** is a prefix, leave the cursor pointing at the largest of these.
+** This is the same effect that executing OP_IncrKey on the key value
+** before OP_MoveLt used to have.
+**
 ** See also: MoveTo
 */
 case OP_MoveLt:
@@ -2842,6 +2996,7 @@ case OP_MoveTo: {
     pC->nullRow = 0;
     if( pC->intKey ){
       i64 iKey;
+      assert( !pOp->p3 );
       Integerify(pTos);
       iKey = intToKey(pTos->i);
       if( pOp->p2==0 && pOp->opcode==OP_MoveTo ){
@@ -2855,11 +3010,16 @@ case OP_MoveTo: {
       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->incrKey = 0;
     sqlite3_search_count++;
     oc = pOp->opcode;
     if( oc==OP_MoveTo && res<0 ){
@@ -3015,7 +3175,7 @@ case OP_IsUnique: {
         break;
       }
     }
-    rc = sqlite3VdbeIdxKeyCompare(pCrsr, len, zKey, 0, &res); 
+    rc = sqlite3VdbeIdxKeyCompare(pCx, len, zKey, 0, &res); 
     if( rc!=SQLITE_OK ) goto abort_due_to_error;
     if( res>0 ){
       pc = pOp->p2 - 1;
@@ -3645,8 +3805,8 @@ case OP_IdxPut: {
       while( res!=0 ){
         int c;
         sqlite3BtreeKeySize(pCrsr, &n);
-        if( n==nKey 
-            && sqlite3VdbeIdxKeyCompare(pCrsr, len, zKey, 0, &c)==SQLITE_OK
+        if( n==nKey && 
+            sqlite3VdbeIdxKeyCompare(&p->aCsr[i], len, zKey, 0, &c)==SQLITE_OK
             && c==0
         ){
           rc = SQLITE_CONSTRAINT;
@@ -3711,19 +3871,24 @@ case OP_IdxRecno: {
   assert( i>=0 && i<p->nCursor );
   pTos++;
   if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
-    u64 sz;
-    int len;
-    char buf[9];
+    i64 rowid;
 
     assert( p->aCsr[i].deferredMoveto==0 );
     assert( p->aCsr[i].intKey==0 );
+    rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
+    if( rc!=SQLITE_OK ){
+      goto abort_due_to_error;
+    }
+    pTos->flags = MEM_Int;
+    pTos->i = rowid;
 
+#if 0
     /* Read the final 9 bytes of the key into buf[]. If the whole key is
     ** less than 9 bytes then just load the whole thing. Set len to the 
     ** number of bytes read.
     */
     sqlite3BtreeKeySize(pCrsr, &sz);
-    len = ((sz>9)?9:sz);
+    len = ((sz>10)?10:sz);
     rc = sqlite3BtreeKey(pCrsr, sz-len, len, buf);
     if( rc!=SQLITE_OK ){
       goto abort_due_to_error;
@@ -3747,6 +3912,7 @@ case OP_IdxRecno: {
       pTos->flags = MEM_Int;
       pTos->i = sz;
     }
+#endif
   }else{
     pTos->flags = MEM_Null;
   }
@@ -3788,10 +3954,15 @@ case OP_IdxGE: {
   assert( pTos>=p->aStack );
   if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int res, rc;
+    Cursor *pC = &p->aCsr[i];
  
     Stringify(pTos);
     assert( p->aCsr[i].deferredMoveto==0 );
-    rc = sqlite3VdbeIdxKeyCompare(pCrsr, pTos->n, pTos->z, 0, &res);
+    if( pOp->p3 ){
+      pC->incrKey = 1;
+    }
+    rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, 0, &res);
+    pC->incrKey = 0;
     if( rc!=SQLITE_OK ){
       break;
     }
@@ -3828,12 +3999,13 @@ case OP_IdxIsNull: {
   z = pTos->z;
   n = pTos->n;
   for(k=0; k<n && i>0; i--){
-    if( z[k]=='a' ){
+    u64 serial_type;
+    k += sqlite3GetVarint(&z[k], &serial_type);
+    if( serial_type==6 ){   /* Serial type 6 is a NULL */
       pc = pOp->p2-1;
       break;
     }
-    while( k<n && z[k] ){ k++; }
-    k++;
+    k += sqlite3VdbeSerialTypeLen(serial_type);
   }
   Release(pTos);
   pTos--;
@@ -3955,7 +4127,9 @@ case OP_IntegrityCk: {
   aRoot = sqliteMallocRaw( sizeof(int)*(nRoot+1) );
   if( aRoot==0 ) goto no_mem;
   for(j=0, i=sqliteHashFirst(&pSet->hash); i; i=sqliteHashNext(i), j++){
-    toInt((char*)sqliteHashKey(i), &aRoot[j]);
+    i64 root64;
+    toInt((char*)sqliteHashKey(i), &root64);
+    aRoot[j] = root64;
   }
   aRoot[j] = 0;
   sqlite3HashClear(&pSet->hash);
index 8fbe6cb51ccc44d20624c4a36ef0a3ffa7e0ed38..ab8964634069d4c41abc55a0677b773a0b6ceb62 100644 (file)
@@ -72,6 +72,7 @@ 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 */
   i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */
   Btree *pBt;           /* Separate file holding temporary table */
   int nData;            /* Number of bytes in pData */
@@ -322,5 +323,5 @@ int sqlite3VdbeSerialPut(unsigned char *, const Mem *);
 int sqlite3VdbeSerialGet(const unsigned char *, u64, Mem *);
 
 int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
-int sqlite3VdbeIdxKeyCompare(BtCursor*, int , const unsigned char*, int, int*);
+int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int, int*);
 int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
index a53998a449334d7a15ba7169d52e724a05f987ef..6340a2ee5505a39cc68184c187cf7ec176b2c414 100644 (file)
@@ -1054,6 +1054,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
     }else{
       sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,sizeof(i64),&res);
     }
+    p->incrKey = 0;
     p->lastRecno = keyToInt(p->movetoTarget);
     p->recnoIsValid = res==0;
     if( res<0 ){
@@ -1347,9 +1348,12 @@ int compareMemCells(Mem *pMem1, Mem *pMem2){
       return 0;
     }
 
-    if( pMem1->i < pMem2->i ) return -1;
-    if( pMem1->i > pMem2->i ) return 1;
-    return 0;
+    return (pMem1->i - pMem2->i);
+  }
+
+  rc = (pMem2->flags&MEM_Null) - (pMem1->flags&MEM_Null);
+  if( rc ){
+    return rc;
   }
 
   /* Both values must be strings or blobs. If only one is a string, then
@@ -1357,18 +1361,12 @@ int compareMemCells(Mem *pMem1, Mem *pMem2){
   ** returns 0 and one value is longer than the other, then that value
   ** is greater.
   */
-  rc = (pMem2->flags&MEM_Null) - (pMem1->flags&MEM_Null);
-  if( rc ){
-    return rc;
-  }
   rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
   if( rc ){
     return rc;
   }
 
-  if( pMem1->n < pMem2->n ) return -1;
-  if( pMem1->n > pMem2->n ) return 1;
-  return 0;
+  return (pMem1->n - pMem2->n);
 }
 
 /*
@@ -1386,10 +1384,11 @@ int compareMemCells(Mem *pMem1, Mem *pMem2){
 ** compared to.
 */
 int sqlite3VdbeKeyCompare(
-  void *userData,                         /* not used yet */
+  void *userData,
   int nKey1, const void *pKey1, 
   int nKey2, const void *pKey2
 ){
+  Cursor *pC = (Cursor *)userData;
   int offset1 = 0;
   int offset2 = 0;
   const unsigned char *aKey1 = (const unsigned char *)pKey1;
@@ -1413,6 +1412,7 @@ 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 );
@@ -1438,12 +1438,24 @@ int sqlite3VdbeKeyCompare(
     }
   }
 
+  /* 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 ){
+    assert( offset2==nKey2 );
+    return -1;
+  }
+
   if( offset1<nKey1 ){
     return 1;
   }
   if( offset2<nKey2 ){
     return -1;
   }
+
+return_result:
+
   return 0;
 }
 
@@ -1455,7 +1467,7 @@ int sqlite3VdbeKeyCompare(
 int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
   i64 sz;
   int rc;
-  char buf[9];
+  char buf[10];
   int len;
   u64 r;
 
@@ -1463,24 +1475,33 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
   if( rc!=SQLITE_OK ){
     return rc;
   }
-  len = ((sz>9)?9:sz);
-  assert( len>=2 );
+  len = ((sz>10)?10:sz);
+
+  /* If there are less than 2 bytes in the key, this cannot be
+  ** a valid index entry. In practice this comes up for a query
+  ** of the sort "SELECT max(x) FROM t1;" when t1 is an empty table
+  ** with an index on x. In this case just call the rowid 0.
+  */
+  if( len<2 ){
+    *rowid = 0;
+    return SQLITE_OK;
+  }
 
   rc = sqlite3BtreeKey(pCur, sz-len, len, buf);
   if( rc!=SQLITE_OK ){
     return rc;
   }
 
-  len = len - 2;
-  while( buf[len] && --len );
+  len--;
+  while( buf[len-1] && --len );
 
-  sqlite3GetVarint(buf, &r);
+  sqlite3GetVarint(&buf[len], &r);
   *rowid = r;
   return SQLITE_OK;
 }
 
 int sqlite3VdbeIdxKeyCompare(
-  BtCursor *pCur
+  Cursor *pC
   int nKey, const unsigned char *pKey,
   int ignorerowid,
   int *res
@@ -1490,6 +1511,7 @@ int sqlite3VdbeIdxKeyCompare(
   int freeCellKey = 0;
   int rc;
   int len;
+  BtCursor *pCur = pC->pCursor;
 
   sqlite3BtreeKeySize(pCur, &nCellKey);
   if( nCellKey<=0 ){
@@ -1518,7 +1540,7 @@ int sqlite3VdbeIdxKeyCompare(
     nKey--;
     while( pKey[nKey] && --nKey );
   }
-  *res = sqlite3VdbeKeyCompare(0, len, pCellKey, nKey, pKey);
+  *res = sqlite3VdbeKeyCompare(pC, len, pCellKey, nKey, pKey);
   
   if( freeCellKey ){
     sqliteFree(pCellKey);
index ea79666bfdcb1ee632f3b7a2369f183dda8526ba..9d28c876eac2788247371d8ba3df0d638d47c980 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.91 2004/05/10 10:37:19 danielk1977 Exp $
+** $Id: where.c,v 1.92 2004/05/14 11:00:53 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -799,19 +799,22 @@ WhereInfo *sqlite3WhereBegin(
       sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
       sqlite3VdbeAddOp(v, OP_MakeKey, nColumn, 0);
       sqlite3AddIdxKeyType(v, pIdx);
+      sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
       if( nColumn==pIdx->nColumn || pLevel->bRev ){
-        sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
         testOp = OP_IdxGT;
       }else{
+/*
         sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
         sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0);
         sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+*/
         testOp = OP_IdxGE;
       }
       if( pLevel->bRev ){
         /* Scan in reverse order */
-        sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0);
+        /* sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0); */
         sqlite3VdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
+        sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
         start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
         sqlite3VdbeAddOp(v, OP_IdxLT, pLevel->iCur, brk);
         pLevel->op = OP_Prev;
@@ -820,6 +823,9 @@ WhereInfo *sqlite3WhereBegin(
         sqlite3VdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
         start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
         sqlite3VdbeAddOp(v, testOp, pLevel->iCur, brk);
+        if( testOp==OP_IdxGE ){
+          sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
+        }
         pLevel->op = OP_Next;
       }
       sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
@@ -1004,11 +1010,16 @@ WhereInfo *sqlite3WhereBegin(
         sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
         sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0);
         sqlite3AddIdxKeyType(v, pIdx);
+/*
         if( leFlag ){
           sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0);
         }
+*/
         if( pLevel->bRev ){
           sqlite3VdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
+          if( !geFlag ){
+            sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
+          }
         }else{
           sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
         }
@@ -1060,15 +1071,20 @@ WhereInfo *sqlite3WhereBegin(
         sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
         sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0);
         sqlite3AddIdxKeyType(v, pIdx);
+/*
         if( !geFlag ){
           sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0);
         }
+*/
         if( pLevel->bRev ){
           pLevel->iMem = pParse->nMem++;
           sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
           testOp = OP_IdxLT;
         }else{
           sqlite3VdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
+          if( !geFlag ){
+            sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
+          }
         }
       }else if( pLevel->bRev ){
         testOp = OP_Noop;
@@ -1084,6 +1100,9 @@ WhereInfo *sqlite3WhereBegin(
       if( testOp!=OP_Noop ){
         sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
         sqlite3VdbeAddOp(v, testOp, pLevel->iCur, brk);
+        if( (leFlag && !pLevel->bRev) || (!geFlag && pLevel->bRev) ){
+          sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
+        }
       }
       sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
       sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont);
index fcb82f9b95ea0d7ace7efd3de2a6456452c85c9b..bdd2a31f77d8b8aafce22c020a855a75e71dd6ba 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing built-in functions.
 #
-# $Id: func.test,v 1.16 2002/11/04 19:32:26 drh Exp $
+# $Id: func.test,v 1.17 2004/05/14 11:00:53 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -167,7 +167,7 @@ do_test func-4.3 {
 } {0 {2 1.2345678901234 2}}
 do_test func-4.4 {
   catchsql {SELECT abs(c) FROM t1 ORDER BY a}
-} {0 {3 12345.67890 5}}
+} {0 {3 12345.6789 5}}
 do_test func-4.4.1 {
   execsql {SELECT abs(a) FROM t2}
 } {1 {} 345 {} 67890}
index d233f9dc3a36ffdae6f2f86d412757b9bacb3fca..4228304961ff3737c661391279df99a33083af14 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.24 2003/09/27 00:41:28 drh Exp $
+# $Id: index.test,v 1.25 2004/05/14 11:00:53 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -335,7 +335,7 @@ do_test index-11.1 {
   }
   set sqlite_search_count 0
   concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count
-} {0.10 3}
+} {0.1 3}
 integrity_check index-11.2
 
 
@@ -344,6 +344,9 @@ integrity_check index-11.2
 # same number they should compare equal to one another.  Verify that this
 # is true in indices.
 #
+# Updated for sqlite v3: SQLite will now store these values as numbers
+# (because the affinity of column a is NUMERIC) so the quirky
+# representations are not retained. i.e. '+1.0' becomes '1'.
 do_test index-12.1 {
   execsql {
     CREATE TABLE t4(a,b);
@@ -356,38 +359,38 @@ do_test index-12.1 {
     INSERT INTO t4 VALUES('00000',7);
     SELECT a FROM t4 ORDER BY b;
   }
-} {0.0 0.00 abc -1.0 +1.0 0 00000}
+} {0 0 abc -1 1 0 0}
 do_test index-12.2 {
   execsql {
     SELECT a FROM t4 WHERE a==0 ORDER BY b
   }
-} {0.0 0.00 0 00000}
+} {0 0 0 0}
 do_test index-12.3 {
   execsql {
     SELECT a FROM t4 WHERE a<0.5 ORDER BY b
   }
-} {0.0 0.00 -1.0 0 00000}
+} {0 0 -1 0 0}
 do_test index-12.4 {
   execsql {
     SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
   }
-} {0.0 0.00 abc +1.0 0 00000}
+} {0 0 abc 1 0 0}
 do_test index-12.5 {
   execsql {
     CREATE INDEX t4i1 ON t4(a);
     SELECT a FROM t4 WHERE a==0 ORDER BY b
   }
-} {0.0 0.00 0 00000}
+} {0 0 0 0}
 do_test index-12.6 {
   execsql {
     SELECT a FROM t4 WHERE a<0.5 ORDER BY b
   }
-} {0.0 0.00 -1.0 0 00000}
+} {0 0 -1 0 0}
 do_test index-12.7 {
   execsql {
     SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
   }
-} {0.0 0.00 abc +1.0 0 00000}
+} {0 0 abc 1 0 0}
 integrity_check index-12.8
 
 # Make sure we cannot drop an automatically created index.
index 0839286d6e3ff6aceba431bb78b5993d9390d050..199aa696b7eedcb9fe1d97e30afb89d684fb8a1f 100644 (file)
@@ -10,7 +10,7 @@
 #***********************************************************************
 # This file runs all tests.
 #
-# $Id: quick.test,v 1.10 2004/05/13 13:38:52 danielk1977 Exp $
+# $Id: quick.test,v 1.11 2004/05/14 11:00:53 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -32,30 +32,21 @@ lappend EXCLUDE interrupt.test    ;# assert() fails in btree
 lappend EXCLUDE ioerr.test        ;# seg-faults (?)
 lappend EXCLUDE memdb.test        ;# fails - malformed database
 lappend EXCLUDE misc3.test        ;# seg-faults (?)
-lappend EXCLUDE printf.test       ;# sqlite3_XX vs sqlite_XX problem
 lappend EXCLUDE table.test        ;# assert() fails in pager
 lappend EXCLUDE trans.test        ;# assert() fails in pager
 lappend EXCLUDE vacuum.test       ;# seg-fault
 
+lappend EXCLUDE printf.test       ;# sqlite3_XX vs sqlite_XX problem
 lappend EXCLUDE auth.test         ;# Cannot attach empty databases.
 lappend EXCLUDE tableapi.test     ;# sqlite3_XX vs sqlite_XX problem
 lappend EXCLUDE version.test      ;# uses the btree_meta API (not updated)
 
-# Some tests fail in these file, possibly because of the manifest
-# type-aware indices (or possibly not).
-lappend EXCLUDE delete.test
-lappend EXCLUDE update.test 
+# Some tests fail in these file as a result of the partial manifest types
+# implementation.
 lappend EXCLUDE misc1.test 
-lappend EXCLUDE index.test 
-lappend EXCLUDE copy.test 
-lappend EXCLUDE conflict.test 
 lappend EXCLUDE capi2.test 
-lappend EXCLUDE null.test 
-lappend EXCLUDE trigger2.test 
+lappend EXCLUDE sort.test
 lappend EXCLUDE where.test
-lappend EXCLUDE unique.test 
-lappend EXCLUDE limit.test
-lappend EXCLUDE intpkey.test
 
 
 if {[sqlite -has-codec]} {
index 24d8ebc36ae3cf31324b63995bbef2158a412a58..1da4cc0c3e1b7d578397b1df082bfb631cedbc42 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the SELECT statement.
 #
-# $Id: select2.test,v 1.19 2004/05/13 05:16:17 danielk1977 Exp $
+# $Id: select2.test,v 1.20 2004/05/14 11:00:53 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -83,26 +83,23 @@ do_test select2-3.1 {
   execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}
 } {500}
 
-# SQLite v3: Change the expressions in the following four test cases
-# from 1000=f2 to '1000'=f2. This is because fields read in using
-# the COPY command have manifest type TEXT.
 do_test select2-3.2a {
   execsql {CREATE INDEX idx1 ON tbl2(f2)}
 } {}
 do_test select2-3.2b {
-  execsql {SELECT f1 FROM tbl2 WHERE '1000'=f2}
+  execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}
 } {500}
 do_test select2-3.2c {
-  execsql {SELECT f1 FROM tbl2 WHERE f2='1000'}
+  execsql {SELECT f1 FROM tbl2 WHERE f2=1000}
 } {500}
 do_test select2-3.2d {
   set sqlite_search_count 0
-  execsql {SELECT * FROM tbl2 WHERE '1000'=f2}
+  execsql {SELECT * FROM tbl2 WHERE 1000=f2}
   set sqlite_search_count
 } {3}
 do_test select2-3.2e {
   set sqlite_search_count 0
-  execsql {SELECT * FROM tbl2 WHERE f2='1000'}
+  execsql {SELECT * FROM tbl2 WHERE f2=1000}
   set sqlite_search_count
 } {3}
 
index 6063ebde1a67925b168c85acc1009545dfdca138..ddc43c448dfb41cd2c21a5b770b549b9fd20c4cd 100644 (file)
@@ -12,7 +12,7 @@
 # focus of this file is testing UNION, INTERSECT and EXCEPT operators
 # in SELECT statements.
 #
-# $Id: select4.test,v 1.14 2004/05/13 05:16:17 danielk1977 Exp $
+# $Id: select4.test,v 1.15 2004/05/14 11:00:53 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -197,13 +197,9 @@ do_test select4-4.1.1 {
   }
 } {5}
 
-# Update for sqlite 3:
-# Change the "UNION ALL SELECT 6" in each of the select statements
-# for the next three test cases to "UNION ALL SELECT '6'". This is
-# to accomadate manifest typing.
 do_test select4-4.1.2 {
   execsql {
-    SELECT DISTINCT log FROM t1 UNION ALL SELECT '6'
+    SELECT DISTINCT log FROM t1 UNION ALL SELECT 6
     INTERSECT
     SELECT n FROM t1 WHERE log=3
     ORDER BY log;
@@ -212,7 +208,7 @@ do_test select4-4.1.2 {
 do_test select4-4.1.3 {
   execsql {
     CREATE TABLE t2 AS
-      SELECT DISTINCT log FROM t1 UNION ALL SELECT '6'
+      SELECT DISTINCT log FROM t1 UNION ALL SELECT 6
       INTERSECT
       SELECT n FROM t1 WHERE log=3
       ORDER BY log;
@@ -223,7 +219,7 @@ execsql {DROP TABLE t2}
 do_test select4-4.1.4 {
   execsql {
     CREATE TABLE t2 AS
-      SELECT DISTINCT log FROM t1 UNION ALL SELECT '6'
+      SELECT DISTINCT log FROM t1 UNION ALL SELECT 6
       INTERSECT
       SELECT n FROM t1 WHERE log=3
       ORDER BY log DESC;
@@ -473,19 +469,16 @@ do_test select4-7.4 {
 } {n 1 log 0 n 2 log 1}
 
 # Make sure DISTINCT works appropriately on TEXT and NUMERIC columns.
-#
-# Update for sqlite v3:
-# Insert X+0.0 instead of X to make sure X has manifest type NUMERIC.
 do_test select4-8.1 {
   execsql {
     BEGIN;
     CREATE TABLE t3(a text, b float, c text);
-    INSERT INTO t3 VALUES(1, 1.1 + 0.0, '1.1');
-    INSERT INTO t3 VALUES(2, 1.10 + 0.0, '1.10');
-    INSERT INTO t3 VALUES(3, 1.10 + 0.0, '1.1');
-    INSERT INTO t3 VALUES(4, 1.1 + 0.0, '1.10');
-    INSERT INTO t3 VALUES(5, 1.2 + 0.0, '1.2');
-    INSERT INTO t3 VALUES(6, 1.3 + 0.0, '1.3');
+    INSERT INTO t3 VALUES(1, 1.1, '1.1');
+    INSERT INTO t3 VALUES(2, 1.10, '1.10');
+    INSERT INTO t3 VALUES(3, 1.10, '1.1');
+    INSERT INTO t3 VALUES(4, 1.1, '1.10');
+    INSERT INTO t3 VALUES(5, 1.2, '1.2');
+    INSERT INTO t3 VALUES(6, 1.3, '1.3');
     COMMIT;
   }
   execsql {
index 90ec06a8aaf67a6d92bcb87cbebab157aa456bda..3cb8f6b77e60d0bc1ec5347feeb7ab47f65c6ba4 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the CREATE TABLE statement.
 #
-# $Id: sort.test,v 1.9 2003/04/18 17:45:15 drh Exp $
+# $Id: sort.test,v 1.10 2004/05/14 11:00:53 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -66,10 +66,10 @@ do_test sort-1.4 {
 } {2 3 6 7 1 4 5 8}
 do_test sort-1.5 {
   execsql {SELECT flt FROM t1 ORDER BY flt}
-} {-11 -1.6 -0.0013442 0.123 2.15 3.141592653 123.0 4221.0}
+} {-11 -1.6 -0.0013442 0.123 2.15 3.141592653 123 4221}
 do_test sort-1.6 {
   execsql {SELECT flt FROM t1 ORDER BY flt DESC}
-} {4221.0 123.0 3.141592653 2.15 0.123 -0.0013442 -1.6 -11}
+} {4221 123 3.141592653 2.15 0.123 -0.0013442 -1.6 -11}
 do_test sort-1.7 {
   execsql {SELECT roman FROM t1 ORDER BY roman}
 } {I II III IV V VI VII VIII}
@@ -356,6 +356,6 @@ do_test sort-8.1 {
     INSERT INTO t5 VALUES(100.0,'A2');
     SELECT * FROM t5 ORDER BY a, b;
   }
-} {100 A1 100.0 A2}
+} {100 A1 100 A2}
 
 finish_test