diff --git a/manifest b/manifest index 34496b20c1..b9e43c21d7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Changes\stoward\sbeing\sabld\sto\sprocess\sindexes\son\sexpressions.\s\sNot\sthere\syet\s-\s\nthis\scheck-in\sis\sjust\smovement\sin\sthat\sdirection.\s\sSome\stests\sare\sfailing. -D 2015-08-25T00:27:06.624 +C Add\scode\sto\smaintain\sindexes\swith\sexpression\sarguments\sacross\sDELETE,\sINSERT,\nand\sUPDATE\sstatements.\s\sLegacy\stests\spass,\sbut\sthe\snew\scode\spaths\sare\sstill\nlargely\suntested.\s\sThe\squery\splanner\scurrently\smakes\sno\seffort\sto\suse\nexpression\sindexes. +D 2015-08-25T16:57:52.554 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e2218eb228374422969de7b1680eda6864affcef F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -273,7 +273,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 48e14b8aea28dc58baafe3cfcb8889c086b7744a -F src/analyze.c f89727c36f997bd2bf6c5e546c2f51dc94e6f2a4 +F src/analyze.c 3ec61c5142e5fd6f66faf83de93d86d9810d1728 F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395 F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 4d9134dc988a87838c06056c89c0e8c4700a0452 @@ -282,14 +282,14 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c f48b3ef91676c06a90a8832987ecef6b94c931ee F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0 -F src/build.c d9d53c7318117e04cfb79bc498b45f4982092f0c +F src/build.c c249a192b2395363e9ec89ec7060312ea6a0b2ca F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c 8ec787fed4929d8ccdf6b1bc360fccc3e1d2ca58 F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a -F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa -F src/expr.c 650ac7c4f659980a3315e2aaa02a0d71e87f14a5 +F src/delete.c 07ba8cc1def3ed9a316c0073217c48ebff59062b +F src/expr.c 4a52fd29145d94c6f2e355ec67489dc8d309f05e F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 824bea430d3a2b7dbc62806ad54da8fdb8ed9e3f @@ -297,7 +297,7 @@ F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c ad9ebaafdc4438bb0de58cd7d6bc199fb5b6917a +F src/insert.c 602809df9668a8418ea488a59a0bef787f0aec6f F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 92bafa308607dd985ca389a788cd9e0a2b608712 @@ -335,14 +335,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/printf.c 2bc439ff20a4aad0e0ad50a37a67b5eae7d20edc F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c ad9404cfa6f698aa530cca1c86570fa92cb65a12 +F src/resolve.c c4691acf9dca466799a0b07cf7f82d18d557f799 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c da6d1e7a4f1c8d713ed5415b5ed21d82ef465c0f -F src/shell.c b1f91e60918df3a68efad1e3a11696b9a7e23d23 +F src/shell.c 5a08835e85c502978bde35a89d4045833f772876 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h 5e2ce12324eb03b75d5b8a37084550eb66dbef78 +F src/sqliteInt.h 5fe814323e6ea95685206f8764db29dba680c8e8 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -396,7 +396,7 @@ F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 F src/tokenize.c 57cb3720f53f84d811def2069c2b169b6be539a5 F src/treeview.c c15df00728034549ff92d78ae851b44952736d3b F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f -F src/update.c 487747b328b7216bb7f6af0695d6937d5c9e605f +F src/update.c 798196d7693277d359846df7587fc15ee58a563f F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c bc9dd64b5db544218b871b66243871c202b2781f F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 @@ -405,7 +405,7 @@ F src/vdbe.h 7a75045d879118b9d3af7e8b3c108f2f27c51473 F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816 F src/vdbeapi.c bda74ef4b5103d7b4a4be36f936d3cf2b56a7d6f F src/vdbeaux.c af2d86b2b114a106c94fc656503fc5c89594f5af -F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 +F src/vdbeblob.c 1d7b97115e7bbac4c318db416d2ca83fc779544a F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090 F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 @@ -772,7 +772,7 @@ F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32 F test/incrvacuum2.test 676c41428765d58f1da7dbe659ef27726d3d30ac F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635 -F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee +F test/index.test fe3c7a1aad82af92623747e9c3f3aa94ccd51238 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 @@ -941,7 +941,7 @@ F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 F test/rollbackfault.test 6a004f71087cc399296cffbb5429ea6da655ae65 F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 -F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 +F test/rowid.test 09fcded0c96fbc0ed11fb75faa3b0bad32cb011a F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d @@ -1379,10 +1379,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P bdaf66465b6b1bdad10c08d9527b98e7000a41e4 -R 3888db9ab5ffaaee9ce833f48e49ed84 -T *branch * index-expr -T *sym-index-expr * -T -sym-trunk * +P 0ad0f8d77d8f95ca2ffb7745d18219f5e87dc89c +R 457a1c92538887efc6aebf70344c3622 U drh -Z 80441a5a4abd6f0065befff78e2e1eff +Z d2f3b8f04887de8a5bca7c4f4441bcbc diff --git a/manifest.uuid b/manifest.uuid index 712ea9a3fd..a43b7e84ea 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0ad0f8d77d8f95ca2ffb7745d18219f5e87dc89c \ No newline at end of file +efaabdb71626bdc03768e87e186c72f6f3da75b2 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 59518cdc3f..3e531bd722 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1186,6 +1186,7 @@ static void analyzeOneTable( regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; j<pPk->nKeyCol; j++){ k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); + assert( k>=0 && k<pTab->nCol ); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName)); } @@ -1235,12 +1236,10 @@ static void analyzeOneTable( ** be taken */ VdbeCoverageNeverTaken(v); #ifdef SQLITE_ENABLE_STAT3 - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, - pIdx->aiColumn[0], regSample); + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample); #else for(i=0; i<nCol; i++){ - i16 iCol = pIdx->aiColumn[i]; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i); + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample); #endif diff --git a/src/build.c b/src/build.c index 64bfe1b061..fc50fdd822 100644 --- a/src/build.c +++ b/src/build.c @@ -443,6 +443,7 @@ static void freeIndex(sqlite3 *db, Index *p){ sqlite3DeleteIndexSamples(db, p); #endif sqlite3ExprDelete(db, p->pPartIdxWhere); + sqlite3ExprListDelete(db, p->aColExpr); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, p->azColl); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 @@ -3101,32 +3102,47 @@ Index *sqlite3CreateIndex( sortOrderMask = 0; /* Ignore DESC */ } - /* Scan the names of the columns of the table to be indexed and - ** load the column indices into the Index structure. Report an error - ** if any column is not found. + /* Analyze the list of expressions that form the terms of the index and + ** report any errors. In the common case where the expression is exactly + ** a table column, store that column in aiColumn[]. For general expressions, + ** populate pIndex->aColExpr and store -2 in aiColumn[]. ** - ** TODO: Add a test to make sure that the same column is not named - ** more than once within the same index. Only the first instance of - ** the column will ever be used by the optimizer. Note that using the - ** same column more than once cannot be an error because that would - ** break backwards compatibility - it needs to be a warning. + ** TODO: Issue a warning if two or more columns of the index are identical. + ** TODO: Issue a warning if the table primary key is used as part of the + ** index key. */ for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){ - Expr *pCExpr; - int requestedSortOrder; + Expr *pCExpr; /* The i-th index expression */ + int requestedSortOrder; /* ASC or DESC on the i-th expression */ char *zColl; /* Collation sequence name */ sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); if( pParse->nErr ) goto exit_create_index; pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); if( pCExpr->op!=TK_COLUMN ){ - sqlite3ErrorMsg(pParse, "indexes on expressions not yet supported"); - continue; + if( pTab==pParse->pNewTable ){ + sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and " + "UNIQUE constraints"); + goto exit_create_index; + } + if( pIndex->aColExpr==0 ){ + pIndex->aColExpr = sqlite3ExprListDup(db, pList, 0); + } + j = -2; + pIndex->aiColumn[i] = -2; + if( sqlite3ExprCanBeNull(pList->a[i].pExpr) ){ + pIndex->uniqNotNull = 1; + } + }else{ + j = pCExpr->iColumn; + assert( j<=0x7fff ); + if( j<0 ){ + j = pTab->iPKey; + }else if( pTab->aCol[j].notNull==0 ){ + pIndex->uniqNotNull = 0; + } + pIndex->aiColumn[i] = (i16)j; } - j = pCExpr->iColumn; - assert( j<=0x7fff ); - if( j<0 ) j = pTab->iPKey; - pIndex->aiColumn[i] = (i16)j; zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; @@ -3147,11 +3163,16 @@ Index *sqlite3CreateIndex( pIndex->azColl[i] = zColl; requestedSortOrder = pListItem->sortOrder & sortOrderMask; pIndex->aSortOrder[i] = (u8)requestedSortOrder; - if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0; } + + /* Append the table key to the end of the index. For WITHOUT ROWID + ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For + ** normal tables (when pPk==0) this will be the rowid. + */ if( pPk ){ for(j=0; j<pPk->nKeyCol; j++){ int x = pPk->aiColumn[j]; + assert( x>=0 ); if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ pIndex->nColumn--; }else{ @@ -3202,6 +3223,7 @@ Index *sqlite3CreateIndex( for(k=0; k<pIdx->nKeyCol; k++){ const char *z1; const char *z2; + assert( pIdx->aiColumn[k]>=0 ); if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; z1 = pIdx->azColl[k]; z2 = pIndex->azColl[k]; @@ -4093,7 +4115,9 @@ void sqlite3UniqueConstraint( sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); for(j=0; j<pIdx->nKeyCol; j++){ - char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName; + char *zCol; + assert( pIdx->aiColumn[j]>=0 ); + zCol = pTab->aCol[pIdx->aiColumn[j]].zName; if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); sqlite3StrAccumAppendAll(&errMsg, pTab->zName); sqlite3StrAccumAppend(&errMsg, ".", 1); diff --git a/src/delete.c b/src/delete.c index 369cdaf6fe..cff922cbb3 100644 --- a/src/delete.c +++ b/src/delete.c @@ -411,6 +411,7 @@ void sqlite3DeleteFrom( /* Extract the rowid or primary key for the current row */ if( pPk ){ for(i=0; i<nPk; i++){ + assert( pPk->aiColumn[i]>=(-1) ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i], iPk+i); } @@ -789,14 +790,13 @@ int sqlite3GenerateIndexKey( ){ Vdbe *v = pParse->pVdbe; int j; - Table *pTab = pIdx->pTable; int regBase; int nCol; if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); - pParse->iPartIdxTab = iDataCur; + pParse->iSelfTab = iDataCur; sqlite3ExprCachePush(pParse); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); @@ -808,9 +808,14 @@ int sqlite3GenerateIndexKey( regBase = sqlite3GetTempRange(pParse, nCol); if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; for(j=0; j<nCol; j++){ - if( pPrior && pPrior->aiColumn[j]==pIdx->aiColumn[j] ) continue; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j], - regBase+j); + if( pPrior + && pPrior->aiColumn[j]==pIdx->aiColumn[j] + && pPrior->aiColumn[j]>=(-1) + ){ + /* This column was already computed by the previous index */ + continue; + } + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); /* If the column affinity is REAL but the number is an integer, then it ** might be stored in the table as an integer (using a compact ** representation) then converted to REAL by an OP_RealAffinity opcode. diff --git a/src/expr.c b/src/expr.c index 1aebef6b16..34c382a192 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2432,6 +2432,28 @@ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){ } } +/* Generate code that will load into register regOut a value that is +** appropriate for the iIdxCol-th column of index pIdx. +*/ +void sqlite3ExprCodeLoadIndexColumn( + Parse *pParse, /* The parsing context */ + Index *pIdx, /* The index whose column is to be loaded */ + int iTabCur, /* Cursor pointing to a table row */ + int iIdxCol, /* The column of the index to be loaded */ + int regOut /* Store the index column value in this register */ +){ + i16 iTabCol = pIdx->aiColumn[iIdxCol]; + if( iTabCol>=(-1) ){ + sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, + iTabCol, regOut); + return; + } + assert( pIdx->aColExpr ); + assert( pIdx->aColExpr->nExpr>iIdxCol ); + pParse->iSelfTab = iTabCur; + sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); +} + /* ** Generate code to extract the value of the iCol-th column of a table. */ @@ -2617,8 +2639,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ inReg = pExpr->iColumn + pParse->ckBase; break; }else{ - /* Deleting from a partial index */ - iTab = pParse->iPartIdxTab; + /* Coding an expression that is part of an index where column names + ** in the index refer to the table to which the index belongs */ + iTab = pParse->iSelfTab; } } inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, diff --git a/src/insert.c b/src/insert.c index 839599438c..ae24991301 100644 --- a/src/insert.c +++ b/src/insert.c @@ -89,7 +89,15 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ } for(n=0; n<pIdx->nColumn; n++){ i16 x = pIdx->aiColumn[n]; - pIdx->zColAff[n] = x<0 ? SQLITE_AFF_INTEGER : pTab->aCol[x].affinity; + if( x>=0 ){ + pIdx->zColAff[n] = pTab->aCol[x].affinity; + }else if( x==(-1) ){ + pIdx->zColAff[n] = SQLITE_AFF_INTEGER; + }else{ + assert( x==(-2) ); + assert( pIdx->aColExpr!=0 ); + pIdx->zColAff[n] = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); + } } pIdx->zColAff[n] = 0; } @@ -1395,15 +1403,22 @@ void sqlite3GenerateConstraintChecks( for(i=0; i<pIdx->nColumn; i++){ int iField = pIdx->aiColumn[i]; int x; - if( iField<0 || iField==pTab->iPKey ){ - if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ - x = regNewData; - regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; + if( iField==(-2) ){ + pParse->ckBase = regNewData+1; + sqlite3ExprCode(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); + pParse->ckBase = 0; + VdbeComment((v, "%s column %d", pIdx->zName, i)); }else{ - x = iField + regNewData + 1; + if( iField==(-1) || iField==pTab->iPKey ){ + if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ + x = regNewData; + regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; + }else{ + x = iField + regNewData + 1; + } + sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); + VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); } - sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); - VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); @@ -1724,6 +1739,13 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ return 0; /* Different columns indexed */ } + if( pSrc->aiColumn[i]==(-2) ){ + assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 ); + if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr, + pDest->aColExpr->a[i].pExpr, -1)!=0 ){ + return 0; /* Different expressions in the index */ + } + } if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){ return 0; /* Different sort orders */ } diff --git a/src/resolve.c b/src/resolve.c index 979596941d..a85543f09e 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -654,7 +654,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* if( pSrcList==0 ) break; */ notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr, 0); - notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1); + /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/ pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; diff --git a/src/shell.c b/src/shell.c index c289998a7b..da7f78e10d 100644 --- a/src/shell.c +++ b/src/shell.c @@ -4252,8 +4252,8 @@ static int process_input(ShellState *p, FILE *in){ fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); errCnt++; } - free(zSql); } + free(zSql); free(zLine); return errCnt>0; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2358795148..73bf83d3de 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1871,6 +1871,7 @@ struct Index { u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ + ExprList *aColExpr; /* Column expressions */ int tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ @@ -2661,7 +2662,7 @@ struct Parse { int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */ int ckBase; /* Base register of data during check constraints */ - int iPartIdxTab; /* Table corresponding to a partial index */ + int iSelfTab; /* Table of an index whose exprs are being coded */ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */ int nLabel; /* Number of labels used */ @@ -3362,6 +3363,7 @@ int sqlite3WhereIsSorted(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*); int sqlite3WhereBreakLabel(WhereInfo*); int sqlite3WhereOkOnePass(WhereInfo*, int*); +void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); diff --git a/src/update.c b/src/update.c index f8347448a1..cc9b690779 100644 --- a/src/update.c +++ b/src/update.c @@ -272,7 +272,9 @@ void sqlite3Update( /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold - ** the key for accessing each index. + ** the key for accessing each index. + ** + ** FIXME: Be smarter about omitting indexes that use expressions. */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; @@ -281,7 +283,8 @@ void sqlite3Update( }else{ reg = 0; for(i=0; i<pIdx->nKeyCol; i++){ - if( aXRef[pIdx->aiColumn[i]]>=0 ){ + i16 iIdxCol = pIdx->aiColumn[i]; + if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){ reg = ++pParse->nMem; break; } @@ -381,6 +384,7 @@ void sqlite3Update( if( pWInfo==0 ) goto update_cleanup; okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); for(i=0; i<nPk; i++){ + assert( pPk->aiColumn[i]>=(-1) ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i], iPk+i); } diff --git a/src/vdbeblob.c b/src/vdbeblob.c index ea01f5ce80..2cdc3edb00 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -247,7 +247,8 @@ int sqlite3_blob_open( for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int j; for(j=0; j<pIdx->nKeyCol; j++){ - if( pIdx->aiColumn[j]==iCol ){ + /* FIXME: Be smarter about indexes that use expressions */ + if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==(-2) ){ zFault = "indexed"; } } diff --git a/test/index.test b/test/index.test index 59c0ea6f90..712f42c3a4 100644 --- a/test/index.test +++ b/test/index.test @@ -56,11 +56,11 @@ do_test index-2.1 { # Try adding an index on a column of a table where the table # exists but the column does not. # -do_test index-2.1 { +do_test index-2.1b { execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)} set v [catch {execsql {CREATE INDEX index1 ON test1(f4)}} msg] lappend v $msg -} {1 {table test1 has no column named f4}} +} {1 {no such column: f4}} # Try an index with some columns that match and others that do now. # @@ -68,7 +68,7 @@ do_test index-2.2 { set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg] execsql {DROP TABLE test1} lappend v $msg -} {1 {table test1 has no column named f4}} +} {1 {no such column: f4}} # Try creating a bunch of indices on the same table # diff --git a/test/rowid.test b/test/rowid.test index b00b5287fd..21696f6839 100644 --- a/test/rowid.test +++ b/test/rowid.test @@ -144,6 +144,7 @@ do_test rowid-2.8 { execsql {SELECT x FROM t1 ORDER BY x} } {1 3 5 7 9} +if 0 { # we can now.... # We cannot index by ROWID # do_test rowid-2.9 { @@ -162,6 +163,7 @@ do_test rowid-2.12 { set v [catch {execsql {CREATE INDEX idxt1 ON t1(x, rowid)}} msg] lappend v $msg } {1 {table t1 has no column named rowid}} +} # Columns defined in the CREATE statement override the buildin ROWID # column names.