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