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

Fix handling of covering indexes that use virtual columns.

FossilOrigin-Name: e0f7e321eca91c49102649f70728de69347cbd7b16599b854203c24cfdc348e6
This commit is contained in:
drh
2019-10-24 20:29:25 +00:00
parent 035f6d909f
commit c7476735c9
5 changed files with 72 additions and 19 deletions

View File

@@ -1,5 +1,5 @@
C Do\snot\sallow\sALTER\sTABLE\sADD\sCOLUMN\sfor\sa\sSTORED\scolumn. C Fix\shandling\sof\scovering\sindexes\sthat\suse\svirtual\scolumns.
D 2019-10-24T01:04:10.370 D 2019-10-24T20:29:25.035
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5
F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484
F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437
F src/build.c f7070af66656b75be79a79a8ac720f4f0f8b48ba56298f2d9bf0f982d07ed949 F src/build.c 0c9704f95817aa585fdad2668c611280d0b62bc4c1c836cd1c797ba96879a7d6
F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181 F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251
@@ -530,7 +530,7 @@ F src/shell.c.in 3093bdf5eedd91da08f0268f1442aa510a60798c9441868149ddbecdf8bcaa7
F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31
F src/sqliteInt.h f8609e5a04eec2e89f35520b31c0b506ef905a3485f09b4dc4e20583743cee31 F src/sqliteInt.h 5b2d25ba23135ece06886d82f60d9a16869506592e5950f3c09257b3b5d28d5c
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -613,7 +613,7 @@ F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd
F src/where.c 6ff3ef076485dd71efbbabcc7ddc0473c04a9bdcb524128939757b002466f2d1 F src/where.c 6ff3ef076485dd71efbbabcc7ddc0473c04a9bdcb524128939757b002466f2d1
F src/whereInt.h 4a296fd4fa79fdcbc2b5e8c1b898901617655811223e1082b899c23ecb092217 F src/whereInt.h 4a296fd4fa79fdcbc2b5e8c1b898901617655811223e1082b899c23ecb092217
F src/wherecode.c d96190c0b536339375846048ad3c41758b4bd6baaf8f8f350da5911d42bc4a61 F src/wherecode.c c491ae0ce1de97bc4eea566350a2d1e7c2c5fcf97b9d4c89593c4f068e21a30d
F src/whereexpr.c 0705f608f6dbbd4e95d440528d6c760b91b6f402ba4eb8b8d964c110e2010780 F src/whereexpr.c 0705f608f6dbbd4e95d440528d6c760b91b6f402ba4eb8b8d964c110e2010780
F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041 F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 30065716878d4058e75eb510b0b27b68e5193d04625eb173210de8061f20f499 P 42fc08bc1528a34a603c2c085b515766a8d33ae7ea0350a52b0ca24b94ebcbc5
R 7202e3e1ab0c99bc839229fb4e803cbe R 6a9e8fc570824aa923ac6838bd994212
U drh U drh
Z 98506792ef3b33ac52584457b01d83d1 Z b5f3ce7a354e5714077f87bfe3d7f12c

View File

@@ -1 +1 @@
42fc08bc1528a34a603c2c085b515766a8d33ae7ea0350a52b0ca24b94ebcbc5 e0f7e321eca91c49102649f70728de69347cbd7b16599b854203c24cfdc348e6

View File

@@ -1923,15 +1923,24 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
** high-order bit of colNotIdxed is always 1. All unindexed columns ** high-order bit of colNotIdxed is always 1. All unindexed columns
** of the table have a 1. ** of the table have a 1.
** **
** 2019-10-24: For the purpose of this computation, virtual columns are
** not considered to be covered by the index, even if they are in the
** index, because we do not trust the logic in whereIndexExprTrans() to be
** able to find all instances of a reference to the indexed table column
** and convert them into references to the index. Hence we always want
** the actual table at hand in order to recompute the virtual column, if
** necessary.
**
** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask ** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask
** to determine if the index is covering index. ** to determine if the index is covering index.
*/ */
static void recomputeColumnsNotIndexed(Index *pIdx){ static void recomputeColumnsNotIndexed(Index *pIdx){
Bitmask m = 0; Bitmask m = 0;
int j; int j;
Table *pTab = pIdx->pTable;
for(j=pIdx->nColumn-1; j>=0; j--){ for(j=pIdx->nColumn-1; j>=0; j--){
int x = pIdx->aiColumn[j]; int x = pIdx->aiColumn[j];
if( x>=0 ){ if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){
testcase( x==BMS-1 ); testcase( x==BMS-1 );
testcase( x==BMS-2 ); testcase( x==BMS-2 );
if( x<BMS-1 ) m |= MASKBIT(x); if( x<BMS-1 ) m |= MASKBIT(x);
@@ -3617,9 +3626,14 @@ void sqlite3CreateIndex(
assert( j<=0x7fff ); assert( j<=0x7fff );
if( j<0 ){ if( j<0 ){
j = pTab->iPKey; j = pTab->iPKey;
}else if( pTab->aCol[j].notNull==0 ){ }else{
if( pTab->aCol[j].notNull==0 ){
pIndex->uniqNotNull = 0; pIndex->uniqNotNull = 0;
} }
if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
pIndex->bHasVCol = 1;
}
}
pIndex->aiColumn[i] = (i16)j; pIndex->aiColumn[i] = (i16)j;
} }
zColl = 0; zColl = 0;

View File

@@ -2295,6 +2295,7 @@ struct Index {
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
#ifdef SQLITE_ENABLE_STAT4 #ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */ int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */

View File

@@ -1106,6 +1106,7 @@ typedef struct IdxExprTrans {
int iTabCur; /* The cursor of the corresponding table */ int iTabCur; /* The cursor of the corresponding table */
int iIdxCur; /* The cursor for the index */ int iIdxCur; /* The cursor for the index */
int iIdxCol; /* The column for the index */ int iIdxCol; /* The column for the index */
int iTabCol; /* The column for the table */
} IdxExprTrans; } IdxExprTrans;
/* The walker node callback used to transform matching expressions into /* The walker node callback used to transform matching expressions into
@@ -1128,10 +1129,30 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
} }
} }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
/* A walker node callback that translates a column reference to a table
** into a corresponding column reference of an index.
*/
static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
if( pExpr->op==TK_COLUMN ){
IdxExprTrans *pX = p->u.pIdxTrans;
if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
pExpr->iTable = pX->iIdxCur;
pExpr->iColumn = pX->iIdxCol;
}
}
return WRC_Continue;
}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
/* /*
** For an indexes on expression X, locate every instance of expression X ** For an indexes on expression X, locate every instance of expression X
** in pExpr and change that subexpression into a reference to the appropriate ** in pExpr and change that subexpression into a reference to the appropriate
** column of the index. ** column of the index.
**
** 2019-10-24: Updated to also translate references to a VIRTUAL column in
** the table into references to the corresponding (stored) column of the
** index.
*/ */
static void whereIndexExprTrans( static void whereIndexExprTrans(
Index *pIdx, /* The Index */ Index *pIdx, /* The Index */
@@ -1141,20 +1162,35 @@ static void whereIndexExprTrans(
){ ){
int iIdxCol; /* Column number of the index */ int iIdxCol; /* Column number of the index */
ExprList *aColExpr; /* Expressions that are indexed */ ExprList *aColExpr; /* Expressions that are indexed */
Table *pTab;
Walker w; Walker w;
IdxExprTrans x; IdxExprTrans x;
aColExpr = pIdx->aColExpr; aColExpr = pIdx->aColExpr;
if( aColExpr==0 ) return; /* Not an index on expressions */ if( aColExpr==0 && !pIdx->bHasVCol ){
/* The index does not reference any expressions or virtual columns
** so no translations are needed. */
return;
}
pTab = pIdx->pTable;
memset(&w, 0, sizeof(w)); memset(&w, 0, sizeof(w));
w.xExprCallback = whereIndexExprTransNode;
w.u.pIdxTrans = &x; w.u.pIdxTrans = &x;
x.iTabCur = iTabCur; x.iTabCur = iTabCur;
x.iIdxCur = iIdxCur; x.iIdxCur = iIdxCur;
for(iIdxCol=0; iIdxCol<aColExpr->nExpr; iIdxCol++){ for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue; i16 iRef = pIdx->aiColumn[iIdxCol];
if( iRef==XN_EXPR ){
assert( aColExpr->a[iIdxCol].pExpr!=0 ); assert( aColExpr->a[iIdxCol].pExpr!=0 );
x.iIdxCol = iIdxCol;
x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
w.xExprCallback = whereIndexExprTransNode;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
}else if( iRef>=0 && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0 ){
x.iTabCol = iRef;
w.xExprCallback = whereIndexExprTransColumn;
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
}else{
continue;
}
x.iIdxCol = iIdxCol;
sqlite3WalkExpr(&w, pWInfo->pWhere); sqlite3WalkExpr(&w, pWInfo->pWhere);
sqlite3WalkExprList(&w, pWInfo->pOrderBy); sqlite3WalkExprList(&w, pWInfo->pOrderBy);
sqlite3WalkExprList(&w, pWInfo->pResultSet); sqlite3WalkExprList(&w, pWInfo->pResultSet);
@@ -1835,7 +1871,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* If pIdx is an index on one or more expressions, then look through /* If pIdx is an index on one or more expressions, then look through
** all the expressions in pWInfo and try to transform matching expressions ** all the expressions in pWInfo and try to transform matching expressions
** into reference to index columns. ** into reference to index columns. Also attempt to translate references
** to virtual columns in the table into references to (stored) columns
** of the index.
** **
** Do not do this for the RHS of a LEFT JOIN. This is because the ** Do not do this for the RHS of a LEFT JOIN. This is because the
** expression may be evaluated after OP_NullRow has been executed on ** expression may be evaluated after OP_NullRow has been executed on