mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-19 21:43:15 +03:00
Update some variable names and comments in the ORDER BY optimizer. Fix a
bug in the ORDER BY optimizer dealing with IS NULL constraints. Updates to test cases. FossilOrigin-Name: cf96eb5945a9bab71104cb1581ee13ab30022566
This commit is contained in:
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Restore\sthe\sPRAGMA\sreverse_unordered_selects\sbehavior.
|
C Update\ssome\svariable\snames\sand\scomments\sin\sthe\sORDER\sBY\soptimizer.\s\sFix\sa\nbug\sin\sthe\sORDER\sBY\soptimizer\sdealing\swith\sIS\sNULL\sconstraints.\s\sUpdates\nto\stest\scases.
|
||||||
D 2013-06-04T18:27:41.462
|
D 2013-06-04T23:40:53.563
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
|
|||||||
F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d
|
F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d
|
||||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||||
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
|
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
|
||||||
F src/where.c cc1e1a7255b6722a419d6a5016d89f227e7a9ce7
|
F src/where.c 0b8fd61de3c71df0ba084d13177c384bb50e4d22
|
||||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||||
@@ -1030,7 +1030,7 @@ F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
|||||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||||
F test/where.test 054a6b6f7933c5a5f50d0bcd650b5eccb450cc81
|
F test/where.test 054a6b6f7933c5a5f50d0bcd650b5eccb450cc81
|
||||||
F test/where2.test 116fb0d6e98a423d12eb9a65906218ce09936674
|
F test/where2.test 116fb0d6e98a423d12eb9a65906218ce09936674
|
||||||
F test/where3.test ae3054e1216ecc0afbcb83674310ebc5de25ba09
|
F test/where3.test 311c04e16f72816616d05d96dd354db7bce545eb
|
||||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||||
@@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||||
P 774d5ff857cfad3471401ed518ed0959eb912e6c
|
P f49cd6c4e752e39801f9d5de0bc370d26f43837c
|
||||||
R a1a3ee93fd22dda060fc640b96157ac6
|
R e9f7dc193466abcd06681335597fcecc
|
||||||
U drh
|
U drh
|
||||||
Z ec57b78c26a34e23e063493e6b075b85
|
Z dc06d4669e35a15ef353fefc6b023d96
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
f49cd6c4e752e39801f9d5de0bc370d26f43837c
|
cf96eb5945a9bab71104cb1581ee13ab30022566
|
||||||
80
src/where.c
80
src/where.c
@@ -4555,7 +4555,9 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
u8 revSet; /* True if rev is known */
|
u8 revSet; /* True if rev is known */
|
||||||
u8 rev; /* Composite sort order */
|
u8 rev; /* Composite sort order */
|
||||||
u8 revIdx; /* Index sort order */
|
u8 revIdx; /* Index sort order */
|
||||||
u8 isWellOrdered; /* All WhereLoops are well-ordered so far */
|
u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */
|
||||||
|
u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */
|
||||||
|
u8 isMatch; /* iColumn matches a term of the ORDER BY clause */
|
||||||
u16 nColumn; /* Number of columns in pIndex */
|
u16 nColumn; /* Number of columns in pIndex */
|
||||||
u16 nOrderBy; /* Number terms in the ORDER BY clause */
|
u16 nOrderBy; /* Number terms in the ORDER BY clause */
|
||||||
int iLoop; /* Index of WhereLoop in pPath being processed */
|
int iLoop; /* Index of WhereLoop in pPath being processed */
|
||||||
@@ -4571,7 +4573,7 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
sqlite3 *db = pWInfo->pParse->db; /* Database connection */
|
sqlite3 *db = pWInfo->pParse->db; /* Database connection */
|
||||||
Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */
|
Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */
|
||||||
Bitmask obDone; /* Mask of all ORDER BY terms */
|
Bitmask obDone; /* Mask of all ORDER BY terms */
|
||||||
Bitmask orderedMask; /* Mask of all well-ordered loops */
|
Bitmask orderDistinctMask; /* Mask of all well-ordered loops */
|
||||||
WhereMaskSet *pMaskSet; /* WhereMaskSet object for this where clause */
|
WhereMaskSet *pMaskSet; /* WhereMaskSet object for this where clause */
|
||||||
|
|
||||||
|
|
||||||
@@ -4583,15 +4585,18 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
** Any WhereLoop with an WHERE_COLUMN_EQ constraint on the rowid is one-row.
|
** Any WhereLoop with an WHERE_COLUMN_EQ constraint on the rowid is one-row.
|
||||||
** Every one-row WhereLoop will have the WHERE_ONEROW bit set in wsFlags.
|
** Every one-row WhereLoop will have the WHERE_ONEROW bit set in wsFlags.
|
||||||
**
|
**
|
||||||
** We say the WhereLoop is "well-ordered" if
|
** We say the WhereLoop is "order-distinct" if the set of columns from
|
||||||
** (i) it satisfies at least one term of the ORDER BY clause, and
|
** that WhereLoop that are in the ORDER BY clause are different for every
|
||||||
** (ii) every row output is distinct over the terms that match the
|
** row of the WhereLoop. Every one-row WhereLoop is automatically
|
||||||
** ORDER BY clause.
|
** order-distinct. A WhereLoop that has no columns in the ORDER BY clause
|
||||||
** Every one-row WhereLoop is automatically well-ordered, even if it
|
** is not order-distinct. To be order-distinct is not quite the same as being
|
||||||
** does not match any terms of the ORDER BY clause.
|
** UNIQUE since a UNIQUE column or index can have multiple rows that
|
||||||
** For condition (ii), be mindful that a UNIQUE column can have multiple
|
** are NULL and NULL values are equivalent for the purpose of order-distinct.
|
||||||
** rows that are NULL and so it not necessarily distinct. The column
|
** To be order-distinct, the columns must be UNIQUE and NOT NULL.
|
||||||
** must be UNIQUE and NOT NULL. in order to be well-ordered.
|
**
|
||||||
|
** The rowid for a table is always UNIQUE and NOT NULL so whenever the
|
||||||
|
** rowid appears in the ORDER BY clause, the corresponding WhereLoop is
|
||||||
|
** automatically order-distinct.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
assert( pOrderBy!=0 );
|
assert( pOrderBy!=0 );
|
||||||
@@ -4606,12 +4611,12 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0;
|
if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0;
|
||||||
|
|
||||||
nOrderBy = pOrderBy->nExpr;
|
nOrderBy = pOrderBy->nExpr;
|
||||||
if( nOrderBy>60 ) return 0;
|
if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */
|
||||||
isWellOrdered = 1;
|
isOrderDistinct = 1;
|
||||||
obDone = MASKBIT(nOrderBy)-1;
|
obDone = MASKBIT(nOrderBy)-1;
|
||||||
orderedMask = 0;
|
orderDistinctMask = 0;
|
||||||
pMaskSet = pWInfo->pWC->pMaskSet;
|
pMaskSet = pWInfo->pWC->pMaskSet;
|
||||||
for(iLoop=0; isWellOrdered && obSat<obDone && iLoop<=nLoop; iLoop++){
|
for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
|
||||||
pLoop = iLoop<nLoop ? pPath->aLoop[iLoop] : pLast;
|
pLoop = iLoop<nLoop ? pPath->aLoop[iLoop] : pLast;
|
||||||
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
|
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
|
||||||
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
|
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
|
||||||
@@ -4623,9 +4628,10 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
return 0;
|
return 0;
|
||||||
}else{
|
}else{
|
||||||
nColumn = pIndex->nColumn;
|
nColumn = pIndex->nColumn;
|
||||||
|
isOrderDistinct = pIndex->onError!=OE_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For every term of the index that is constrained by == or IS NULL
|
/* For every term of the index that is constrained by == or IS NULL,
|
||||||
** mark off corresponding ORDER BY terms wherever they occur
|
** mark off corresponding ORDER BY terms wherever they occur
|
||||||
** in the ORDER BY clause.
|
** in the ORDER BY clause.
|
||||||
*/
|
*/
|
||||||
@@ -4653,17 +4659,20 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
** that are not constrained by == or IN.
|
** that are not constrained by == or IN.
|
||||||
*/
|
*/
|
||||||
rev = revSet = 0;
|
rev = revSet = 0;
|
||||||
|
distinctColumns = 0;
|
||||||
for(j=0; j<=nColumn; j++){
|
for(j=0; j<=nColumn; j++){
|
||||||
u8 bOnce; /* True to run the ORDER BY search loop */
|
u8 bOnce; /* True to run the ORDER BY search loop */
|
||||||
|
|
||||||
|
/* Skip over == and IS NULL terms */
|
||||||
if( j<pLoop->u.btree.nEq
|
if( j<pLoop->u.btree.nEq
|
||||||
&& (pLoop->aTerm[j]->eOperator & (WO_EQ|WO_ISNULL))!=0
|
&& ((i = pLoop->aTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
|
||||||
){
|
){
|
||||||
continue; /* Skip == and IS NULL terms already processed */
|
if( i & WO_ISNULL ) isOrderDistinct = 0;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the column number in the table and sort order for the
|
/* Get the column number in the table (iColumn) and sort order
|
||||||
** j-th column of the index for this WhereLoop
|
** (revIdx) for the j-th column of the index.
|
||||||
*/
|
*/
|
||||||
if( j<nColumn ){
|
if( j<nColumn ){
|
||||||
/* Normal index columns */
|
/* Normal index columns */
|
||||||
@@ -4679,22 +4688,24 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
/* An unconstrained column that might be NULL means that this
|
/* An unconstrained column that might be NULL means that this
|
||||||
** WhereLoop is not well-ordered
|
** WhereLoop is not well-ordered
|
||||||
*/
|
*/
|
||||||
if( iColumn>=0
|
if( isOrderDistinct
|
||||||
|
&& iColumn>=0
|
||||||
&& j>=pLoop->u.btree.nEq
|
&& j>=pLoop->u.btree.nEq
|
||||||
&& pIndex->pTable->aCol[iColumn].notNull==0
|
&& pIndex->pTable->aCol[iColumn].notNull==0
|
||||||
){
|
){
|
||||||
isWellOrdered = 0;
|
isOrderDistinct = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the ORDER BY term that corresponds to the j-th column
|
/* Find the ORDER BY term that corresponds to the j-th column
|
||||||
** of the index and and mark that ORDER BY term off
|
** of the index and and mark that ORDER BY term off
|
||||||
*/
|
*/
|
||||||
bOnce = 1;
|
bOnce = 1;
|
||||||
|
isMatch = 0;
|
||||||
for(i=0; bOnce && i<nOrderBy; i++){
|
for(i=0; bOnce && i<nOrderBy; i++){
|
||||||
if( MASKBIT(i) & obSat ) continue;
|
if( MASKBIT(i) & obSat ) continue;
|
||||||
pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr);
|
pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr);
|
||||||
if( pOBExpr->op!=TK_COLUMN ) continue;
|
|
||||||
if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ) bOnce = 0;
|
if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ) bOnce = 0;
|
||||||
|
if( pOBExpr->op!=TK_COLUMN ) continue;
|
||||||
if( pOBExpr->iTable!=iCur ) continue;
|
if( pOBExpr->iTable!=iCur ) continue;
|
||||||
if( pOBExpr->iColumn!=iColumn ) continue;
|
if( pOBExpr->iColumn!=iColumn ) continue;
|
||||||
if( iColumn>=0 ){
|
if( iColumn>=0 ){
|
||||||
@@ -4702,15 +4713,15 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
if( !pColl ) pColl = db->pDfltColl;
|
if( !pColl ) pColl = db->pDfltColl;
|
||||||
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
|
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
|
||||||
}
|
}
|
||||||
bOnce = 1;
|
isMatch = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if( bOnce && i<nOrderBy ){
|
if( isMatch ){
|
||||||
if( iColumn<0 ) isWellOrdered = 1;
|
if( iColumn<0 ) distinctColumns = 1;
|
||||||
obSat |= MASKBIT(i);
|
obSat |= MASKBIT(i);
|
||||||
if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
|
if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
|
||||||
/* If we have an ORDER BY clause, we must match the next available
|
/* Make sure the sort order is compatible in an ORDER BY clause.
|
||||||
** column of the ORDER BY */
|
** Sort order is irrelevant for a GROUP BY clause. */
|
||||||
if( revSet ){
|
if( revSet ){
|
||||||
if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0;
|
if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0;
|
||||||
}else{
|
}else{
|
||||||
@@ -4721,29 +4732,28 @@ static int wherePathSatisfiesOrderBy(
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
/* No match found */
|
/* No match found */
|
||||||
if( j<nColumn || pIndex==0 || pIndex->onError==OE_None ){
|
if( j==0 || j<nColumn ) isOrderDistinct = 0;
|
||||||
isWellOrdered = 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} /* end Loop over all index columns */
|
} /* end Loop over all index columns */
|
||||||
|
if( distinctColumns ) isOrderDistinct = 1;
|
||||||
} /* end-if not one-row */
|
} /* end-if not one-row */
|
||||||
|
|
||||||
/* Mark off any other ORDER BY terms that reference pLoop */
|
/* Mark off any other ORDER BY terms that reference pLoop */
|
||||||
if( isWellOrdered ){
|
if( isOrderDistinct ){
|
||||||
orderedMask |= pLoop->maskSelf;
|
orderDistinctMask |= pLoop->maskSelf;
|
||||||
for(i=0; i<nOrderBy; i++){
|
for(i=0; i<nOrderBy; i++){
|
||||||
Expr *p;
|
Expr *p;
|
||||||
if( MASKBIT(i) & obSat ) continue;
|
if( MASKBIT(i) & obSat ) continue;
|
||||||
p = pOrderBy->a[i].pExpr;
|
p = pOrderBy->a[i].pExpr;
|
||||||
if( (exprTableUsage(pMaskSet, p)&~orderedMask)==0 ){
|
if( (exprTableUsage(pMaskSet, p)&~orderDistinctMask)==0 ){
|
||||||
obSat |= MASKBIT(i);
|
obSat |= MASKBIT(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( obSat==obDone ) return 1;
|
if( obSat==obDone ) return 1;
|
||||||
if( !isWellOrdered ) return 0;
|
if( !isOrderDistinct ) return 0;
|
||||||
if( isLastLoop ) return 1;
|
if( isLastLoop ) return 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,37 +190,37 @@ do_test where3-2.2 {
|
|||||||
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
||||||
WHERE cpk=bx AND apk=bx
|
WHERE cpk=bx AND apk=bx
|
||||||
}
|
}
|
||||||
} {tB {} tA * tC * tD *}
|
} {tB * tA * tC * tD *}
|
||||||
do_test where3-2.3 {
|
do_test where3-2.3 {
|
||||||
queryplan {
|
queryplan {
|
||||||
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
||||||
WHERE cpk=bx AND apk=bx
|
WHERE cpk=bx AND apk=bx
|
||||||
}
|
}
|
||||||
} {tB {} tA * tC * tD *}
|
} {tB * tA * tC * tD *}
|
||||||
do_test where3-2.4 {
|
do_test where3-2.4 {
|
||||||
queryplan {
|
queryplan {
|
||||||
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
||||||
WHERE apk=cx AND bpk=ax
|
WHERE apk=cx AND bpk=ax
|
||||||
}
|
}
|
||||||
} {tC {} tA * tB * tD *}
|
} {tC * tA * tB * tD *}
|
||||||
do_test where3-2.5 {
|
do_test where3-2.5 {
|
||||||
queryplan {
|
queryplan {
|
||||||
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
||||||
WHERE cpk=ax AND bpk=cx
|
WHERE cpk=ax AND bpk=cx
|
||||||
}
|
}
|
||||||
} {tA {} tC * tB * tD *}
|
} {tA * tC * tB * tD *}
|
||||||
do_test where3-2.6 {
|
do_test where3-2.6 {
|
||||||
queryplan {
|
queryplan {
|
||||||
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
||||||
WHERE bpk=cx AND apk=bx
|
WHERE bpk=cx AND apk=bx
|
||||||
}
|
}
|
||||||
} {tC {} tB * tA * tD *}
|
} {tC * tB * tA * tD *}
|
||||||
do_test where3-2.7 {
|
do_test where3-2.7 {
|
||||||
queryplan {
|
queryplan {
|
||||||
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx
|
||||||
WHERE cpk=bx AND apk=cx
|
WHERE cpk=bx AND apk=cx
|
||||||
}
|
}
|
||||||
} {tB {} tC * tA * tD *}
|
} {tB * tC * tA * tD *}
|
||||||
|
|
||||||
# Ticket [13f033c865f878953]
|
# Ticket [13f033c865f878953]
|
||||||
# If the outer loop must be a full table scan, do not let ANALYZE trick
|
# If the outer loop must be a full table scan, do not let ANALYZE trick
|
||||||
|
|||||||
Reference in New Issue
Block a user