-C New\sNext\sopcode\sand\sindexing\sstyle\simplemented.\s(CVS\s304)
-D 2001-11-07T16:48:27
+C The\snew\scode\sfor\staking\sadvantage\sof\sinequalities\sin\sWHERE\sclauses\nis\sin\splace.\s\sIt\sappears\sto\swork.\s(CVS\s305)
+D 2001-11-08T00:45:21
F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd
F Makefile.template 1fdb891f14083ee0b63cf7282f91529634438e7a
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
F src/btree.h 0250a0a577a98cc64ddf1582d50c08b8d2451650
F src/build.c 40b7d14435e2cfc5298e8b7bab5e92ed26f42310
F src/delete.c 5d93a21c1388cfb1359bda01c072f25583a2f4f2
-F src/expr.c 2dd0252ced345c1e64db015b94dc6b5d7a57eef3
+F src/expr.c 53515a7ba787bf4f0b3f73be30eb86aadb6f1b90
F src/hash.c d0110e6da70a5962e21575fccf8206f7d9d75e00
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
F src/insert.c 3526be771a01035198bef28d8f370cbcab94f46d
F src/shell.c 71597951753b56a97fea1c7a30908f31e635c00c
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 934de9112747ad8d8e7d5fec44876246b24ca5a3
-F src/sqliteInt.h 555cff59458966ac16f044cc985f2267c75a606e
+F src/sqliteInt.h aa26c7f8a0c5c3210a81177c60ca08bf8f3f7825
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
F src/tclsqlite.c 4896e078495bf868742f5394dcf01c5efe5bea02
-F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
+F src/test1.c 41eabe255970ef947263b94145c9b2766bab8675
F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
F src/update.c b1e315e20b98a013d30fd9ff3b7d9dc4f29b39b3
F src/util.c ac83973ecc647d3d3c58708f148442365abf9b94
-F src/vdbe.c 66e82eb4d042e34752ed23c3c13f921a895376af
-F src/vdbe.h da7c01076268f4fa1a17b7d6f27e21c3fd9a5d3f
-F src/where.c a6cac72314905902542c5239683d07fed27f6ee1
+F src/vdbe.c b4cdc0017bf0574ededf17d7ff5f1d66a58bf430
+F src/vdbe.h cd4c8647051a0c22c0e133c375f1cd17bb8b1e06
+F src/where.c 13a112b720fffd40612051f9e6d37262c4c818c8
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
F test/bigrow.test 9458134d67f81559845f934fdd6802fe19a68ad1
F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce
F test/expr.test b4171c84b767f7b7e94dbce4824ba8e981a1c72f
F test/func.test 9012f7fc5369422c890e93549aa61d762e0c8bb3
F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
-F test/index.test 6076f29d09a4f26a2efa38b03b8cc338b8662f0e
+F test/index.test c58829080a24aed3f897d7a77d9592aea30164fa
F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
F test/insert2.test d6901ca931e308fea7fca8c95ebe7dc957cc9fc2
F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
-F test/rowid.test 427bfbbe9684fe7a2f851aa05badaae6d4972ce8
+F test/rowid.test ba56df896cb913b70d06661d960869e310fe426e
F test/select1.test 13aa0a5545209a73d1073cb9062a1b9075b734ae
-F test/select2.test f91c903e2bab0e9d45274855a981eebf846d5e32
+F test/select2.test 070c7ac1a66e294004a2a1bfdc9cd2f4d29c1e6e
F test/select3.test 5e1fe8e5a4e63fb2827ab3b89527e0fd4ae35259
F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
F test/unique.test ef1f67607a7109e9c0842cd8557550fb121d7ec6
F test/update.test 8cf76467d46b1650539763c95d5208340c61d561
F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e
-F test/where.test 43d5ac94da3f3722375307f948884dc79b326a91
+F test/where.test 20b19475fe894b86b06d2979592260dd16beeb17
F tool/lemon.c bfd036ab9309c7f34e1357d9a065ad137814e741
F tool/lempar.c 9b604e6a8b3d55c0b9cbcb130a7302fb8bafe2b9
F tool/memleak.awk 296dfbce7a9ca499b95ce04e30334e64a50052e0
F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
-P e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0
-R 2ff273a13d7d9aa297cec267ea881bcc
+P decbeb9151885fee473b3fa58c8cf78a2338d2d8
+R d92c3b8d059b1ac938a54da5297c6da3
U drh
-Z 17c5246b4b0cf0179995e37754c3ee96
+Z 73b06b3dcf3434a2ed8ea2fd74f12aeb
-decbeb9151885fee473b3fa58c8cf78a2338d2d8
\ No newline at end of file
+262bcd17df19f45def6144b5a7e0602ca5b03deb
\ No newline at end of file
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.32 2001/10/22 02:58:10 drh Exp $
+** $Id: expr.c,v 1.33 2001/11/08 00:45:21 drh Exp $
*/
#include "sqliteInt.h"
{ "max", 3, FN_Max },
{ "sum", 3, FN_Sum },
{ "avg", 3, FN_Avg },
- { "fcnt", 4, FN_Fcnt }, /* Used for testing only */
{ "length", 6, FN_Length },
{ "substr", 6, FN_Substr },
{ "abs", 3, FN_Abs },
too_many_args = n>3;
break;
}
- /* The "fcnt(*)" function always returns the number of OP_MoveTo
- ** operations that have occurred so far while processing the
- ** SQL statement. This information can be used by test procedures
- ** to verify that indices are being used properly to minimize
- ** searching. All arguments to fcnt() are ignored. fcnt() has
- ** no use (other than testing) that we are aware of.
- */
- case FN_Fcnt: {
- n = 0;
- break;
- }
-
default: break;
}
if( no_such_func ){
int i;
ExprList *pList = pExpr->pList;
switch( id ){
- case FN_Fcnt: {
- sqliteVdbeAddOp(v, OP_Fcnt, 0, 0);
- break;
- }
case FN_Min:
case FN_Max: {
op = id==FN_Min ? OP_Min : OP_Max;
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.68 2001/11/07 16:48:27 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.69 2001/11/08 00:45:21 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
int iMem; /* Memory cell used by this level */
Index *pIdx; /* Index used */
int iCur; /* Cursor number used for this index */
+ int score; /* How well this indexed scored */
int brk; /* Jump here to break out of the loop */
int cont; /* Jump here to continue with the next loop cycle */
int op, p1, p2; /* Opcode used to terminate the loop */
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test1.c,v 1.4 2001/09/24 03:12:40 drh Exp $
+** $Id: test1.c,v 1.5 2001/11/08 00:45:21 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
** Register commands with the TCL interpreter.
*/
int Sqlitetest1_Init(Tcl_Interp *interp){
+ extern int sqlite_search_count;
Tcl_CreateCommand(interp, "sqlite_mprintf_int", sqlite_mprintf_int, 0, 0);
Tcl_CreateCommand(interp, "sqlite_mprintf_str", sqlite_mprintf_str, 0, 0);
Tcl_CreateCommand(interp, "sqlite_mprintf_double", sqlite_mprintf_double,0,0);
Tcl_CreateCommand(interp, "sqlite_get_table_printf", test_get_table_printf,
0, 0);
Tcl_CreateCommand(interp, "sqlite_close", sqlite_test_close, 0, 0);
+ Tcl_LinkVar(interp, "sqlite_search_count",
+ (char*)&sqlite_search_count, TCL_LINK_INT);
#ifdef MEMORY_DEBUG
Tcl_CreateCommand(interp, "sqlite_malloc_fail", sqlite_malloc_fail, 0, 0);
Tcl_CreateCommand(interp, "sqlite_malloc_stat", sqlite_malloc_stat, 0, 0);
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.95 2001/11/07 16:48:27 drh Exp $
+** $Id: vdbe.c,v 1.96 2001/11/08 00:45:22 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
+/*
+** The following global variable is incremented every time a cursor
+** moves, either by the OP_MoveTo or the OP_Next opcode. The test
+** procedures use this information to make sure that indices are
+** working correctly.
+*/
+int sqlite_search_count = 0;
+
/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine. Each instruction is an instance
Agg agg; /* Aggregate information */
int nSet; /* Number of sets allocated */
Set *aSet; /* An array of sets */
- int nFetch; /* Number of OP_Fetch instructions executed */
int nCallback; /* Number of callbacks invoked so far */
int iLimit; /* Limit on the number of callbacks remaining */
int iOffset; /* Offset before beginning to do callbacks */
"Transaction", "Commit", "Rollback", "ReadCookie",
"SetCookie", "VerifyCookie", "Open", "OpenTemp",
"OpenWrite", "OpenAux", "OpenWrAux", "Close",
- "MoveTo", "Fcnt", "NewRecno", "Put",
- "Distinct", "Found", "NotFound", "Delete",
- "Column", "KeyAsData", "Recno", "FullKey",
- "Rewind", "Next", "Destroy", "Clear",
- "CreateIndex", "CreateTable", "Reorganize", "IdxPut",
- "IdxDelete", "IdxRecno", "IdxGT", "IdxGE",
- "MemLoad", "MemStore", "ListWrite", "ListRewind",
- "ListRead", "ListReset", "SortPut", "SortMakeRec",
- "SortMakeKey", "Sort", "SortNext", "SortCallback",
- "SortReset", "FileOpen", "FileRead", "FileColumn",
- "AggReset", "AggFocus", "AggIncr", "AggNext",
- "AggSet", "AggGet", "SetInsert", "SetFound",
- "SetNotFound", "MakeRecord", "MakeKey", "MakeIdxKey",
- "IncrKey", "Goto", "If", "Halt",
- "ColumnCount", "ColumnName", "Callback", "NullCallback",
- "Integer", "String", "Pop", "Dup",
- "Pull", "Add", "AddImm", "Subtract",
- "Multiply", "Divide", "Remainder", "BitAnd",
- "BitOr", "BitNot", "ShiftLeft", "ShiftRight",
- "AbsValue", "Precision", "Min", "Max",
- "Like", "Glob", "Eq", "Ne",
- "Lt", "Le", "Gt", "Ge",
- "IsNull", "NotNull", "Negative", "And",
- "Or", "Not", "Concat", "Noop",
- "Strlen", "Substr", "Limit",
+ "MoveTo", "NewRecno", "Put", "Distinct",
+ "Found", "NotFound", "Delete", "Column",
+ "KeyAsData", "Recno", "FullKey", "Rewind",
+ "Next", "Destroy", "Clear", "CreateIndex",
+ "CreateTable", "Reorganize", "IdxPut", "IdxDelete",
+ "IdxRecno", "IdxGT", "IdxGE", "MemLoad",
+ "MemStore", "ListWrite", "ListRewind", "ListRead",
+ "ListReset", "SortPut", "SortMakeRec", "SortMakeKey",
+ "Sort", "SortNext", "SortCallback", "SortReset",
+ "FileOpen", "FileRead", "FileColumn", "AggReset",
+ "AggFocus", "AggIncr", "AggNext", "AggSet",
+ "AggGet", "SetInsert", "SetFound", "SetNotFound",
+ "MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey",
+ "Goto", "If", "Halt", "ColumnCount",
+ "ColumnName", "Callback", "NullCallback", "Integer",
+ "String", "Pop", "Dup", "Pull",
+ "Add", "AddImm", "Subtract", "Multiply",
+ "Divide", "Remainder", "BitAnd", "BitOr",
+ "BitNot", "ShiftLeft", "ShiftRight", "AbsValue",
+ "Precision", "Min", "Max", "Like",
+ "Glob", "Eq", "Ne", "Lt",
+ "Le", "Gt", "Ge", "IsNull",
+ "NotNull", "Negative", "And", "Or",
+ "Not", "Concat", "Noop", "Strlen",
+ "Substr", "Limit",
};
/*
sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res);
pC->recnoIsValid = 0;
}
- p->nFetch++;
+ sqlite_search_count++;
if( res<0 ){
sqliteBtreeNext(pC->pCursor, &res);
pC->recnoIsValid = 0;
break;
}
-/* Opcode: Fcnt * * *
-**
-** Push an integer onto the stack which is the total number of
-** MoveTo opcodes that have been executed by this virtual machine.
-**
-** This instruction is used to implement the special fcnt() function
-** in the SQL dialect that SQLite understands. fcnt() is used for
-** testing purposes.
-*/
-case OP_Fcnt: {
- int i = ++p->tos;
- VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
- aStack[i].i = p->nFetch;
- aStack[i].flags = STK_Int;
- break;
-}
-
/* Opcode: Distinct P1 P2 *
**
** Use the top of the stack as a key. If a record with that key does
rc = sqliteBtreeNext(pCrsr, &res);
if( res==0 ){
pc = pOp->p2 - 1;
- p->nFetch++;
+ sqlite_search_count++;
}
p->aCsr[i].recnoIsValid = 0;
}
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
-** $Id: vdbe.h,v 1.35 2001/11/07 16:48:28 drh Exp $
+** $Id: vdbe.h,v 1.36 2001/11/08 00:45:22 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#define OP_OpenWrAux 11
#define OP_Close 12
#define OP_MoveTo 13
-#define OP_Fcnt 14
-#define OP_NewRecno 15
-#define OP_Put 16
-#define OP_Distinct 17
-#define OP_Found 18
-#define OP_NotFound 19
-#define OP_Delete 20
-#define OP_Column 21
-#define OP_KeyAsData 22
-#define OP_Recno 23
-#define OP_FullKey 24
-#define OP_Rewind 25
-#define OP_Next 26
-
-#define OP_Destroy 27
-#define OP_Clear 28
-#define OP_CreateIndex 29
-#define OP_CreateTable 30
-#define OP_Reorganize 31
-
-#define OP_IdxPut 32
-#define OP_IdxDelete 33
-#define OP_IdxRecno 34
-#define OP_IdxGT 35
-#define OP_IdxGE 36
-
-#define OP_MemLoad 37
-#define OP_MemStore 38
-
-#define OP_ListWrite 39
-#define OP_ListRewind 40
-#define OP_ListRead 41
-#define OP_ListReset 42
-
-#define OP_SortPut 43
-#define OP_SortMakeRec 44
-#define OP_SortMakeKey 45
-#define OP_Sort 46
-#define OP_SortNext 47
-#define OP_SortCallback 48
-#define OP_SortReset 49
-
-#define OP_FileOpen 50
-#define OP_FileRead 51
-#define OP_FileColumn 52
-
-#define OP_AggReset 53
-#define OP_AggFocus 54
-#define OP_AggIncr 55
-#define OP_AggNext 56
-#define OP_AggSet 57
-#define OP_AggGet 58
-
-#define OP_SetInsert 59
-#define OP_SetFound 60
-#define OP_SetNotFound 61
-
-#define OP_MakeRecord 62
-#define OP_MakeKey 63
-#define OP_MakeIdxKey 64
-#define OP_IncrKey 65
-
-#define OP_Goto 66
-#define OP_If 67
-#define OP_Halt 68
-
-#define OP_ColumnCount 69
-#define OP_ColumnName 70
-#define OP_Callback 71
-#define OP_NullCallback 72
-
-#define OP_Integer 73
-#define OP_String 74
-#define OP_Pop 75
-#define OP_Dup 76
-#define OP_Pull 77
-
-#define OP_Add 78
-#define OP_AddImm 79
-#define OP_Subtract 80
-#define OP_Multiply 81
-#define OP_Divide 82
-#define OP_Remainder 83
-#define OP_BitAnd 84
-#define OP_BitOr 85
-#define OP_BitNot 86
-#define OP_ShiftLeft 87
-#define OP_ShiftRight 88
-#define OP_AbsValue 89
-#define OP_Precision 90
-#define OP_Min 91
-#define OP_Max 92
-#define OP_Like 93
-#define OP_Glob 94
-#define OP_Eq 95
-#define OP_Ne 96
-#define OP_Lt 97
-#define OP_Le 98
-#define OP_Gt 99
-#define OP_Ge 100
-#define OP_IsNull 101
-#define OP_NotNull 102
-#define OP_Negative 103
-#define OP_And 104
-#define OP_Or 105
-#define OP_Not 106
-#define OP_Concat 107
-#define OP_Noop 108
-
-#define OP_Strlen 109
-#define OP_Substr 110
-
-#define OP_Limit 111
-
-#define OP_MAX 111
+#define OP_NewRecno 14
+#define OP_Put 15
+#define OP_Distinct 16
+#define OP_Found 17
+#define OP_NotFound 18
+#define OP_Delete 19
+#define OP_Column 20
+#define OP_KeyAsData 21
+#define OP_Recno 22
+#define OP_FullKey 23
+#define OP_Rewind 24
+#define OP_Next 25
+
+#define OP_Destroy 26
+#define OP_Clear 27
+#define OP_CreateIndex 28
+#define OP_CreateTable 29
+#define OP_Reorganize 30
+
+#define OP_IdxPut 31
+#define OP_IdxDelete 32
+#define OP_IdxRecno 33
+#define OP_IdxGT 34
+#define OP_IdxGE 35
+
+#define OP_MemLoad 36
+#define OP_MemStore 37
+
+#define OP_ListWrite 38
+#define OP_ListRewind 39
+#define OP_ListRead 40
+#define OP_ListReset 41
+
+#define OP_SortPut 42
+#define OP_SortMakeRec 43
+#define OP_SortMakeKey 44
+#define OP_Sort 45
+#define OP_SortNext 46
+#define OP_SortCallback 47
+#define OP_SortReset 48
+
+#define OP_FileOpen 49
+#define OP_FileRead 50
+#define OP_FileColumn 51
+
+#define OP_AggReset 52
+#define OP_AggFocus 53
+#define OP_AggIncr 54
+#define OP_AggNext 55
+#define OP_AggSet 56
+#define OP_AggGet 57
+
+#define OP_SetInsert 58
+#define OP_SetFound 59
+#define OP_SetNotFound 60
+
+#define OP_MakeRecord 61
+#define OP_MakeKey 62
+#define OP_MakeIdxKey 63
+#define OP_IncrKey 64
+
+#define OP_Goto 65
+#define OP_If 66
+#define OP_Halt 67
+
+#define OP_ColumnCount 68
+#define OP_ColumnName 69
+#define OP_Callback 70
+#define OP_NullCallback 71
+
+#define OP_Integer 72
+#define OP_String 73
+#define OP_Pop 74
+#define OP_Dup 75
+#define OP_Pull 76
+
+#define OP_Add 77
+#define OP_AddImm 78
+#define OP_Subtract 79
+#define OP_Multiply 80
+#define OP_Divide 81
+#define OP_Remainder 82
+#define OP_BitAnd 83
+#define OP_BitOr 84
+#define OP_BitNot 85
+#define OP_ShiftLeft 86
+#define OP_ShiftRight 87
+#define OP_AbsValue 88
+#define OP_Precision 89
+#define OP_Min 90
+#define OP_Max 91
+#define OP_Like 92
+#define OP_Glob 93
+#define OP_Eq 94
+#define OP_Ne 95
+#define OP_Lt 96
+#define OP_Le 97
+#define OP_Gt 98
+#define OP_Ge 99
+#define OP_IsNull 100
+#define OP_NotNull 101
+#define OP_Negative 102
+#define OP_And 103
+#define OP_Or 104
+#define OP_Not 105
+#define OP_Concat 106
+#define OP_Noop 107
+
+#define OP_Strlen 108
+#define OP_Substr 109
+
+#define OP_Limit 110
+
+#define OP_MAX 110
/*
** Prototypes for the VDBE interface. See comments on the implementation
** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
-** $Id: where.c,v 1.25 2001/11/07 16:48:28 drh Exp $
+** $Id: where.c,v 1.26 2001/11/08 00:45:22 drh Exp $
*/
#include "sqliteInt.h"
return mask;
}
+/*
+** Return TRUE if the given operator is one of the operators that is
+** allowed for an indexable WHERE clause. The allowed operators are
+** "=", "<", ">", "<=", and ">=".
+*/
+static int allowedOp(int op){
+ switch( op ){
+ case TK_LT:
+ case TK_LE:
+ case TK_GT:
+ case TK_GE:
+ case TK_EQ:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
/*
** The input to this routine is an ExprInfo structure with only the
** "p" field filled in. The job of this routine is to analyze the
pInfo->indexable = 0;
pInfo->idxLeft = -1;
pInfo->idxRight = -1;
- if( pExpr->op==TK_EQ && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
+ if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
if( pExpr->pRight->op==TK_COLUMN ){
pInfo->idxRight = pExpr->pRight->iTable - base;
pInfo->indexable = 1;
Table *pTab = pTabList->a[idx].pTab;
Index *pIdx;
Index *pBestIdx = 0;
+ int bestScore = 0;
/* Check to see if there is an expression that uses only the
** ROWID field of this table. If so, set aDirect[i] to 1.
}
/* Do a search for usable indices. Leave pBestIdx pointing to
- ** the most specific usable index.
+ ** the "best" index. pBestIdx is left set to NULL if no indices
+ ** are usable.
+ **
+ ** The best index is determined as follows. For each of the
+ ** left-most terms that is fixed by an equality operator, add
+ ** 4 to the score. The right-most term of the index may be
+ ** constrained by an inequality. Add 1 if for an "x<..." constraint
+ ** and add 2 for an "x>..." constraint. Chose the index that
+ ** gives the best score.
**
- ** "Most specific" means that pBestIdx is the usable index that
- ** has the largest value for nColumn. A usable index is one for
- ** which there are subexpressions to compute every column of the
- ** index.
+ ** This scoring system is designed so that the score can later be
+ ** used to determine how the index is used. If the score&3 is 0
+ ** then all constraints are equalities. If score&1 is not 0 then
+ ** there is an inequality used as a termination key. (ex: "x<...")
+ ** If score&2 is not 0 then there is an inequality used as the
+ ** start key. (ex: "x>...");
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int columnMask = 0;
+ int eqMask = 0; /* Index columns covered by an x=... constraint */
+ int ltMask = 0; /* Index columns covered by an x<... constraint */
+ int gtMask = 0; /* Index columns covered by an x>... constraing */
+ int nEq, m, score;
- if( pIdx->nColumn>32 ) continue;
+ if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */
for(j=0; j<nExpr; j++){
if( aExpr[j].idxLeft==idx
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
int k;
for(k=0; k<pIdx->nColumn; k++){
if( pIdx->aiColumn[k]==iColumn ){
- columnMask |= 1<<k;
+ switch( aExpr[j].p->op ){
+ case TK_EQ: {
+ eqMask |= 1<<k;
+ break;
+ }
+ case TK_LE:
+ case TK_LT: {
+ ltMask |= 1<<k;
+ break;
+ }
+ case TK_GE:
+ case TK_GT: {
+ gtMask |= 1<<k;
+ break;
+ }
+ default: {
+ /* CANT_HAPPEN */
+ assert( 0 );
+ break;
+ }
+ }
break;
}
}
int k;
for(k=0; k<pIdx->nColumn; k++){
if( pIdx->aiColumn[k]==iColumn ){
- columnMask |= 1<<k;
+ switch( aExpr[j].p->op ){
+ case TK_EQ: {
+ eqMask |= 1<<k;
+ break;
+ }
+ case TK_LE:
+ case TK_LT: {
+ gtMask |= 1<<k;
+ break;
+ }
+ case TK_GE:
+ case TK_GT: {
+ ltMask |= 1<<k;
+ break;
+ }
+ default: {
+ /* CANT_HAPPEN */
+ assert( 0 );
+ break;
+ }
+ }
break;
}
}
}
}
- if( columnMask + 1 == (1<<pIdx->nColumn) ){
- if( pBestIdx==0 || pBestIdx->nColumn<pIdx->nColumn ){
- pBestIdx = pIdx;
- }
+ for(nEq=0; nEq<pIdx->nColumn; nEq++){
+ m = (1<<(nEq+1))-1;
+ if( (m & eqMask)!=m ) break;
+ }
+ score = nEq*4;
+ m = 1<<nEq;
+ if( m & ltMask ) score++;
+ if( m & gtMask ) score+=2;
+ if( score>bestScore ){
+ pBestIdx = pIdx;
+ bestScore = score;
}
}
pWInfo->a[i].pIdx = pBestIdx;
+ pWInfo->a[i].score = bestScore;
loopMask |= 1<<idx;
if( pBestIdx ){
pWInfo->a[i].iCur = nCur++;
pLevel->op = OP_Noop;
}else if( pIdx==0 ){
/* Case 2: There was no usable index. We must do a complete
- ** scan of the table.
+ ** scan of the entire database table.
*/
int start;
pLevel->p1 = base+idx;
pLevel->p2 = start;
haveKey = 0;
- }else{
- /* Case 3: We do have a usable index in pIdx.
+ }else if( pLevel->score%4==0 ){
+ /* Case 3: All index constraints are equality operators.
*/
int start;
- for(j=0; j<pIdx->nColumn; j++){
+ int testOp;
+ int nColumn = pLevel->score/4;
+ for(j=0; j<nColumn; j++){
for(k=0; k<nExpr; k++){
if( aExpr[k].p==0 ) continue;
if( aExpr[k].idxLeft==idx
+ && aExpr[k].p->op==TK_EQ
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
&& aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
){
break;
}
if( aExpr[k].idxRight==idx
+ && aExpr[k].p->op==TK_EQ
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
&& aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
){
pLevel->iMem = pParse->nMem++;
brk = pLevel->brk = sqliteVdbeMakeLabel(v);
cont = pLevel->cont = sqliteVdbeMakeLabel(v);
- sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0);
- sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
+ sqliteVdbeAddOp(v, OP_MakeKey, nColumn, 0);
+ if( nColumn==pIdx->nColumn ){
+ sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
+ testOp = OP_IdxGT;
+ }else{
+ sqliteVdbeAddOp(v, OP_Dup, 0, 0);
+ sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
+ sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+ testOp = OP_IdxGE;
+ }
sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqliteVdbeAddOp(v, OP_IdxGT, pLevel->iCur, brk);
+ sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
if( i==pTabList->nId-1 && pushKey ){
haveKey = 1;
pLevel->op = OP_Next;
pLevel->p1 = pLevel->iCur;
pLevel->p2 = start;
+ }else{
+ /* Case 4: The contraints on the right-most index field are
+ ** inequalities.
+ */
+ int score = pLevel->score;
+ int nEqColumn = score/4;
+ int start;
+ int leFlag, geFlag;
+ int testOp;
+
+ /* Evaluate the equality constraints
+ */
+ for(j=0; j<nEqColumn; j++){
+ for(k=0; k<nExpr; k++){
+ if( aExpr[k].p==0 ) continue;
+ if( aExpr[k].idxLeft==idx
+ && aExpr[k].p->op==TK_EQ
+ && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
+ && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
+ ){
+ sqliteExprCode(pParse, aExpr[k].p->pRight);
+ aExpr[k].p = 0;
+ break;
+ }
+ if( aExpr[k].idxRight==idx
+ && aExpr[k].p->op==TK_EQ
+ && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
+ && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
+ ){
+ sqliteExprCode(pParse, aExpr[k].p->pLeft);
+ aExpr[k].p = 0;
+ break;
+ }
+ }
+ }
+
+ /* Duplicate the equality contraint values because they will all be
+ ** used twice: once to make the termination key and once to make the
+ ** start key.
+ */
+ for(j=0; j<nEqColumn; j++){
+ sqliteVdbeAddOp(v, OP_Dup, nEqColumn-1, 0);
+ }
+
+ /* Generate the termination key. This is the key value that
+ ** will end the search. There is no termination key if there
+ ** are no equality contraints and no "X<..." constraint.
+ */
+ if( (score & 1)!=0 ){
+ for(k=0; k<nExpr; k++){
+ Expr *pExpr = aExpr[k].p;
+ if( pExpr==0 ) continue;
+ if( aExpr[k].idxLeft==idx
+ && (pExpr->op==TK_LT || pExpr->op==TK_LE)
+ && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
+ && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
+ ){
+ sqliteExprCode(pParse, pExpr->pRight);
+ leFlag = pExpr->op==TK_LE;
+ aExpr[k].p = 0;
+ break;
+ }
+ if( aExpr[k].idxRight==idx
+ && (pExpr->op==TK_GT || pExpr->op==TK_GE)
+ && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
+ && pExpr->pRight->iColumn==pIdx->aiColumn[j]
+ ){
+ sqliteExprCode(pParse, pExpr->pLeft);
+ leFlag = pExpr->op==TK_GE;
+ aExpr[k].p = 0;
+ break;
+ }
+ }
+ testOp = OP_IdxGE;
+ }else{
+ testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop;
+ leFlag = 1;
+ }
+ if( testOp!=OP_Noop ){
+ pLevel->iMem = pParse->nMem++;
+ sqliteVdbeAddOp(v, OP_MakeKey, nEqColumn + (score & 1), 0);
+ if( leFlag ){
+ sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
+ }
+ sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+ }
+
+ /* Generate the start key. This is the key that defines the lower
+ ** bound on the search. There is no start key if there are not
+ ** equality constraints and if there is no "X>..." constraint. In
+ ** that case, generate a "Rewind" instruction in place of the
+ ** start key search.
+ */
+ if( (score & 2)!=0 ){
+ for(k=0; k<nExpr; k++){
+ Expr *pExpr = aExpr[k].p;
+ if( pExpr==0 ) continue;
+ if( aExpr[k].idxLeft==idx
+ && (pExpr->op==TK_GT || pExpr->op==TK_GE)
+ && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
+ && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
+ ){
+ sqliteExprCode(pParse, pExpr->pRight);
+ geFlag = pExpr->op==TK_GE;
+ aExpr[k].p = 0;
+ break;
+ }
+ if( aExpr[k].idxRight==idx
+ && (pExpr->op==TK_LT || pExpr->op==TK_LE)
+ && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
+ && pExpr->pRight->iColumn==pIdx->aiColumn[j]
+ ){
+ sqliteExprCode(pParse, pExpr->pLeft);
+ geFlag = pExpr->op==TK_LE;
+ aExpr[k].p = 0;
+ break;
+ }
+ }
+ }
+ brk = pLevel->brk = sqliteVdbeMakeLabel(v);
+ cont = pLevel->cont = sqliteVdbeMakeLabel(v);
+ if( nEqColumn>0 || (score&2)!=0 ){
+ sqliteVdbeAddOp(v, OP_MakeKey, nEqColumn + ((score&2)!=0), 0);
+ if( !geFlag ){
+ sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
+ }
+ sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
+ }else{
+ sqliteVdbeAddOp(v, OP_Rewind, pLevel->iCur, brk);
+ }
+
+ /* Generate the the top of the loop. If there is a termination
+ ** key we have to test for that key and abort at the top of the
+ ** loop.
+ */
+ start = sqliteVdbeCurrentAddr(v);
+ if( testOp!=OP_Noop ){
+ sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
+ sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
+ }
+ sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
+ if( i==pTabList->nId-1 && pushKey ){
+ haveKey = 1;
+ }else{
+ sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
+ haveKey = 0;
+ }
+
+ /* Record the instruction used to terminate the loop.
+ */
+ pLevel->op = OP_Next;
+ pLevel->p1 = pLevel->iCur;
+ pLevel->p2 = start;
}
loopMask |= 1<<idx;
# This file implements regression tests for SQLite library. The
# focus of this file is testing the CREATE INDEX statement.
#
-# $Id: index.test,v 1.14 2001/09/27 15:11:55 drh Exp $
+# $Id: index.test,v 1.15 2001/11/08 00:45:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
for {set i 1} {$i<=50} {incr i} {
execsql "INSERT INTO t3 VALUES('x${i}x',$i,0.$i)"
}
- execsql {SELECT c, fcnt() FROM t3 WHERE b==10}
-} {0.10 1}
+ set sqlite_search_count 0
+ concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count
+} {0.10 3}
finish_test
# focus of this file is testing the magic ROWID column that is
# found on all tables.
#
-# $Id: rowid.test,v 1.5 2001/09/18 02:02:23 drh Exp $
+# $Id: rowid.test,v 1.6 2001/11/08 00:45:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
} {256}
do_test rowid-4.5 {
execsql {CREATE INDEX idxt2 ON t2(y)}
- execsql {
- SELECT t1.x, fcnt() FROM t2, t1
+ set sqlite_search_count 0
+ concat [execsql {
+ SELECT t1.x FROM t2, t1
WHERE t2.y==256 AND t1.rowid==t2.rowid
- }
-} {4 1}
+ }] $sqlite_search_count
+} {4 3}
do_test rowid-4.5.1 {
- execsql {
- SELECT t1.x, fcnt() FROM t2, t1
+ set sqlite_search_count 0
+ concat [execsql {
+ SELECT t1.x FROM t2, t1
WHERE t1.OID==t2.rowid AND t2.y==81
- }
-} {3 1}
+ }] $sqlite_search_count
+} {3 3}
do_test rowid-4.6 {
execsql {
SELECT t1.x FROM t1, t2
# This file implements regression tests for SQLite library. The
# focus of this file is testing the SELECT statement.
#
-# $Id: select2.test,v 1.14 2001/09/16 00:13:28 drh Exp $
+# $Id: select2.test,v 1.15 2001/11/08 00:45:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
execsql {SELECT f1 FROM tbl2 WHERE f2=1000}
} {500}
do_test select2-3.2d {
- execsql {SELECT fcnt() FROM tbl2 WHERE 1000=f2}
-} {1}
+ set sqlite_search_count 0
+ execsql {SELECT * FROM tbl2 WHERE 1000=f2}
+ set sqlite_search_count
+} {3}
do_test select2-3.2e {
- execsql {SELECT fcnt() FROM tbl2 WHERE f2=1000}
-} {1}
-
-# omit the time-dependent tests
-#
-do_probtest select2-3.2f {
- set t1 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}} 1] 0]
- set t2 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE f2=1000}} 1] 0]
- expr {$t1*0.7<$t2 && $t2*0.7<$t1}
-} {1}
+ set sqlite_search_count 0
+ execsql {SELECT * FROM tbl2 WHERE f2=1000}
+ set sqlite_search_count
+} {3}
# Make sure queries run faster with an index than without
#
-do_probtest select2-3.3 {
- set t1 [lindex [time {execsql {SELECT f1 from tbl2 WHERE f2==2000}} 1] 0]
+do_test select2-3.3 {
execsql {DROP INDEX idx1}
- set t2 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE f2==2000}} 1] 0]
- expr {$t1*10 < $t2}
-} {1}
-do_probtest select2-3.4 {
- expr {[execsql {SELECT fcnt() FROM tbl2 WHERE f2==2000}]>10}
-} {1}
+ set sqlite_search_count 0
+ execsql {SELECT f1 FROM tbl2 WHERE f2==2000}
+ set sqlite_search_count
+} {29999}
finish_test
# This file implements regression tests for SQLite library. The
# focus of this file is testing the use of indices in WHERE clases.
#
-# $Id: where.test,v 1.3 2001/09/16 00:13:28 drh Exp $
+# $Id: where.test,v 1.4 2001/11/08 00:45:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
}
} {}
-# Verify that queries use an index. We are using the special "fcnt(*)"
-# function to verify the results. fcnt(*) returns the number of Fetch
-# operations that have occurred up to the point where fcnt(*) is invoked.
-# By verifing that fcnt(*) returns a small number we know that an index
-# was used instead of an exhaustive search.
+# Do an SQL statement. Append the search count to the end of the result.
+#
+proc count sql {
+ set ::sqlite_search_count 0
+ return [concat [execsql $sql] $::sqlite_search_count]
+}
+
+# Verify that queries use an index. We are using the special variable
+# "sqlite_search_count" which tallys the number of executions of MoveTo
+# and Next operators in the VDBE. By verifing that the search count is
+# small we can be assured that indices are being used properly.
#
do_test where-1.1 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE w=10}
-} {3 121 1}
+ count {SELECT x, y FROM t1 WHERE w=10}
+} {3 121 3}
do_test where-1.2 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE w=11}
-} {3 144 1}
+ count {SELECT x, y FROM t1 WHERE w=11}
+} {3 144 3}
do_test where-1.3 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE 11=w}
-} {3 144 1}
+ count {SELECT x, y FROM t1 WHERE 11=w}
+} {3 144 3}
do_test where-1.4 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE 11=w AND x>2}
-} {3 144 1}
+ count {SELECT x, y FROM t1 WHERE 11=w AND x>2}
+} {3 144 3}
do_test where-1.5 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE y<200 AND w=11 AND x>2}
-} {3 144 1}
+ count {SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2}
+} {3 144 3}
do_test where-1.6 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE y<200 AND x>2 AND w=11}
-} {3 144 1}
+ count {SELECT x, y FROM t1 WHERE y<200 AND x>2 AND w=11}
+} {3 144 3}
do_test where-1.7 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE w=11 AND y<200 AND x>2}
-} {3 144 1}
+ count {SELECT x, y FROM t1 WHERE w=11 AND y<200 AND x>2}
+} {3 144 3}
do_test where-1.8 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE w>10 AND y=144 AND x=3}
-} {3 144 1}
+ count {SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3}
+} {3 144 3}
do_test where-1.9 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE y=144 AND w>10 AND x=3}
-} {3 144 1}
+ count {SELECT x, y FROM t1 WHERE y=144 AND w>10 AND x=3}
+} {3 144 3}
do_test where-1.10 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE x=3 AND w>=10 AND y=121}
-} {3 121 1}
+ count {SELECT x, y FROM t1 WHERE x=3 AND w>=10 AND y=121}
+} {3 121 3}
do_test where-1.11 {
- execsql {SELECT x, y, fcnt(*) FROM t1 WHERE x=3 AND y=100 AND w<10}
-} {3 100 1}
+ count {SELECT x, y FROM t1 WHERE x=3 AND y=100 AND w<10}
+} {3 100 3}
+
+# New for SQLite version 2.1: Verify that that inequality constraints
+# are used correctly.
+#
+do_test where-1.12 {
+ count {SELECT w FROM t1 WHERE x=3 AND y<100}
+} {8 3}
+do_test where-1.13 {
+ count {SELECT w FROM t1 WHERE x=3 AND 100>y}
+} {8 3}
+do_test where-1.14 {
+ count {SELECT w FROM t1 WHERE 3=x AND y<100}
+} {8 3}
+do_test where-1.15 {
+ count {SELECT w FROM t1 WHERE 3=x AND 100>y}
+} {8 3}
+do_test where-1.16 {
+ count {SELECT w FROM t1 WHERE x=3 AND y<=100}
+} {8 9 5}
+do_test where-1.17 {
+ count {SELECT w FROM t1 WHERE x=3 AND 100>=y}
+} {8 9 5}
+do_test where-1.18 {
+ count {SELECT w FROM t1 WHERE x=3 AND y>225}
+} {15 3}
+do_test where-1.19 {
+ count {SELECT w FROM t1 WHERE x=3 AND 225<y}
+} {15 3}
+do_test where-1.20 {
+ count {SELECT w FROM t1 WHERE x=3 AND y>=225}
+} {14 15 5}
+do_test where-1.21 {
+ count {SELECT w FROM t1 WHERE x=3 AND 225<=y}
+} {14 15 5}
+do_test where-1.22 {
+ count {SELECT w FROM t1 WHERE x=3 AND y>121 AND y<196}
+} {11 12 5}
+do_test where-1.23 {
+ count {SELECT w FROM t1 WHERE x=3 AND y>=121 AND y<=196}
+} {10 11 12 13 9}
+do_test where-1.24 {
+ count {SELECT w FROM t1 WHERE x=3 AND 121<y AND 196>y}
+} {11 12 5}
+do_test where-1.25 {
+ count {SELECT w FROM t1 WHERE x=3 AND 121<=y AND 196>=y}
+} {10 11 12 13 9}
+
+# Need to work on optimizing the BETWEEN operator.
+#
+# do_test where-1.26 {
+# count {SELECT w FROM t1 WHERE x=3 AND y BETWEEN 121 AND 196}
+# } {10 11 12 13 9}
+
+do_test where-1.27 {
+ count {SELECT w FROM t1 WHERE x=3 AND y+1==122}
+} {10 17}
+do_test where-1.28 {
+ count {SELECT w FROM t1 WHERE x+1=4 AND y+1==122}
+} {10 99}
+do_test where-1.29 {
+ count {SELECT w FROM t1 WHERE y==121}
+} {10 99}
+
+
+do_test where-1.30 {
+ count {SELECT w FROM t1 WHERE w>97}
+} {98 99 100 6}
+do_test where-1.31 {
+ count {SELECT w FROM t1 WHERE w>=97}
+} {97 98 99 100 8}
+do_test where-1.33 {
+ count {SELECT w FROM t1 WHERE w==97}
+} {97 3}
+do_test where-1.34 {
+ count {SELECT w FROM t1 WHERE w+1==98}
+} {97 99}
+do_test where-1.35 {
+ count {SELECT w FROM t1 WHERE w<3}
+} {1 2 4}
+do_test where-1.36 {
+ count {SELECT w FROM t1 WHERE w<=3}
+} {1 2 3 6}
+do_test where-1.37 {
+ count {SELECT w FROM t1 WHERE w+1<=4}
+} {1 2 3 99}
+
# Do the same kind of thing except use a join as the data source.
#
do_test where-2.1 {
- execsql {
- SELECT w, p, fcnt(*) FROM t2, t1
+ count {
+ SELECT w, p FROM t2, t1
WHERE x=q AND y=s AND r=8977
}
-} {34 67 2}
+} {34 67 6}
do_test where-2.2 {
- execsql {
- SELECT w, p, fcnt(*) FROM t2, t1
+ count {
+ SELECT w, p FROM t2, t1
WHERE x=q AND s=y AND r=8977
}
-} {34 67 2}
+} {34 67 6}
do_test where-2.3 {
- execsql {
- SELECT w, p, fcnt(*) FROM t2, t1
+ count {
+ SELECT w, p FROM t2, t1
WHERE x=q AND s=y AND r=8977 AND w>10
}
-} {34 67 2}
+} {34 67 6}
do_test where-2.4 {
- execsql {
- SELECT w, p, fcnt(*) FROM t2, t1
+ count {
+ SELECT w, p FROM t2, t1
WHERE p<80 AND x=q AND s=y AND r=8977 AND w>10
}
-} {34 67 2}
+} {34 67 6}
do_test where-2.5 {
- execsql {
- SELECT w, p, fcnt(*) FROM t2, t1
+ count {
+ SELECT w, p FROM t2, t1
WHERE p<80 AND x=q AND 8977=r AND s=y AND w>10
}
-} {34 67 2}
+} {34 67 6}
do_test where-2.6 {
- execsql {
- SELECT w, p, fcnt(*) FROM t2, t1
+ count {
+ SELECT w, p FROM t2, t1
WHERE x=q AND p=77 AND s=y AND w>5
}
-} {24 77 2}
+} {24 77 6}
do_test where-2.7 {
- execsql {
- SELECT w, p, fcnt(*) FROM t1, t2
+ count {
+ SELECT w, p FROM t1, t2
WHERE x=q AND p>77 AND s=y AND w=5
}
-} {5 96 2}
+} {5 96 6}
# Lets do a 3-way join.
#
do_test where-3.1 {
- execsql {
- SELECT A.w, B.p, C.w, fcnt(*) FROM t1 as A, t2 as B, t1 as C
+ count {
+ SELECT A.w, B.p, C.w FROM t1 as A, t2 as B, t1 as C
WHERE C.w=101-B.p AND B.r=10202-A.y AND A.w=11
}
-} {11 90 11 3}
+} {11 90 11 9}
do_test where-3.2 {
- execsql {
- SELECT A.w, B.p, C.w, fcnt(*) FROM t1 as A, t2 as B, t1 as C
+ count {
+ SELECT A.w, B.p, C.w FROM t1 as A, t2 as B, t1 as C
WHERE C.w=101-B.p AND B.r=10202-A.y AND A.w=12
}
-} {12 89 12 3}
+} {12 89 12 9}
do_test where-3.3 {
- execsql {
- SELECT A.w, B.p, C.w, fcnt(*) FROM t1 as A, t2 as B, t1 as C
+ count {
+ SELECT A.w, B.p, C.w FROM t1 as A, t2 as B, t1 as C
WHERE A.w=15 AND B.p=C.w AND B.r=10202-A.y
}
-} {15 86 86 3}
+} {15 86 86 9}
finish_test