-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
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
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
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
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
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
-bbca16f88d00cd33ac7229edf3ee4623eff6e62f
\ No newline at end of file
+20d152fcddb4fa53556a9c93c7a869600a7c5183
\ No newline at end of file
** 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>
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);
** 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"
}
}
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);
}
}
** 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>
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 */
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);
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);
** 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"
}
}
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 ){
** 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"
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
/*
** 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;
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:
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));
** 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"
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;
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);
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++){
*************************************************************************
** 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"
**
** 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 {
** 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>
** 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
containsNull = 1;
}else if( pOp->p3 && pOp->p3[j]=='t' ){
Stringify(p, i);
- }else if( flags & STK_Real ){
- z = aStack[i].z;
- sqliteRealToSortable(aStack[i].r, &z[1]);
- z[0] = 0;
+ aStack[i].flags &= ~(STK_Int|STK_Real);
+ nByte += aStack[i].n+1;
+ }else if( (flags & (STK_Real|STK_Int))!=0 || isNumber(zStack[i]) ){
+ if( (flags & (STK_Real|STK_Int))==STK_Int ){
+ aStack[i].r = aStack[i].i;
+ }else if( (flags & (STK_Real|STK_Int))==0 ){
+ aStack[i].r = atof(zStack[i]);
+ }
Release(p, i);
- len = strlen(&z[1]);
- zStack[i] = 0;
- aStack[i].flags = STK_Real;
- aStack[i].n = len+2;
- nByte += aStack[i].n;
- }else if( flags & STK_Int ){
z = aStack[i].z;
- aStack[i].r = aStack[i].i;
- sqliteRealToSortable(aStack[i].r, &z[1]);
- z[0] = 0;
- Release(p, i);
- len = strlen(&z[1]);
+ sqliteRealToSortable(aStack[i].r, z);
+ len = strlen(z);
zStack[i] = 0;
- aStack[i].flags = STK_Int;
- aStack[i].n = len+2;
- nByte += aStack[i].n;
+ aStack[i].flags = STK_Real;
+ aStack[i].n = len+1;
+ nByte += aStack[i].n+1;
}else{
- assert( flags & STK_Str );
- if( isNumber(zStack[i]) ){
- aStack[i].r = atof(zStack[i]);
- Release(p, i);
- z = aStack[i].z;
- sqliteRealToSortable(aStack[i].r, &z[1]);
- z[0] = 0;
- len = strlen(&z[1]);
- zStack[i] = 0;
- aStack[i].flags = STK_Real;
- aStack[i].n = len+2;
- }
- nByte += aStack[i].n;
+ nByte += aStack[i].n+1;
}
}
if( nByte+sizeof(u32)>MAX_BYTES_PER_ROW ){
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;
}
# 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
}
} {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