diff --git a/manifest b/manifest index 82bd338898..18e3a64474 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index cfe1845b60..be01826201 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f63fb6dd4e8e33d4c1983396b1a0305836ee4df7 \ No newline at end of file +dbfe6e93166d9557d66cab9dca7977baa3501e5e \ No newline at end of file diff --git a/src/build.c b/src/build.c index b672449492..1881aba249 100644 --- a/src/build.c +++ b/src/build.c @@ -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 @@ -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); } diff --git a/src/date.c b/src/date.c index 0c332abe51..824f2732eb 100644 --- a/src/date.c +++ b/src/date.c @@ -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; diff --git a/src/func.c b/src/func.c index 5d95ca0cd3..5a4a46147d 100644 --- a/src/func.c +++ b/src/func.c @@ -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 #include @@ -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; diff --git a/src/insert.c b/src/insert.c index 06785ed336..86c2fcc2ed 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,10 +12,61 @@ ** 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; inCol; 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); diff --git a/src/shell.c b/src/shell.c index 648a9bbec8..ef853dc7ff 100644 --- a/src/shell.c +++ b/src/shell.c @@ -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 #include @@ -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); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5f264faf6c..e29a4c9863 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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*); diff --git a/src/update.c b/src/update.c index 71d8938995..2c3c3c300d 100644 --- a/src/update.c +++ b/src/update.c @@ -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); diff --git a/src/util.c b/src/util.c index 5524245d94..07bb1b99aa 100644 --- a/src/util.c +++ b/src/util.c @@ -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 @@ -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 ){ diff --git a/src/vdbe.c b/src/vdbe.c index d694820202..7f00e341bf 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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 && inCursor ); 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; k0; 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( khash); 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); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 8fbe6cb51c..ab89646340 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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 *); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index a53998a449..6340a2ee55 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -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( offset19)?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); diff --git a/src/where.c b/src/where.c index ea79666bfd..9d28c876ea 100644 --- a/src/where.c +++ b/src/where.c @@ -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); diff --git a/test/func.test b/test/func.test index fcb82f9b95..bdd2a31f77 100644 --- a/test/func.test +++ b/test/func.test @@ -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} diff --git a/test/index.test b/test/index.test index d233f9dc3a..4228304961 100644 --- a/test/index.test +++ b/test/index.test @@ -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. diff --git a/test/quick.test b/test/quick.test index 0839286d6e..199aa696b7 100644 --- a/test/quick.test +++ b/test/quick.test @@ -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]} { diff --git a/test/select2.test b/test/select2.test index 24d8ebc36a..1da4cc0c3e 100644 --- a/test/select2.test +++ b/test/select2.test @@ -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} diff --git a/test/select4.test b/test/select4.test index 6063ebde1a..ddc43c448d 100644 --- a/test/select4.test +++ b/test/select4.test @@ -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 { diff --git a/test/sort.test b/test/sort.test index 90ec06a8aa..3cb8f6b77e 100644 --- a/test/sort.test +++ b/test/sort.test @@ -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