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

Merge the accidental fork.

FossilOrigin-Name: 86a06dd0494c2fe83d4fde517557600956cedd9e
This commit is contained in:
drh
2009-08-13 15:42:52 +00:00
8 changed files with 371 additions and 330 deletions

View File

@@ -1,8 +1,8 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Fix\sa\stypo\son\sa\scomment\sin\ssqlite3VdbeIntegerAffinity().
D 2009-08-13T15:13:53
C Merge\sthe\saccidental\sfork.
D 2009-08-13T15:42:52
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in c606c9b502dfde3b9c3b2d23ed49f3737829693b
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -149,7 +149,7 @@ F src/os.h fa3f4aa0119ff721a2da4b47ffd74406ac864c05
F src/os_common.h 8c61457df58f1a4bd5f5adc3e90e01b37bf7afbc
F src/os_os2.c bed77dc26e3a95ce4a204936b9a1ca6fe612fcc5
F src/os_unix.c cdb2a08b9ce4aa13b3f7b91d4dd60fb48be9f56a
F src/os_win.c 79bb3c59d60bc6faadd379cf036c132fa545d7d6
F src/os_win.c 6de69d8f51d4bf35484e9be1588089a61569491f
F src/pager.c a47be286477ed6c7b9a342dd53d4e4043f29d8c2
F src/pager.h 11852d044c86cf5a9d6e34171fb0c4fcf1f6265f
F src/parse.y 6c42631e72a3d14cde2bee85e79409066066d3df
@@ -166,7 +166,7 @@ F src/select.c 67b0778c9585905c8aa75aaa469e76ef3c1d315a
F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
F src/sqlite.h.in eb42257503a48f6f12ff0b23a81067ba9b5ac1eb
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
F src/sqliteInt.h 1840be421126be4e0027cc5b144bc82659ff781f
F src/sqliteInt.h 6337542c0eb0e6521991b29f59c8bcbdfda222e7
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
@@ -216,7 +216,7 @@ F src/vdbeblob.c a3f3e0e877fc64ea50165eec2855f5ada4477611
F src/vdbemem.c 364cfce843926224f917ab89ee476be958c864ed
F src/vtab.c aedd76e8670d5a5379f93804398d3ba960125547
F src/walker.c 1edca756275f158b80f20eb6f104c8d3fcc96a04
F src/where.c 7e696d69a6d1b0fa277da2801ae4126dd4db0f8c
F src/where.c 53adef2c7b8bc888755cf41fb3449aedb36a429c
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
@@ -677,7 +677,7 @@ F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
F test/trigger7.test 72feaf8dbc52cea84de0c3e6ce7559ff19c479af
F test/trigger8.test 83d92c212f36442d26527d6f7701575905a52ae1
F test/trigger9.test e6e8dbab673666b3c0a63f0fefcff2329fe6bba8
F test/triggerA.test 208dbda4d2f7c918b02f8a0dfa3acd2a0fe00691
F test/triggerA.test 0718ad2d9bfef27c7af00e636df79bee6b988da7
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
@@ -696,7 +696,7 @@ F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
F test/vtab5.test a0a84a89c622f4e2e816ebf39883dc319b4a1024
F test/vtab6.test 226b116d63ad77f9b084d556f772c45a0d28e9b5
F test/vtab6.test c7f290d172609d636fbfc58166eadcb55d5c117c
F test/vtab7.test a8c3c3cb3eb60be364991bd714e4927e26c4cd85
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
@@ -714,7 +714,7 @@ F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 42c4373595f4409d9c6a9987b4a60000ad664faf
F test/where7.test b6e84b472a024e45c6dbdadc52bbcab3fcc8d0e1
F test/where8.test fb2ccd7f1fa33287fef25b6bad6849c868a6e331
F test/where8.test 8d3704d04a683e792d373005f2e4e13bfd7e2dd5
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
F test/where9.test be19e1a92f80985c1a121b4678bf7d2123eaa623
F test/whereA.test 1d1674254614147c866ab9b59af6582f454a858c
@@ -745,14 +745,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
P 7f4810747b0864981f27edbd504bfab2efea1e3c
R 655d909830158c1e4c23bcea01aa6d6f
P b5a709d3609d40a6e5ef77f9889077d7395d3d26 19f799b32f9d1be25d4185ce18b13f4dd502e199
R ab41ee398e311449a6447494098a83fa
U drh
Z 17d73766b926eb2f8f7cfafceb82ffbd
Z b589a26f62eacda54d72d773c2f21084
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFKhC20oxKgR168RlERAoiwAJ42KYNrKXAZVoTeDiGDP3EWje6GjACgji6w
f06QEcTTR62jhYQgo4FrOOo=
=xxUY
iD8DBQFKhDR/oxKgR168RlERApwTAJ9tk5whkfe/L35NGftqAQgymtHvzgCeItIr
T+WsDYk3Sl3YexQvu3qmYi8=
=kIse
-----END PGP SIGNATURE-----

View File

@@ -1 +1 @@
b5a709d3609d40a6e5ef77f9889077d7395d3d26
86a06dd0494c2fe83d4fde517557600956cedd9e

View File

@@ -309,8 +309,8 @@ struct tm *__cdecl localtime(const time_t *t)
sqlite3_int64 t64;
t64 = *t;
t64 = (t64 + 11644473600)*10000000;
uTm.dwLowDateTime = t64 & 0xFFFFFFFF;
uTm.dwHighDateTime= t64 >> 32;
uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
uTm.dwHighDateTime= (DWORD)(t64 >> 32);
FileTimeToLocalFileTime(&uTm,&lTm);
FileTimeToSystemTime(&lTm,&pTm);
y.tm_year = pTm.wYear - 1900;
@@ -330,7 +330,7 @@ struct tm *__cdecl localtime(const time_t *t)
#define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e)
#define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f)
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-offsetof(winFile,h)]
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
/*
** Acquire a lock on the handle h
@@ -469,6 +469,9 @@ static BOOL winceLockFile(
winFile *pFile = HANDLE_TO_WINFILE(phFile);
BOOL bReturn = FALSE;
UNUSED_PARAMETER(dwFileOffsetHigh);
UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
if (!pFile->hMutex) return TRUE;
winceMutexAcquire(pFile->hMutex);
@@ -530,14 +533,17 @@ static BOOL winceUnlockFile(
winFile *pFile = HANDLE_TO_WINFILE(phFile);
BOOL bReturn = FALSE;
UNUSED_PARAMETER(dwFileOffsetHigh);
UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
if (!pFile->hMutex) return TRUE;
winceMutexAcquire(pFile->hMutex);
/* Releasing a reader lock or an exclusive lock */
if (dwFileOffsetLow >= SHARED_FIRST &&
dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE){
if (dwFileOffsetLow == SHARED_FIRST){
/* Did we have an exclusive lock? */
if (pFile->local.bExclusive){
assert(nNumberOfBytesToUnlockLow == SHARED_SIZE);
pFile->local.bExclusive = FALSE;
pFile->shared->bExclusive = FALSE;
bReturn = TRUE;
@@ -545,6 +551,7 @@ static BOOL winceUnlockFile(
/* Did we just have a reader lock? */
else if (pFile->local.nReaders){
assert(nNumberOfBytesToUnlockLow == 1);
pFile->local.nReaders --;
if (pFile->local.nReaders == 0)
{
@@ -586,6 +593,9 @@ static BOOL winceLockFileEx(
DWORD nNumberOfBytesToLockHigh,
LPOVERLAPPED lpOverlapped
){
UNUSED_PARAMETER(dwReserved);
UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
/* If the caller wants a shared read lock, forward this call
** to winceLockFile */
if (lpOverlapped->Offset == SHARED_FIRST &&
@@ -1592,9 +1602,15 @@ static int getSectorSize(
const char *zRelative /* UTF-8 file name */
){
DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
/* GetDiskFreeSpace is not supported under WINCE */
#if SQLITE_OS_WINCE
UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(zRelative);
#else
char zFullpath[MAX_PATH+1];
int rc;
DWORD dwRet = 0, dwDummy;
DWORD dwRet = 0;
DWORD dwDummy;
/*
** We need to get the full path name of the file
@@ -1620,7 +1636,6 @@ static int getSectorSize(
&bytesPerSector,
&dwDummy,
&dwDummy);
#if SQLITE_OS_WINCE==0
}else{
/* trim path to just drive reference */
CHAR *p = (CHAR *)zConverted;
@@ -1635,7 +1650,6 @@ static int getSectorSize(
&bytesPerSector,
&dwDummy,
&dwDummy);
#endif
}
free(zConverted);
}
@@ -1643,6 +1657,7 @@ static int getSectorSize(
bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
}
}
#endif
return (int) bytesPerSector;
}

View File

@@ -16,6 +16,33 @@
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
/*
** These #defines should enable >2GB file support on POSIX if the
** underlying operating system supports it. If the OS lacks
** large file support, or if the OS is windows, these should be no-ops.
**
** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any
** system #includes. Hence, this block of code must be the very first
** code in all source files.
**
** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
** on the compiler command line. This is necessary if you are compiling
** on a recent machine (ex: Red Hat 7.2) but you want your code to work
** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2
** without this option, LFS is enable. But LFS does not exist in the kernel
** in Red Hat 6.0, so the code won't work. Hence, for maximum binary
** portability you should omit LFS.
**
** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later.
*/
#ifndef SQLITE_DISABLE_LFS
# define _LARGE_FILE 1
# ifndef _FILE_OFFSET_BITS
# define _FILE_OFFSET_BITS 64
# endif
# define _LARGEFILE_SOURCE 1
#endif
/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
@@ -82,33 +109,6 @@
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
#endif
/*
** These #defines should enable >2GB file support on POSIX if the
** underlying operating system supports it. If the OS lacks
** large file support, or if the OS is windows, these should be no-ops.
**
** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any
** system #includes. Hence, this block of code must be the very first
** code in all source files.
**
** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
** on the compiler command line. This is necessary if you are compiling
** on a recent machine (ex: Red Hat 7.2) but you want your code to work
** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2
** without this option, LFS is enable. But LFS does not exist in the kernel
** in Red Hat 6.0, so the code won't work. Hence, for maximum binary
** portability you should omit LFS.
**
** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later.
*/
#ifndef SQLITE_DISABLE_LFS
# define _LARGE_FILE 1
# ifndef _FILE_OFFSET_BITS
# define _FILE_OFFSET_BITS 64
# endif
# define _LARGEFILE_SOURCE 1
#endif
/*
** The SQLITE_THREADSAFE macro must be defined as either 0 or 1.

View File

@@ -195,6 +195,7 @@ struct WhereCost {
WherePlan plan; /* The lookup strategy */
double rCost; /* Overall cost of pursuing this search strategy */
double nRow; /* Estimated number of output rows */
Bitmask used; /* Bitmask of cursors used by this plan */
};
/*
@@ -1338,6 +1339,11 @@ static int isSortingIndex(
nTerm = pOrderBy->nExpr;
assert( nTerm>0 );
/* Argument pIdx must either point to a 'real' named index structure,
** or an index structure allocated on the stack by bestBtreeIndex() to
** represent the rowid index that is part of every table. */
assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) );
/* Match terms of the ORDER BY clause against columns of
** the index.
**
@@ -1364,7 +1370,7 @@ static int isSortingIndex(
if( !pColl ){
pColl = db->pDfltColl;
}
if( i<pIdx->nColumn ){
if( pIdx->zName && i<pIdx->nColumn ){
iColumn = pIdx->aiColumn[i];
if( iColumn==pIdx->pTable->iPKey ){
iColumn = -1;
@@ -1393,7 +1399,7 @@ static int isSortingIndex(
return 0;
}
}
assert( pIdx->aSortOrder!=0 );
assert( pIdx->aSortOrder!=0 || iColumn==-1 );
assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
assert( iSortOrder==0 || iSortOrder==1 );
termSortOrder = iSortOrder ^ pTerm->sortOrder;
@@ -1436,30 +1442,6 @@ static int isSortingIndex(
return 0;
}
/*
** Check table to see if the ORDER BY clause in pOrderBy can be satisfied
** by sorting in order of ROWID. Return true if so and set *pbRev to be
** true for reverse ROWID and false for forward ROWID order.
*/
static int sortableByRowid(
int base, /* Cursor number for table to be sorted */
ExprList *pOrderBy, /* The ORDER BY clause */
WhereMaskSet *pMaskSet, /* Mapping from table cursors to bitmaps */
int *pbRev /* Set to 1 if ORDER BY is DESC */
){
Expr *p;
assert( pOrderBy!=0 );
assert( pOrderBy->nExpr>0 );
p = pOrderBy->a[0].pExpr;
if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1
&& !referencesOtherTables(pOrderBy, pMaskSet, 1, base) ){
*pbRev = pOrderBy->a[0].sortOrder;
return 1;
}
return 0;
}
/*
** Prepare a crude estimate of the logarithm of the input value.
** The results need not be exact. This is only used for estimating
@@ -1560,6 +1542,7 @@ static void bestOrClauseIndex(
int flags = WHERE_MULTI_OR;
double rTotal = 0;
double nRow = 0;
Bitmask used = 0;
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
WhereCost sTermCost;
@@ -1582,6 +1565,7 @@ static void bestOrClauseIndex(
}
rTotal += sTermCost.rCost;
nRow += sTermCost.nRow;
used |= sTermCost.used;
if( rTotal>=pCost->rCost ) break;
}
@@ -1599,6 +1583,7 @@ static void bestOrClauseIndex(
if( rTotal<pCost->rCost ){
pCost->rCost = rTotal;
pCost->nRow = nRow;
pCost->used = used;
pCost->plan.wsFlags = flags;
pCost->plan.u.pTerm = pTerm;
}
@@ -1851,7 +1836,7 @@ static void bestVirtualIndex(
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
j = pIdxCons->iTermOffset;
pTerm = &pWC->a[j];
pIdxCons->usable = (pTerm->prereqRight & notReady)==0 ?1:0;
pIdxCons->usable = (pTerm->prereqRight&notReady) ? 0 : 1;
}
memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
if( pIdxInfo->needToFreeIdxStr ){
@@ -1872,6 +1857,13 @@ static void bestVirtualIndex(
return;
}
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++){
if( pUsage[i].argvIndex>0 ){
pCost->used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight;
}
}
/* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
** inital value of lowestCost in this loop. If it is, then the
** (cost<lowestCost) test below will never be true.
@@ -1934,290 +1926,285 @@ static void bestBtreeIndex(
ExprList *pOrderBy, /* The ORDER BY clause */
WhereCost *pCost /* Lowest cost query plan */
){
WhereTerm *pTerm; /* A single term of the WHERE clause */
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
Index *pProbe; /* An index we are evaluating */
int rev; /* True to scan in reverse order */
int wsFlags; /* Flags associated with pProbe */
int nEq; /* Number of == or IN constraints */
int eqTermMask; /* Mask of valid equality operators */
double cost; /* Cost of using pProbe */
double nRow; /* Estimated number of rows in result set */
int i; /* Loop counter */
Index *pIdx; /* Copy of pProbe, or zero for IPK index */
int eqTermMask; /* Current mask of valid equality operators */
int idxEqTermMask; /* Index mask of valid equality operators */
WHERETRACE(("bestIndex: tbl=%s notReady=%llx\n", pSrc->pTab->zName,notReady));
pProbe = pSrc->pTab->pIndex;
if( pSrc->notIndexed ){
pProbe = 0;
}
Index pk;
unsigned int pkint[2] = {1000000, 1};
int pkicol = -1;
int wsFlagMask;
/* If the table has no indices and there are no terms in the where
** clause that refer to the ROWID, then we will never be able to do
** anything other than a full table scan on this table. We might as
** well put it first in the join order. That way, perhaps it can be
** referenced by other tables in the join.
*/
memset(pCost, 0, sizeof(*pCost));
if( pProbe==0 &&
findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IN|WO_LT|WO_LE|WO_GT|WO_GE,0)==0 &&
(pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev)) ){
if( pParse->db->flags & SQLITE_ReverseOrder ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
*/
pCost->plan.wsFlags |= WHERE_REVERSE;
}
return;
}
pCost->rCost = SQLITE_BIG_DBL;
/* Check for a rowid=EXPR or rowid IN (...) constraints. If there was
** an INDEXED BY clause attached to this table, skip this step.
*/
if( !pSrc->pIndex ){
pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
if( pTerm ){
Expr *pExpr;
pCost->plan.wsFlags = WHERE_ROWID_EQ;
if( pTerm->eOperator & WO_EQ ){
/* Rowid== is always the best pick. Look no further. Because only
** a single row is generated, output is always in sorted order */
pCost->plan.wsFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
pCost->plan.nEq = 1;
WHERETRACE(("... best is rowid\n"));
pCost->rCost = 0;
pCost->nRow = 1;
return;
}else if( !ExprHasProperty((pExpr = pTerm->pExpr), EP_xIsSelect)
&& pExpr->x.pList
){
/* Rowid IN (LIST): cost is NlogN where N is the number of list
** elements. */
pCost->rCost = pCost->nRow = pExpr->x.pList->nExpr;
pCost->rCost *= estLog(pCost->rCost);
}else{
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
** in the result of the inner select. We have no way to estimate
** that value so make a wild guess. */
pCost->nRow = 100;
pCost->rCost = 200;
}
WHERETRACE(("... rowid IN cost: %.9g\n", pCost->rCost));
}
/* Estimate the cost of a table scan. If we do not know how many
** entries are in the table, use 1 million as a guess.
*/
cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
WHERETRACE(("... table scan base cost: %.9g\n", cost));
wsFlags = WHERE_ROWID_RANGE;
/* Check for constraints on a range of rowids in a table scan.
*/
pTerm = findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE|WO_GT|WO_GE, 0);
if( pTerm ){
if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){
wsFlags |= WHERE_TOP_LIMIT;
cost /= 3; /* Guess that rowid<EXPR eliminates two-thirds of rows */
}
if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){
wsFlags |= WHERE_BTM_LIMIT;
cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */
}
WHERETRACE(("... rowid range reduces cost to %.9g\n", cost));
}else{
wsFlags = 0;
}
nRow = cost;
/* If the table scan does not satisfy the ORDER BY clause, increase
** the cost by NlogN to cover the expense of sorting. */
if( pOrderBy ){
if( sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev) ){
wsFlags |= WHERE_ORDERBY|WHERE_ROWID_RANGE;
if( rev ){
wsFlags |= WHERE_REVERSE;
}
}else{
cost += cost*estLog(cost);
WHERETRACE(("... sorting increases cost to %.9g\n", cost));
}
}else if( pParse->db->flags & SQLITE_ReverseOrder ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
*/
wsFlags |= WHERE_REVERSE;
}
/* Remember this case if it is the best so far */
if( cost<pCost->rCost ){
pCost->rCost = cost;
pCost->nRow = nRow;
pCost->plan.wsFlags = wsFlags;
}
}
bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
/* If the pSrc table is the right table of a LEFT JOIN then we may not
** use an index to satisfy IS NULL constraints on that table. This is
** because columns might end up being NULL if the table does not match -
** a circumstance which the index cannot help us discover. Ticket #2177.
*/
if( (pSrc->jointype & JT_LEFT)!=0 ){
eqTermMask = WO_EQ|WO_IN;
if( pSrc->jointype & JT_LEFT ){
idxEqTermMask = WO_EQ|WO_IN;
}else{
eqTermMask = WO_EQ|WO_IN|WO_ISNULL;
idxEqTermMask = WO_EQ|WO_IN|WO_ISNULL;
}
/* Look at each index.
*/
if( pSrc->pIndex ){
pProbe = pSrc->pIndex;
pIdx = pProbe = pSrc->pIndex;
wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE);
eqTermMask = idxEqTermMask;
}else{
Index *pFirst = pSrc->pTab->pIndex;
memset(&pk, 0, sizeof(Index));
pk.nColumn = 1;
pk.aiColumn = &pkicol;
pk.aiRowEst = pkint;
pk.onError = OE_Replace;
pk.pTable = pSrc->pTab;
if( pSrc->notIndexed==0 ){
pk.pNext = pFirst;
}
if( pFirst && pFirst->aiRowEst ){
pkint[0] = pFirst->aiRowEst[0];
}
pProbe = &pk;
wsFlagMask = ~(
WHERE_COLUMN_IN|WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_RANGE
);
eqTermMask = WO_EQ|WO_IN;
pIdx = 0;
}
for(; pProbe; pProbe=(pSrc->pIndex ? 0 : pProbe->pNext)){
double inMultiplier = 1; /* Number of equality look-ups needed */
int inMultIsEst = 0; /* True if inMultiplier is an estimate */
WHERETRACE(("... index %s:\n", pProbe->zName));
/* Count the number of columns in the index that are satisfied
** by x=EXPR or x IS NULL constraints or x IN (...) constraints.
** For a term of the form x=EXPR or x IS NULL we only have to do
** a single binary search. But for x IN (...) we have to do a
** number of binary searched
** equal to the number of entries on the RHS of the IN operator.
** The inMultipler variable with try to estimate the number of
** binary searches needed.
for(; pProbe; pIdx=pProbe=pProbe->pNext){
const unsigned int * const aiRowEst = pProbe->aiRowEst;
double cost; /* Cost of using pProbe */
double nRow; /* Estimated number of rows in result set */
int rev; /* True to scan in reverse order */
int wsFlags = 0;
Bitmask used = 0;
/* The following variables are populated based on the properties of
** scan being evaluated. They are then used to determine the expected
** cost and number of rows returned.
**
** nEq:
** Number of equality terms that can be implemented using the index.
**
** nInMul:
** The "in-multiplier". This is an estimate of how many seek operations
** SQLite must perform on the index in question. For example, if the
** WHERE clause is:
**
** WHERE a IN (1, 2, 3) AND b IN (4, 5, 6)
**
** SQLite must perform 9 lookups on an index on (a, b), so nInMul is
** set to 9. Given the same schema and either of the following WHERE
** clauses:
**
** WHERE a = 1
** WHERE a >= 2
**
** nInMul is set to 1.
**
** If there exists a WHERE term of the form "x IN (SELECT ...)", then
** the sub-select is assumed to return 25 rows for the purposes of
** determining nInMul.
**
** bInEst:
** Set to true if there was at least one "x IN (SELECT ...)" term used
** in determining the value of nInMul.
**
** nBound:
** Set based on whether or not there is a range constraint on the
** (nEq+1)th column of the index. 1 if there is neither an upper or
** lower bound, 3 if there is an upper or lower bound, or 9 if there
** is both an upper and lower bound.
**
** bSort:
** Boolean. True if there is an ORDER BY clause that will require an
** external sort (i.e. scanning the index being evaluated will not
** correctly order records).
**
** bLookup:
** Boolean. True if for each index entry visited a lookup on the
** corresponding table b-tree is required. This is always false
** for the rowid index. For other indexes, it is true unless all the
** columns of the table used by the SELECT statement are present in
** the index (such an index is sometimes described as a covering index).
** For example, given the index on (a, b), the second of the following
** two queries requires table b-tree lookups, but the first does not.
**
** SELECT a, b FROM tbl WHERE a = 1;
** SELECT a, b, c FROM tbl WHERE a = 1;
*/
wsFlags = 0;
for(i=0; i<pProbe->nColumn; i++){
int j = pProbe->aiColumn[i];
pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pProbe);
int nEq;
int bInEst = 0;
int nInMul = 1;
int nBound = 1;
int bSort = 0;
int bLookup = 0;
/* Determine the values of nEq and nInMul */
for(nEq=0; nEq<pProbe->nColumn; nEq++){
WhereTerm *pTerm; /* A single term of the WHERE clause */
int j = pProbe->aiColumn[nEq];
pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx);
if( pTerm==0 ) break;
wsFlags |= WHERE_COLUMN_EQ;
wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
if( pTerm->eOperator & WO_IN ){
Expr *pExpr = pTerm->pExpr;
wsFlags |= WHERE_COLUMN_IN;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
inMultiplier *= 25;
inMultIsEst = 1;
nInMul *= 25;
bInEst = 1;
}else if( pExpr->x.pList ){
inMultiplier *= pExpr->x.pList->nExpr + 1;
nInMul *= pExpr->x.pList->nExpr + 1;
}
}else if( pTerm->eOperator & WO_ISNULL ){
wsFlags |= WHERE_COLUMN_NULL;
}
used |= pTerm->prereqRight;
}
nRow = pProbe->aiRowEst[i] * inMultiplier;
/* If inMultiplier is an estimate and that estimate results in an
** nRow it that is more than half number of rows in the table,
** then reduce inMultipler */
if( inMultIsEst && nRow*2 > pProbe->aiRowEst[0] ){
nRow = pProbe->aiRowEst[0]/2;
inMultiplier = nRow/pProbe->aiRowEst[i];
}
cost = nRow + inMultiplier*estLog(pProbe->aiRowEst[0]);
nEq = i;
if( pProbe->onError!=OE_None && nEq==pProbe->nColumn ){
/* Determine the value of nBound. */
if( nEq<pProbe->nColumn ){
int j = pProbe->aiColumn[nEq];
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
if( pTop ){
wsFlags |= WHERE_TOP_LIMIT;
nBound *= 3;
used |= pTop->prereqRight;
}
if( pBtm ){
wsFlags |= WHERE_BTM_LIMIT;
nBound *= 3;
used |= pBtm->prereqRight;
}
wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
}
}else if( pProbe->onError!=OE_None ){
testcase( wsFlags & WHERE_COLUMN_IN );
testcase( wsFlags & WHERE_COLUMN_NULL );
if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
wsFlags |= WHERE_UNIQUE;
}
}
WHERETRACE(("...... nEq=%d inMult=%.9g nRow=%.9g cost=%.9g\n",
nEq, inMultiplier, nRow, cost));
/* Look for range constraints. Assume that each range constraint
** makes the search space 1/3rd smaller.
*/
if( nEq<pProbe->nColumn ){
int j = pProbe->aiColumn[nEq];
pTerm = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pProbe);
if( pTerm ){
wsFlags |= WHERE_COLUMN_RANGE;
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){
wsFlags |= WHERE_TOP_LIMIT;
cost /= 3;
nRow /= 3;
}
if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){
wsFlags |= WHERE_BTM_LIMIT;
cost /= 3;
nRow /= 3;
}
WHERETRACE(("...... range reduces nRow to %.9g and cost to %.9g\n",
nRow, cost));
}
}
/* Add the additional cost of sorting if that is a factor.
*/
/* If there is an ORDER BY clause and the index being considered will
** naturally scan rows in the required order, set the appropriate flags
** in wsFlags. Otherwise, if there is an ORDER BY clause but the index
** will scan rows in a different order, set the bSort variable. */
if( pOrderBy ){
if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0
&& isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev)
&& isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev)
){
if( wsFlags==0 ){
wsFlags = WHERE_COLUMN_RANGE;
}
wsFlags |= WHERE_ORDERBY;
if( rev ){
wsFlags |= WHERE_REVERSE;
}
wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY;
wsFlags |= (rev ? WHERE_REVERSE : 0);
}else{
cost += cost*estLog(cost);
WHERETRACE(("...... orderby increases cost to %.9g\n", cost));
bSort = 1;
}
}else if( wsFlags!=0 && (pParse->db->flags & SQLITE_ReverseOrder)!=0 ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
*/
wsFlags |= WHERE_REVERSE;
}
/* Check to see if we can get away with using just the index without
** ever reading the table. If that is the case, then halve the
** cost of this index.
*/
if( wsFlags && pSrc->colUsed < (((Bitmask)1)<<(BMS-1)) ){
/* If currently calculating the cost of using an index (not the IPK
** index), determine if all required column data may be obtained without
** seeking to entries in the main table (i.e. if the index is a covering
** index for this query). If it is, set the WHERE_IDX_ONLY flag in
** wsFlags. Otherwise, set the bLookup variable to true. */
if( pIdx && wsFlags ){
Bitmask m = pSrc->colUsed;
int j;
for(j=0; j<pProbe->nColumn; j++){
int x = pProbe->aiColumn[j];
for(j=0; j<pIdx->nColumn; j++){
int x = pIdx->aiColumn[j];
if( x<BMS-1 ){
m &= ~(((Bitmask)1)<<x);
}
}
if( m==0 ){
wsFlags |= WHERE_IDX_ONLY;
cost /= 2;
WHERETRACE(("...... idx-only reduces cost to %.9g\n", cost));
}else{
bLookup = 1;
}
}
/* If this index has achieved the lowest cost so far, then use it.
*/
if( wsFlags!=0 && cost < pCost->rCost ){
#if 0
if( bInEst && (nInMul*aiRowEst[nEq])>(aiRowEst[0]/2) ){
nInMul = aiRowEst[0] / (2 * aiRowEst[nEq]);
}
nRow = (double)(aiRowEst[nEq] * nInMul) / nBound;
cost = (nEq>0) * nInMul * estLog(aiRowEst[0])
+ nRow
+ bSort * nRow * estLog(nRow)
+ bLookup * nRow * estLog(aiRowEst[0]);
#else
/* The following block calculates nRow and cost for the index scan
** in the same way as SQLite versions 3.6.17 and earlier. Some elements
** of this calculation are difficult to justify. But using this strategy
** works well in practice and causes the test suite to pass. */
nRow = (double)(aiRowEst[nEq] * nInMul);
if( bInEst && nRow*2>aiRowEst[0] ){
nRow = aiRowEst[0]/2;
nInMul = nRow / aiRowEst[nEq];
}
cost = nRow + nInMul*estLog(aiRowEst[0]);
nRow /= nBound;
cost /= nBound;
if( bSort ){
cost += cost*estLog(cost);
}
if( pIdx && bLookup==0 ){
cost /= 2;
}
#endif
WHERETRACE((
"tbl=%s idx=%s nEq=%d nInMul=%d nBound=%d bSort=%d bLookup=%d"
" wsFlags=%d (nRow=%.2f cost=%.2f)\n",
pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
nEq, nInMul, nBound, bSort, bLookup, wsFlags, nRow, cost
));
if( (!pIdx || wsFlags) && cost<pCost->rCost ){
pCost->rCost = cost;
pCost->nRow = nRow;
pCost->plan.wsFlags = wsFlags;
pCost->used = used;
pCost->plan.wsFlags = (wsFlags&wsFlagMask);
pCost->plan.nEq = nEq;
assert( pCost->plan.wsFlags & WHERE_INDEXED );
pCost->plan.u.pIdx = pProbe;
pCost->plan.u.pIdx = pIdx;
}
if( pSrc->pIndex ) break;
wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE);
eqTermMask = idxEqTermMask;
}
/* Report the best result
*/
/* If there is no ORDER BY clause and the SQLITE_ReverseOrder flag
** is set, then reverse the order that the index will be scanned
** in. This is used for application testing, to help find cases
** where application behaviour depends on the (undefined) order that
** SQLite outputs rows in in the absence of an ORDER BY clause. */
if( !pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){
pCost->plan.wsFlags |= WHERE_REVERSE;
}
assert( pOrderBy || (pCost->plan.wsFlags&WHERE_ORDERBY)==0 );
assert( pCost->plan.u.pIdx==0 || (pCost->plan.wsFlags&WHERE_ROWID_EQ)==0 );
assert( pSrc->pIndex==0
|| pCost->plan.u.pIdx==0
|| pCost->plan.u.pIdx==pSrc->pIndex
);
WHERETRACE(("best index is: %s\n",
(pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
));
bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
pCost->plan.wsFlags |= eqTermMask;
WHERETRACE(("best index is %s, nrow=%.9g, cost=%.9g, wsFlags=%x, nEq=%d\n",
(pCost->plan.wsFlags & WHERE_INDEXED)!=0 ?
pCost->plan.u.pIdx->zName : "(none)", pCost->nRow,
pCost->rCost, pCost->plan.wsFlags, pCost->plan.nEq));
}
/*
@@ -3271,44 +3258,82 @@ WhereInfo *sqlite3WhereBegin(
WhereCost bestPlan; /* Most efficient plan seen so far */
Index *pIdx; /* Index for FROM table at pTabItem */
int j; /* For looping over FROM tables */
int bestJ = 0; /* The value of j */
int bestJ = -1; /* The value of j */
Bitmask m; /* Bitmask value for j or bestJ */
int once = 0; /* True when first table is seen */
int isOptimal; /* Iterator for optimal/non-optimal search */
memset(&bestPlan, 0, sizeof(bestPlan));
bestPlan.rCost = SQLITE_BIG_DBL;
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */
WhereCost sCost; /* Cost information from best[Virtual]Index() */
ExprList *pOrderBy; /* ORDER BY clause for index to optimize */
doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
if( once && doNotReorder ) break;
m = getMask(pMaskSet, pTabItem->iCursor);
if( (m & notReady)==0 ){
if( j==iFrom ) iFrom++;
continue;
}
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
/* Loop through the remaining entries in the FROM clause to find the
** next nested loop. The FROM clause entries may be iterated through
** either once or twice.
**
** The first iteration, which is always performed, searches for the
** FROM clause entry that permits the lowest-cost, "optimal" scan. In
** this context an optimal scan is one that uses the same strategy
** for the given FROM clause entry as would be selected if the entry
** were used as the innermost nested loop.
**
** The second iteration is only performed if no optimal scan strategies
** were found by the first. This iteration is used to search for the
** lowest cost scan overall.
**
** Previous versions of SQLite performed only the second iteration -
** the next outermost loop was always that with the lowest overall
** cost. However, this meant that SQLite could select the wrong plan
** for scripts such as the following:
**
** CREATE TABLE t1(a, b);
** CREATE TABLE t2(c, d);
** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a;
**
** The best strategy is to iterate through table t1 first. However it
** is not possible to determine this with a simple greedy algorithm.
** However, since the cost of a linear scan through table t2 is the same
** as the cost of a linear scan through table t1, a simple greedy
** algorithm may choose to use t2 for the outer loop, which is a much
** costlier approach.
*/
for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
Bitmask mask = (isOptimal ? 0 : notReady);
assert( (pTabList->nSrc-iFrom)>1 || isOptimal );
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */
WhereCost sCost; /* Cost information from best[Virtual]Index() */
ExprList *pOrderBy; /* ORDER BY clause for index to optimize */
assert( pTabItem->pTab );
doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
if( j!=iFrom && doNotReorder ) break;
m = getMask(pMaskSet, pTabItem->iCursor);
if( (m & notReady)==0 ){
if( j==iFrom ) iFrom++;
continue;
}
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
assert( pTabItem->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTabItem->pTab) ){
sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
bestVirtualIndex(pParse, pWC, pTabItem, notReady, pOrderBy, &sCost, pp);
}else
if( IsVirtual(pTabItem->pTab) ){
sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
bestVirtualIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost, pp);
}else
#endif
{
bestBtreeIndex(pParse, pWC, pTabItem, notReady, pOrderBy, &sCost);
{
bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost);
}
assert( isOptimal || (sCost.used&notReady)==0 );
if( (sCost.used&notReady)==0
&& (j==iFrom || sCost.rCost<bestPlan.rCost)
){
bestPlan = sCost;
bestJ = j;
}
if( doNotReorder ) break;
}
if( once==0 || sCost.rCost<bestPlan.rCost ){
once = 1;
bestPlan = sCost;
bestJ = j;
}
if( doNotReorder ) break;
}
assert( once );
assert( bestJ>=0 );
assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
WHERETRACE(("*** Optimizer selects table %d for loop %d\n", bestJ,
pLevel-pWInfo->a));

View File

@@ -79,7 +79,7 @@ do_test triggerA-1.6 {
CREATE VIEW v5 AS SELECT x, b FROM t1, t2 WHERE y=c;
SELECT * FROM v5;
}
} {1 103 2 203 3 305 4 404 5 504 6 603 7 705 8 805 9 904 10 1003}
} {10 1003 9 904 8 805 7 705 6 603 5 504 4 404 3 305 2 203 1 103}
# Create INSTEAD OF triggers on the views. Run UPDATE and DELETE statements
# using those triggers. Verify correct operation.

View File

@@ -492,6 +492,7 @@ do_test vtab6-11.1.4 {
do_test vtab6-11.2.0 {
execsql {
CREATE INDEX ab_i ON ab_r(b);
CREATE INDEX bc_i ON bc_r(b);
}
} {}
@@ -560,7 +561,7 @@ do_test vtab6-11.4.1 {
catchsql {
SELECT a, b, c FROM ab NATURAL JOIN bc;
}
} {1 {table ab: xBestIndex returned an invalid plan}}
} {1 {table bc: xBestIndex returned an invalid plan}}
do_test vtab6-11.4.2 {
catchsql {
SELECT a, b, c FROM bc NATURAL JOIN ab;

View File

@@ -287,7 +287,7 @@ do_test where8-3.15 {
SELECT sum(e IS NULL) FROM t2 AS inner WHERE t2.d>inner.d
)
}
} {I I I I I I I I I I II II II II II II II II II II III III III III III 99 0}
} {I II I II I II I II I II I II III I II III I II III I II III I II III 9 0}
#-----------------------------------------------------------------------
# The following tests - where8-4.* - verify that adding or removing