1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-12 13:01:09 +03:00

Merge the latest changes from trunk: chiefly the outer/inner loop query

optimizer scoring enhancement and the INSTR() function.

FossilOrigin-Name: 2993ca20207f8dac02f58d01e31d68c84328356a
This commit is contained in:
drh
2012-11-10 01:27:59 +00:00
17 changed files with 733 additions and 77 deletions

View File

@@ -1,5 +1,5 @@
C Pull\sall\sthe\slatest\strunk\senhancements\sinto\sthe\ssessions\sbranch.
D 2012-10-30T21:03:48.529
C Merge\sthe\slatest\schanges\sfrom\strunk:\schiefly\sthe\souter/inner\sloop\squery\noptimizer\sscoring\senhancement\sand\sthe\sINSTR()\sfunction.
D 2012-11-10T01:27:59.154
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -142,10 +142,10 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 72a70dcfda75d3a1f81041ce4573e7afddcd8e4e
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 9bc9463952bdc9fc43111b1f9c83a0af9b8e2239
F src/expr.c 152ba793a8747061c0c332857d0e4d4fd52d4397
F src/expr.c 3b25a95f3d309403940ba4a3212f197b8b6251d5
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c c82a04e7a92bb728f9ab972b76590403283be2af
F src/func.c cbb90dc84b22eea25caf39528d342279e61b8898
F src/func.c 1755cafdb8f2a291681f1ea55e0215518ebd6e52
F src/global.c fb44b11e02e06c995e6ed6642509edd23599d584
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
@@ -172,9 +172,9 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c
F src/os.h 027491c77d2404c0a678bb3fb06286f331eb9b57
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c 603d020fe6c58047794cc72c05c7c8f4a82a0579
F src/os_unix.c f0753566e1125d8b2eef6dd080b48ed91a83d424
F src/os_win.c 43ec1285357e5d5d919cb0492eac775c58ad7d12
F src/pager.c ee59fef31673d5124413c5a801cfd9ef3e6766d3
F src/pager.c ed53fe75a269c1d67645fe079ea0f3f0ce6492d5
F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0
F src/parse.y f29df90bd3adc64b33114ab1de9fb7768fcf2099
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
@@ -188,12 +188,12 @@ F src/resolve.c 7b986a715ac281643309c29257bb58cfae7aa810
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 3a8baf4719f9723b4e0b43f2baa60692d0d921f8
F src/shell.c 24cd0aa74aff73ea08594629faead564c4c2a286
F src/sqlite.h.in d460ae07ecdd1c820272d9c217547c7b572cb4b7
F src/sqlite.h.in 6c9386f4be831a293bc7bac803f735e12a666ac1
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
F src/sqliteInt.h 205fa7fd18a7e6e0ed2ff9cfbccf36fb51304ee4
F src/sqliteInt.h b071b5d387b9d256b1dcd2d0240fe50a74dbb898
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 53463144deb5dfac0a66b3be4dd7844b8f8a4c98
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 289be7b639406314813219ee7bc043d21f36ab12
F src/test1.c 936afc02766403e5debca49a1817a780e116df7e
@@ -227,7 +227,7 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25
F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
F src/test_quota.c e5fdb7d28e5afae1b619922804e544db0041ec81
F src/test_quota.c 0e0e2e3bf6766b101ecccd8c042b66e44e9be8f5
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
@@ -261,10 +261,10 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
F src/where.c 6a753aa008de6494e64dd265a27afbb0ad80ccf5
F src/where.c 832e33fefbe5ba751c1f5a06e63de98be95e56f2
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 52fc8dee494092031a556911d404ca30a749a30b
F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748
@@ -556,6 +556,7 @@ F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
F test/insert4.test 87f6798f31d60c4e177622fcc3663367e6ecbd90
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
F test/instr.test a34e1d46a9eefb098a7167ef0e730a4a3d82fba0
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1
F test/intpkey.test 7af30f6ae852d8d1c2b70e4bf1551946742e92d8
@@ -647,10 +648,10 @@ F test/notify3.test a86259abbfb923aa27d30f0fc038c88e5251488a
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
F test/null.test a8b09b8ed87852742343b33441a9240022108993
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
F test/orderby1.test ef4f7c40df81b9a4303a718433d34052f07db47d
F test/orderby1.test f33968647da5c546528fe4d2bf86c6a6a2e5a7ae
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
F test/pager1.test 07116f72a61960b882952e7472cc2846d161d6e2
F test/pager1.test f4c57e14583da2183fe31555c67fb32feda96092
F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442
@@ -986,6 +987,8 @@ F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5
F test/whereD.test 3f3ee93825c94804f1fc91eef2de0d365981759a
F test/whereE.test 7bd34945797efef15819368479bacc34215e4e1d
F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
@@ -1034,7 +1037,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P 76767d651fe733614b1719aef9ad5ed4568234e4 9dca18f5fea84afbecb314ee1cdfb98430656af3
R 44966c032a1121fa311efd7f4c01d9a9
P fce667f2d93a4ba65ccf1e748469576a3cd7ffcc 5a3b07f0f5dfae7eea870303f52f37d6a17f1da2
R 2cae8c229d6424df7351cab19781b1e6
U drh
Z f9e45ab7bfa5d5b4a8fa6d0808ba86fd
Z 883d57cdfacddb67b9acee024d2c5aac

View File

@@ -1 +1 @@
fce667f2d93a4ba65ccf1e748469576a3cd7ffcc
2993ca20207f8dac02f58d01e31d68c84328356a

View File

@@ -4030,8 +4030,10 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
ExprSetIrreducible(pExpr);
pExpr->iAgg = (i16)i;
pExpr->pAggInfo = pAggInfo;
}
return WRC_Prune;
}else{
return WRC_Continue;
}
}
}
return WRC_Continue;
@@ -4043,9 +4045,10 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
}
/*
** Analyze the given expression looking for aggregate functions and
** for variables that need to be added to the pParse->aAgg[] array.
** Make additional entries to the pParse->aAgg[] array as necessary.
** Analyze the pExpr expression looking for aggregate functions and
** for variables that need to be added to AggInfo object that pNC->pAggInfo
** points to. Additional entries are made on the AggInfo object as
** necessary.
**
** This routine should only be called after the expression has been
** analyzed by sqlite3ResolveExprNames().

View File

@@ -168,6 +168,55 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
/*
** Implementation of the instr() function.
**
** instr(haystack,needle) finds the first occurrence of needle
** in haystack and returns the number of previous characters plus 1,
** or 0 if needle does not occur within haystack.
**
** If both haystack and needle are BLOBs, then the result is one more than
** the number of bytes in haystack prior to the first occurrence of needle,
** or 0 if needle never occurs in haystack.
*/
static void instrFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const unsigned char *zHaystack;
const unsigned char *zNeedle;
int nHaystack;
int nNeedle;
int typeHaystack, typeNeedle;
int N = 1;
int isText;
typeHaystack = sqlite3_value_type(argv[0]);
typeNeedle = sqlite3_value_type(argv[1]);
if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
nHaystack = sqlite3_value_bytes(argv[0]);
nNeedle = sqlite3_value_bytes(argv[1]);
if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
zHaystack = sqlite3_value_blob(argv[0]);
zNeedle = sqlite3_value_blob(argv[1]);
isText = 0;
}else{
zHaystack = sqlite3_value_text(argv[0]);
zNeedle = sqlite3_value_text(argv[1]);
isText = 1;
}
while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
N++;
do{
nHaystack--;
zHaystack++;
}while( isText && (zHaystack[0]&0xc0)==0x80 );
}
if( nNeedle>nHaystack ) N = 0;
sqlite3_result_int(context, N);
}
/*
** Implementation of the substr() function.
**
@@ -1536,6 +1585,7 @@ void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),

View File

@@ -5374,8 +5374,13 @@ static int unixDelete(
int rc = SQLITE_OK;
UNUSED_PARAMETER(NotUsed);
SimulateIOError(return SQLITE_IOERR_DELETE);
if( osUnlink(zPath)==(-1) && errno!=ENOENT ){
return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
if( osUnlink(zPath)==(-1) ){
if( errno==ENOENT ){
rc = SQLITE_IOERR_DELETE_NOENT;
}else{
rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
}
return rc;
}
#ifndef SQLITE_DISABLE_DIRSYNC
if( (dirSync & 1)!=0 ){

View File

@@ -3159,6 +3159,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
if( rc ) return rc;
if( nPage==0 ){
rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
isWal = 0;
}else{
rc = sqlite3OsAccess(

View File

@@ -469,6 +469,7 @@ int sqlite3_exec(
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))

View File

@@ -1975,6 +1975,7 @@ struct WhereLevel {
} in; /* Used when plan.wsFlags&WHERE_IN_ABLE */
Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
} u;
double rOptCost; /* "Optimal" cost for this level */
/* The following field is really not part of the current level. But
** we need a place to cache virtual table index information for each

View File

@@ -209,6 +209,7 @@ int sqlite3_db_status(
db->pnBytesFreed = &nByte;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
sqlite3VdbeClearObject(db, pVdbe);
sqlite3DbFree(db, pVdbe);
}
db->pnBytesFreed = 0;

View File

@@ -1179,7 +1179,13 @@ int sqlite3_quota_ftruncate(quota_FILE *p, sqlite3_int64 szNew){
rc = ftruncate(fileno(p->f), szNew);
#endif
#if SQLITE_OS_WIN
# if defined(__MINGW32__) && defined(SQLITE_TEST)
/* _chsize_s() is missing from MingW (as of 2012-11-06). Use
** _chsize() as a work-around for testing purposes. */
rc = _chsize(_fileno(p->f), (long)szNew);
# else
rc = _chsize_s(_fileno(p->f), szNew);
# endif
#endif
if( pFile && rc==0 ){
quotaGroup *pGroup = pFile->pGroup;

View File

@@ -5102,6 +5102,19 @@ WhereInfo *sqlite3WhereBegin(
if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
notIndexed |= m;
}
if( isOptimal ){
pWInfo->a[j].rOptCost = sWBI.cost.rCost;
}else if( iFrom<nTabList-1 ){
/* If two or more tables have nearly the same outer loop cost,
** very different inner loop (optimal) cost, we want to choose
** for the outer loop that table which benefits the least from
** being in the inner loop. The following code scales the
** outer loop cost estimate to accomplish that. */
WHERETRACE((" scaling cost from %.1f to %.1f\n",
sWBI.cost.rCost,
sWBI.cost.rCost/pWInfo->a[j].rOptCost));
sWBI.cost.rCost /= pWInfo->a[j].rOptCost;
}
/* Conditions under which this table becomes the best so far:
**
@@ -5109,8 +5122,8 @@ WhereInfo *sqlite3WhereBegin(
** yet run. (In other words, it must not depend on tables
** in inner loops.)
**
** (2) A full-table-scan plan cannot supercede indexed plan unless
** the full-table-scan is an "optimal" plan as defined above.
** (2) (This rule was removed on 2012-11-09. The scaling of the
** cost using the optimal scan cost made this rule obsolete.)
**
** (3) All tables have an INDEXED BY clause or this table lacks an
** INDEXED BY clause or this table uses the specific
@@ -5125,9 +5138,6 @@ WhereInfo *sqlite3WhereBegin(
** is defined by the compareCost() function above.
*/
if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */
&& (bestJ<0 || (notIndexed&m)!=0 /* (2) */
|| (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
|| (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
&& (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */
|| NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
&& (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */

View File

@@ -68,4 +68,164 @@ do_test aggnested-2.0 {
} {A,B,B 3 33 333 3333}
db2 close
##################### Test cases for ticket [bfbf38e5e9956ac69f] ############
#
# This first test case is the original problem report:
do_test aggnested-3.0 {
db eval {
CREATE TABLE AAA (
aaa_id INTEGER PRIMARY KEY AUTOINCREMENT
);
CREATE TABLE RRR (
rrr_id INTEGER PRIMARY KEY AUTOINCREMENT,
rrr_date INTEGER NOT NULL,
rrr_aaa INTEGER
);
CREATE TABLE TTT (
ttt_id INTEGER PRIMARY KEY AUTOINCREMENT,
target_aaa INTEGER NOT NULL,
source_aaa INTEGER NOT NULL
);
insert into AAA (aaa_id) values (2);
insert into TTT (ttt_id, target_aaa, source_aaa)
values (4469, 2, 2);
insert into TTT (ttt_id, target_aaa, source_aaa)
values (4476, 2, 1);
insert into RRR (rrr_id, rrr_date, rrr_aaa)
values (0, 0, NULL);
insert into RRR (rrr_id, rrr_date, rrr_aaa)
values (2, 4312, 2);
SELECT i.aaa_id,
(SELECT sum(CASE WHEN (t.source_aaa == i.aaa_id) THEN 1 ELSE 0 END)
FROM TTT t
) AS segfault
FROM
(SELECT curr.rrr_aaa as aaa_id
FROM RRR curr
-- you also can comment out the next line
-- it causes segfault to happen after one row is outputted
INNER JOIN AAA a ON (curr.rrr_aaa = aaa_id)
LEFT JOIN RRR r ON (r.rrr_id <> 0 AND r.rrr_date < curr.rrr_date)
GROUP BY curr.rrr_id
HAVING r.rrr_date IS NULL
) i;
}
} {2 1}
# Further variants of the test case, as found in the ticket
#
do_test aggnested-3.1 {
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1 (
id1 INTEGER PRIMARY KEY AUTOINCREMENT,
value1 INTEGER
);
INSERT INTO t1 VALUES(4469,2),(4476,1);
CREATE TABLE t2 (
id2 INTEGER PRIMARY KEY AUTOINCREMENT,
value2 INTEGER
);
INSERT INTO t2 VALUES(0,1),(2,2);
SELECT
(SELECT sum(value2==xyz) FROM t2)
FROM
(SELECT curr.value1 as xyz
FROM t1 AS curr LEFT JOIN t1 AS other
GROUP BY curr.id1);
}
} {1 1}
do_test aggnested-3.2 {
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1 (
id1 INTEGER,
value1 INTEGER,
x1 INTEGER
);
INSERT INTO t1 VALUES(4469,2,98),(4469,1,99),(4469,3,97);
CREATE TABLE t2 (
value2 INTEGER
);
INSERT INTO t2 VALUES(1);
SELECT
(SELECT sum(value2==xyz) FROM t2)
FROM
(SELECT value1 as xyz, max(x1) AS pqr
FROM t1
GROUP BY id1);
}
} {0}
do_test aggnested-3.3 {
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1(id1, value1);
INSERT INTO t1 VALUES(4469,2),(4469,1);
CREATE TABLE t2 (value2);
INSERT INTO t2 VALUES(1);
SELECT (SELECT sum(value2=value1) FROM t2), max(value1)
FROM t1
GROUP BY id1;
}
} {0 2}
# A batch of queries all doing approximately the same operation involving
# two nested aggregate queries.
#
do_test aggnested-3.11 {
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1(id1, value1);
INSERT INTO t1 VALUES(4469,12),(4469,11),(4470,34);
CREATE INDEX t1id1 ON t1(id1);
CREATE TABLE t2 (value2);
INSERT INTO t2 VALUES(12),(34),(34);
INSERT INTO t2 SELECT value2 FROM t2;
SELECT max(value1), (SELECT count(*) FROM t2 WHERE value2=max(value1))
FROM t1
GROUP BY id1;
}
} {12 2 34 4}
do_test aggnested-3.12 {
db eval {
SELECT max(value1), (SELECT count(*) FROM t2 WHERE value2=value1)
FROM t1
GROUP BY id1;
}
} {12 2 34 4}
do_test aggnested-3.13 {
db eval {
SELECT value1, (SELECT sum(value2=value1) FROM t2)
FROM t1;
}
} {12 2 11 0 34 4}
do_test aggnested-3.14 {
db eval {
SELECT value1, (SELECT sum(value2=value1) FROM t2)
FROM t1
WHERE value1 IN (SELECT max(value1) FROM t1 GROUP BY id1);
}
} {12 2 34 4}
do_test aggnested-3.15 {
# FIXME: If case 3.16 works, then this case really ought to work too...
catchsql {
SELECT max(value1), (SELECT sum(value2=max(value1)) FROM t2)
FROM t1
GROUP BY id1;
}
} {1 {misuse of aggregate function max()}}
do_test aggnested-3.16 {
db eval {
SELECT max(value1), (SELECT sum(value2=value1) FROM t2)
FROM t1
GROUP BY id1;
}
} {12 2 34 4}
finish_test

210
test/instr.test Normal file
View File

@@ -0,0 +1,210 @@
# 2012 October 24
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing the built-in INSTR() functions.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a table to work with.
#
do_test instr-1.1 {
db eval {SELECT instr('abcdefg','a');}
} {1}
do_test instr-1.2 {
db eval {SELECT instr('abcdefg','b');}
} {2}
do_test instr-1.3 {
db eval {SELECT instr('abcdefg','c');}
} {3}
do_test instr-1.4 {
db eval {SELECT instr('abcdefg','d');}
} {4}
do_test instr-1.5 {
db eval {SELECT instr('abcdefg','e');}
} {5}
do_test instr-1.6 {
db eval {SELECT instr('abcdefg','f');}
} {6}
do_test instr-1.7 {
db eval {SELECT instr('abcdefg','g');}
} {7}
do_test instr-1.8 {
db eval {SELECT instr('abcdefg','h');}
} {0}
do_test instr-1.9 {
db eval {SELECT instr('abcdefg','abcdefg');}
} {1}
do_test instr-1.10 {
db eval {SELECT instr('abcdefg','abcdefgh');}
} {0}
do_test instr-1.11 {
db eval {SELECT instr('abcdefg','bcdefg');}
} {2}
do_test instr-1.12 {
db eval {SELECT instr('abcdefg','bcdefgh');}
} {0}
do_test instr-1.13 {
db eval {SELECT instr('abcdefg','cdefg');}
} {3}
do_test instr-1.14 {
db eval {SELECT instr('abcdefg','cdefgh');}
} {0}
do_test instr-1.15 {
db eval {SELECT instr('abcdefg','defg');}
} {4}
do_test instr-1.16 {
db eval {SELECT instr('abcdefg','defgh');}
} {0}
do_test instr-1.17 {
db eval {SELECT instr('abcdefg','efg');}
} {5}
do_test instr-1.18 {
db eval {SELECT instr('abcdefg','efgh');}
} {0}
do_test instr-1.19 {
db eval {SELECT instr('abcdefg','fg');}
} {6}
do_test instr-1.20 {
db eval {SELECT instr('abcdefg','fgh');}
} {0}
do_test instr-1.21 {
db eval {SELECT coalesce(instr('abcdefg',NULL),'nil');}
} {nil}
do_test instr-1.22 {
db eval {SELECT coalesce(instr(NULL,'x'),'nil');}
} {nil}
do_test instr-1.23 {
db eval {SELECT instr(12345,34);}
} {3}
do_test instr-1.24 {
db eval {SELECT instr(123456.78,34);}
} {3}
do_test instr-1.25 {
db eval {SELECT instr(123456.78,x'3334');}
} {3}
do_test instr-1.26 {
db eval {SELECT instr('äbcdefg','efg');}
} {5}
do_test instr-1.27 {
db eval {SELECT instr('€xyzzy','xyz');}
} {2}
do_test instr-1.28 {
db eval {SELECT instr('abc€xyzzy','xyz');}
} {5}
do_test instr-1.29 {
db eval {SELECT instr('abc€xyzzy','€xyz');}
} {4}
do_test instr-1.30 {
db eval {SELECT instr('abc€xyzzy','c€xyz');}
} {3}
do_test instr-1.31 {
db eval {SELECT instr(x'0102030405',x'01');}
} {1}
do_test instr-1.32 {
db eval {SELECT instr(x'0102030405',x'02');}
} {2}
do_test instr-1.33 {
db eval {SELECT instr(x'0102030405',x'03');}
} {3}
do_test instr-1.34 {
db eval {SELECT instr(x'0102030405',x'04');}
} {4}
do_test instr-1.35 {
db eval {SELECT instr(x'0102030405',x'05');}
} {5}
do_test instr-1.36 {
db eval {SELECT instr(x'0102030405',x'06');}
} {0}
do_test instr-1.37 {
db eval {SELECT instr(x'0102030405',x'0102030405');}
} {1}
do_test instr-1.38 {
db eval {SELECT instr(x'0102030405',x'02030405');}
} {2}
do_test instr-1.39 {
db eval {SELECT instr(x'0102030405',x'030405');}
} {3}
do_test instr-1.40 {
db eval {SELECT instr(x'0102030405',x'0405');}
} {4}
do_test instr-1.41 {
db eval {SELECT instr(x'0102030405',x'0506');}
} {0}
do_test instr-1.42 {
db eval {SELECT instr(x'0102030405',x'');}
} {1}
do_test instr-1.43 {
db eval {SELECT instr(x'',x'');}
} {1}
do_test instr-1.44 {
db eval {SELECT instr('','');}
} {1}
do_test instr-1.45 {
db eval {SELECT instr('abcdefg','');}
} {1}
unset -nocomplain longstr
set longstr abcdefghijklmonpqrstuvwxyz
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
append longstr $longstr
# puts [string length $longstr]
append longstr Xabcde
do_test instr-1.46 {
db eval {SELECT instr($longstr,'X');}
} {106497}
do_test instr-1.47 {
db eval {SELECT instr($longstr,'Y');}
} {0}
do_test instr-1.48 {
db eval {SELECT instr($longstr,'Xa');}
} {106497}
do_test instr-1.49 {
db eval {SELECT instr($longstr,'zXa');}
} {106496}
set longstr [string map {a ä} $longstr]
do_test instr-1.50 {
db eval {SELECT instr($longstr,'X');}
} {106497}
do_test instr-1.51 {
db eval {SELECT instr($longstr,'Y');}
} {0}
do_test instr-1.52 {
db eval {SELECT instr($longstr,'Xä');}
} {106497}
do_test instr-1.53 {
db eval {SELECT instr($longstr,'zXä');}
} {106496}
do_test instr-1.54 {
db eval {SELECT instr(x'78c3a4e282ac79','x');}
} {1}
do_test instr-1.55 {
db eval {SELECT instr(x'78c3a4e282ac79','y');}
} {4}
do_test instr-1.56 {
db eval {SELECT instr(x'78c3a4e282ac79',x'79');}
} {7}
do_test instr-1.57 {
db eval {SELECT instr('xä€y',x'79');}
} {4}
finish_test

View File

@@ -48,7 +48,7 @@ do_test 1.0 {
} {}
do_test 1.1a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {one-a one-c two-a two-b three-a three-c}
@@ -57,7 +57,7 @@ do_test 1.1a {
do_test 1.1b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {~/ORDER BY/} ;# ORDER BY optimized out
@@ -66,7 +66,7 @@ do_test 1.1b {
#
do_test 1.2a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
}
} {one-a one-c two-a two-b three-a three-c}
@@ -75,7 +75,7 @@ do_test 1.2a {
do_test 1.2b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
}
} {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms
@@ -85,13 +85,13 @@ do_test 1.3a {
optimization_control db order-by-idx-join 0
db cache flush
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {one-a one-c two-a two-b three-a three-c}
do_test 1.3b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {/ORDER BY/} ;# separate sorting pass due to disabled optimization
optimization_control db all 1
@@ -101,53 +101,53 @@ db cache flush
#
do_test 1.4a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
}
} {three-a three-c two-a two-b one-a one-c}
do_test 1.4b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn
}
} {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting
do_test 1.4c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
}
} {~/ORDER BY/} ;# optimized out
do_test 1.5a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
}
} {one-c one-a two-b two-a three-c three-a}
do_test 1.5b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC
}
} {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting
do_test 1.5c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
}
} {~/ORDER BY/} ;# optimized out
do_test 1.6a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
}
} {three-c three-a two-b two-a one-c one-a}
do_test 1.6b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
}
} {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting
do_test 1.6c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
}
} {~/ORDER BY/} ;# ORDER BY optimized-out
@@ -183,7 +183,7 @@ do_test 2.0 {
} {}
do_test 2.1a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {one-a one-c two-a two-b three-a three-c}
@@ -192,19 +192,19 @@ do_test 2.1a {
do_test 2.1b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {~/ORDER BY/} ;# ORDER BY optimized out
do_test 2.1c {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn
}
} {one-a one-c two-a two-b three-a three-c}
do_test 2.1d {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn
}
} {~/ORDER BY/} ;# ORDER BY optimized out
@@ -213,7 +213,7 @@ do_test 2.1d {
#
do_test 2.2a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
}
} {one-a one-c two-a two-b three-a three-c}
@@ -222,7 +222,7 @@ do_test 2.2a {
do_test 2.2b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
}
} {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms
@@ -232,13 +232,13 @@ do_test 2.3a {
optimization_control db order-by-idx-join 0
db cache flush
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {one-a one-c two-a two-b three-a three-c}
do_test 2.3b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {/ORDER BY/} ;# separate sorting pass due to disabled optimization
optimization_control db all 1
@@ -248,53 +248,53 @@ db cache flush
#
do_test 2.4a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
}
} {three-a three-c two-a two-b one-a one-c}
do_test 2.4b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn
}
} {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting
do_test 2.4c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
}
} {~/ORDER BY/} ;# optimized out
do_test 2.5a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
}
} {one-c one-a two-b two-a three-c three-a}
do_test 2.5b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC
}
} {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting
do_test 2.5c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
}
} {~/ORDER BY/} ;# optimized out
do_test 2.6a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
}
} {three-c three-a two-b two-a one-c one-a}
do_test 2.6b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
}
} {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting
do_test 2.6c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
}
} {~/ORDER BY/} ;# ORDER BY optimized out
@@ -330,7 +330,7 @@ do_test 3.0 {
} {}
do_test 3.1a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
}
} {one-c one-a two-b two-a three-c three-a}
@@ -339,7 +339,7 @@ do_test 3.1a {
do_test 3.1b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
}
} {~/ORDER BY/} ;# ORDER BY optimized out
@@ -348,7 +348,7 @@ do_test 3.1b {
#
do_test 3.2a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC
}
} {one-c one-a two-b two-a three-c three-a}
@@ -357,7 +357,7 @@ do_test 3.2a {
do_test 3.2b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC
}
} {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms
@@ -367,13 +367,13 @@ do_test 3.3a {
optimization_control db order-by-idx-join 0
db cache flush
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
}
} {one-c one-a two-b two-a three-c three-a}
do_test 3.3b {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
}
} {/ORDER BY/} ;# separate sorting pass due to disabled optimization
optimization_control db all 1
@@ -383,54 +383,54 @@ db cache flush
#
do_test 3.4a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {one-a one-c two-a two-b three-a three-c}
do_test 3.4b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
}
} {one-a one-c two-a two-b three-a three-c} ;# verify same order after sorting
do_test 3.4c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
}
} {~/ORDER BY/} ;# optimized out
do_test 3.5a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
}
} {three-c three-a two-b two-a one-c one-a}
do_test 3.5b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
}
} {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting
do_test 3.5c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
}
} {~/ORDER BY/} ;# optimzed out
do_test 3.6a {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
}
} {three-a three-c two-a two-b one-a one-c}
do_test 3.6b {
db eval {
SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn
}
} {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting
do_test 3.6c {
db eval {
EXPLAIN QUERY PLAN
SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
}
} {~/ORDER BY/} ;# inverted ASC/DESC is optimized out

View File

@@ -2487,4 +2487,32 @@ do_test pager1-32.1 {
# Cleanup 20MB file left by the previous test.
forcedelete test.db
#-------------------------------------------------------------------------
# Test that if a transaction is committed in journal_mode=DELETE mode,
# and the call to unlink() returns an ENOENT error, the COMMIT does not
# succeed.
#
if {$::tcl_platform(platform)=="unix"} {
do_test pager1-33.1 {
sqlite3 db test.db
execsql {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('one');
INSERT INTO t1 VALUES('two');
BEGIN;
INSERT INTO t1 VALUES('three');
INSERT INTO t1 VALUES('four');
}
forcedelete bak-journal
file rename test.db-journal bak-journal
catchsql COMMIT
} {1 {disk I/O error}}
do_test pager1-33.2 {
file rename bak-journal test.db-journal
execsql { SELECT * FROM t1 }
} {one two}
}
finish_test

62
test/whereE.test Normal file
View File

@@ -0,0 +1,62 @@
# 2012 November 9
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing the query planner to make sure it
# is making good planning decisions.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix whereE
do_execsql_test 1.1 {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(1,10), (2,20), (3,30), (2,22), (3, 33);
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
ALTER TABLE t1 ADD COLUMN c;
UPDATE t1 SET c=a*rowid+10000;
CREATE INDEX t1ab ON t1(a,b);
CREATE TABLE t2(x,y);
INSERT INTO t2 VALUES(4,44),(5,55),(6,66),(7,77);
INSERT INTO t2 SELECT x+4, (x+4)*11 FROM t2;
INSERT INTO t2 SELECT x+8, (x+8)*11 FROM t2;
INSERT INTO t2 SELECT x+16, (x+16)*11 FROM t2;
INSERT INTO t2 SELECT x+32, (x+32)*11 FROM t2;
INSERT INTO t2 SELECT x+64, (x+32)*11 FROM t2;
ALTER TABLE t2 ADD COLUMN z;
UPDATE t2 SET z=2;
CREATE UNIQUE INDEX t2zx ON t2(z,x);
EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x;
} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/}
do_execsql_test 1.2 {
EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x;
} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/}
do_execsql_test 1.3 {
ANALYZE;
EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x;
} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/}
do_execsql_test 1.4 {
EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x;
} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/}
finish_test

115
test/whereF.test Normal file
View File

@@ -0,0 +1,115 @@
# 2012 November 9
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Test cases for query planning decisions.
#
# The tests in this file demonstrate the behaviour of the query planner
# in determining the order in which joined tables are scanned.
#
# Assume there are two tables being joined - t1 and t2. Each has a cost
# if it is the outer loop, and a cost if it is the inner loop. As follows:
#
# t1(outer) - cost of scanning t1 as the outer loop.
# t1(inner) - cost of scanning t1 as the inner loop.
# t2(outer) - cost of scanning t2 as the outer loop.
# t2(inner) - cost of scanning t2 as the inner loop.
#
# Depending on the order in which the planner nests the scans, the total
# cost of the join query is one of:
#
# t1(outer) * t2(inner)
# t2(outer) * t1(inner)
#
# The tests in this file attempt to verify that the planner nests joins in
# the correct order when the following are true:
#
# + (t1(outer) * t2(inner)) > (t1(inner) * t2(outer)
# + t1(outer) < t2(outer)
#
# In other words, when the best overall query plan has t2 as the outer loop,
# but when the outer loop is considered independent of the inner, t1 is the
# most efficient choice.
#
# In order to make them more predictable, automatic indexes are turned off for
# the tests in this file.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix x
do_execsql_test 1.0 {
PRAGMA automatic_index = 0;
CREATE TABLE t1(a, b, c);
CREATE TABLE t2(d, e, f);
CREATE UNIQUE INDEX i1 ON t1(a);
CREATE UNIQUE INDEX i2 ON t2(d);
} {}
foreach {tn sql} {
1 "SELECT * FROM t1, t2 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10"
2 "SELECT * FROM t2, t1 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10"
3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10"
} {
do_test 1.$tn {
db eval "EXPLAIN QUERY PLAN $sql"
} {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/}
}
do_execsql_test 2.0 {
DROP TABLE t1;
DROP TABLE t2;
CREATE TABLE t1(a, b, c);
CREATE TABLE t2(d, e, f);
CREATE UNIQUE INDEX i1 ON t1(a);
CREATE UNIQUE INDEX i2 ON t1(b);
CREATE UNIQUE INDEX i3 ON t2(d);
} {}
foreach {tn sql} {
1 "SELECT * FROM t1, t2 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e"
2 "SELECT * FROM t2, t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e"
3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e"
} {
do_test 2.$tn {
db eval "EXPLAIN QUERY PLAN $sql"
} {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/}
}
do_execsql_test 3.0 {
DROP TABLE t1;
DROP TABLE t2;
CREATE TABLE t1(a, b, c);
CREATE TABLE t2(d, e, f);
CREATE UNIQUE INDEX i1 ON t1(a, b);
CREATE INDEX i2 ON t2(d);
} {}
foreach {tn sql} {
1 {SELECT t1.a, t1.b, t2.d, t2.e FROM t1, t2
WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)}
2 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2, t1
WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)}
3 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2 CROSS JOIN t1
WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)}
} {
do_test 3.$tn {
db eval "EXPLAIN QUERY PLAN $sql"
} {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/}
}
finish_test