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:
drh 2002-07-18 00:34:09 +00:00
parent 53e3fc70bf
commit 491791a827
12 changed files with 206 additions and 71 deletions

View File

@ -1 +1 @@
2.5.6
2.6.0

View File

@ -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

View File

@ -1 +1 @@
bbca16f88d00cd33ac7229edf3ee4623eff6e62f
20d152fcddb4fa53556a9c93c7a869600a7c5183

View File

@ -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);

View File

@ -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);
}
}

View File

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.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);

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.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 ){

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.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));

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.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++){

View File

@ -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 {

View File

@ -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;
}

View 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.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