From: drh Date: Tue, 4 Jun 2013 23:40:53 +0000 (+0000) Subject: Update some variable names and comments in the ORDER BY optimizer. Fix a X-Git-Tag: version-3.8.0~130^2~27 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e353ee3898ce329271e8b4dd726307e730907601;p=thirdparty%2Fsqlite.git 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 --- diff --git a/manifest b/manifest index 487bb8cc30..7b304b267b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Restore\sthe\sPRAGMA\sreverse_unordered_selects\sbehavior. -D 2013-06-04T18:27:41.462 +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-04T23:40:53.563 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c cc1e1a7255b6722a419d6a5016d89f227e7a9ce7 +F src/where.c 0b8fd61de3c71df0ba084d13177c384bb50e4d22 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1030,7 +1030,7 @@ F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e F test/where.test 054a6b6f7933c5a5f50d0bcd650b5eccb450cc81 F test/where2.test 116fb0d6e98a423d12eb9a65906218ce09936674 -F test/where3.test ae3054e1216ecc0afbcb83674310ebc5de25ba09 +F test/where3.test 311c04e16f72816616d05d96dd354db7bce545eb F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b @@ -1093,7 +1093,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 774d5ff857cfad3471401ed518ed0959eb912e6c -R a1a3ee93fd22dda060fc640b96157ac6 +P f49cd6c4e752e39801f9d5de0bc370d26f43837c +R e9f7dc193466abcd06681335597fcecc U drh -Z ec57b78c26a34e23e063493e6b075b85 +Z dc06d4669e35a15ef353fefc6b023d96 diff --git a/manifest.uuid b/manifest.uuid index dd954ef445..269a302e79 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f49cd6c4e752e39801f9d5de0bc370d26f43837c \ No newline at end of file +cf96eb5945a9bab71104cb1581ee13ab30022566 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 3bb15bdc96..d9dccf7541 100644 --- a/src/where.c +++ b/src/where.c @@ -4555,7 +4555,9 @@ static int wherePathSatisfiesOrderBy( u8 revSet; /* True if rev is known */ u8 rev; /* Composite 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 nOrderBy; /* Number terms in the ORDER BY clause */ int iLoop; /* Index of WhereLoop in pPath being processed */ @@ -4571,8 +4573,8 @@ static int wherePathSatisfiesOrderBy( sqlite3 *db = pWInfo->pParse->db; /* Database connection */ Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */ Bitmask obDone; /* Mask of all ORDER BY terms */ - Bitmask orderedMask; /* Mask of all well-ordered loops */ - WhereMaskSet *pMaskSet; /* WhereMaskSet object for this where clause */ + Bitmask orderDistinctMask; /* Mask of all well-ordered loops */ + 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. ** Every one-row WhereLoop will have the WHERE_ONEROW bit set in wsFlags. ** - ** We say the WhereLoop is "well-ordered" if - ** (i) it satisfies at least one term of the ORDER BY clause, and - ** (ii) every row output is distinct over the terms that match the - ** ORDER BY clause. - ** Every one-row WhereLoop is automatically well-ordered, even if it - ** does not match any terms of the ORDER BY clause. - ** For condition (ii), be mindful that a UNIQUE column can have multiple - ** rows that are NULL and so it not necessarily distinct. The column - ** must be UNIQUE and NOT NULL. in order to be well-ordered. + ** We say the WhereLoop is "order-distinct" if the set of columns from + ** that WhereLoop that are in the ORDER BY clause are different for every + ** row of the WhereLoop. Every one-row WhereLoop is automatically + ** order-distinct. A WhereLoop that has no columns in the ORDER BY clause + ** is not order-distinct. To be order-distinct is not quite the same as being + ** UNIQUE since a UNIQUE column or index can have multiple rows that + ** are NULL and NULL values are equivalent for the purpose of order-distinct. + ** To be order-distinct, the columns must be UNIQUE and NOT NULL. + ** + ** 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 ); @@ -4606,12 +4611,12 @@ static int wherePathSatisfiesOrderBy( if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; nOrderBy = pOrderBy->nExpr; - if( nOrderBy>60 ) return 0; - isWellOrdered = 1; + if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ + isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; - orderedMask = 0; + orderDistinctMask = 0; pMaskSet = pWInfo->pWC->pMaskSet; - for(iLoop=0; isWellOrdered && obSataLoop[iLoop] : pLast; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; @@ -4623,9 +4628,10 @@ static int wherePathSatisfiesOrderBy( return 0; }else{ 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 ** in the ORDER BY clause. */ @@ -4653,17 +4659,20 @@ static int wherePathSatisfiesOrderBy( ** that are not constrained by == or IN. */ rev = revSet = 0; + distinctColumns = 0; for(j=0; j<=nColumn; j++){ u8 bOnce; /* True to run the ORDER BY search loop */ + /* Skip over == and IS NULL terms */ if( ju.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 - ** j-th column of the index for this WhereLoop + /* Get the column number in the table (iColumn) and sort order + ** (revIdx) for the j-th column of the index. */ if( j=0 + if( isOrderDistinct + && iColumn>=0 && j>=pLoop->u.btree.nEq && pIndex->pTable->aCol[iColumn].notNull==0 ){ - isWellOrdered = 0; + isOrderDistinct = 0; } /* Find the ORDER BY term that corresponds to the j-th column ** of the index and and mark that ORDER BY term off */ bOnce = 1; + isMatch = 0; for(i=0; bOnce && ia[i].pExpr); - if( pOBExpr->op!=TK_COLUMN ) continue; if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ) bOnce = 0; + if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; if( iColumn>=0 ){ @@ -4702,15 +4713,15 @@ static int wherePathSatisfiesOrderBy( if( !pColl ) pColl = db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } - bOnce = 1; + isMatch = 1; break; } - if( bOnce && iwctrlFlags & WHERE_GROUPBY)==0 ){ - /* If we have an ORDER BY clause, we must match the next available - ** column of the ORDER BY */ + /* Make sure the sort order is compatible in an ORDER BY clause. + ** Sort order is irrelevant for a GROUP BY clause. */ if( revSet ){ if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0; }else{ @@ -4721,29 +4732,28 @@ static int wherePathSatisfiesOrderBy( } }else{ /* No match found */ - if( jonError==OE_None ){ - isWellOrdered = 0; - } + if( j==0 || jmaskSelf; + if( isOrderDistinct ){ + orderDistinctMask |= pLoop->maskSelf; for(i=0; ia[i].pExpr; - if( (exprTableUsage(pMaskSet, p)&~orderedMask)==0 ){ + if( (exprTableUsage(pMaskSet, p)&~orderDistinctMask)==0 ){ obSat |= MASKBIT(i); } } } } if( obSat==obDone ) return 1; - if( !isWellOrdered ) return 0; + if( !isOrderDistinct ) return 0; if( isLastLoop ) return 1; return -1; } diff --git a/test/where3.test b/test/where3.test index c8ec8eb169..842f683749 100644 --- a/test/where3.test +++ b/test/where3.test @@ -190,37 +190,37 @@ do_test where3-2.2 { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=bx } -} {tB {} tA * tC * tD *} +} {tB * tA * tC * tD *} do_test where3-2.3 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=bx } -} {tB {} tA * tC * tD *} +} {tB * tA * tC * tD *} do_test where3-2.4 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE apk=cx AND bpk=ax } -} {tC {} tA * tB * tD *} +} {tC * tA * tB * tD *} do_test where3-2.5 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=ax AND bpk=cx } -} {tA {} tC * tB * tD *} +} {tA * tC * tB * tD *} do_test where3-2.6 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE bpk=cx AND apk=bx } -} {tC {} tB * tA * tD *} +} {tC * tB * tA * tD *} do_test where3-2.7 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=cx } -} {tB {} tC * tA * tD *} +} {tB * tC * tA * tD *} # Ticket [13f033c865f878953] # If the outer loop must be a full table scan, do not let ANALYZE trick