From: dan Date: Wed, 17 Feb 2016 20:06:12 +0000 (+0000) Subject: Schemalint changes: Avoid creating candidate indexes if a compatible index exists... X-Git-Tag: version-3.22.0~147^2~53 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1c93844dd30973b13907a837876e7aa161e4bbed;p=thirdparty%2Fsqlite.git Schemalint changes: Avoid creating candidate indexes if a compatible index exists. Do not quote identifiers that do not require it. FossilOrigin-Name: cf0f7eeb4f6490b1e3f05b45e83b87cd64640846 --- diff --git a/manifest b/manifest index f1eaa8735a..ff57fedd26 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sfurther\sissues\sin\sschemalint. -D 2016-02-16T18:37:37.844 +C Schemalint\schanges:\sAvoid\screating\scandidate\sindexes\sif\sa\scompatible\sindex\sexists.\sDo\snot\squote\sidentifiers\sthat\sdo\snot\srequire\sit. +D 2016-02-17T20:06:12.566 F Makefile.in dac2776c84e0d533b158a9af6e57e05c4a6b19f3 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc b0493f10caddb8adf992a4e6f1943141fc7c6816 @@ -350,7 +350,7 @@ F src/resolve.c 9f7ce3a3c087afb7597b7c916c99126ff3f12f0c F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e F src/select.c ff80004a9a6ece891a8d9327a88e7b6e2588ee6d F src/shell.c 2cde87e03712204231167c4a6c61b0eb5129e105 -F src/shell_indexes.c 27d3b064078066c9a284a93149c4a151821f55bf +F src/shell_indexes.c 6cc207072469f1ded8c3bb9de1d4b6590a28abb8 F src/sqlite.h.in c7db059d3b810b70b83d9ed1436fa813eba22462 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d @@ -1430,7 +1430,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 58d4cf26e15f90463148bec63d6ab514ffbbae60 -R f221e3cac7f52c2c660e427ee329aa03 +P 73a7f010937828c5195a198604f976e8458cef73 +R 3a9a4af7276c9c00e5b2666c0bfe324e U dan -Z 8b18cd934aae857f866e3f00c12cba6f +Z 82976e1002963ffa4a1c502f357a9ae9 diff --git a/manifest.uuid b/manifest.uuid index 4b3aa263c2..2e9ca33ba0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -73a7f010937828c5195a198604f976e8458cef73 \ No newline at end of file +cf0f7eeb4f6490b1e3f05b45e83b87cd64640846 \ No newline at end of file diff --git a/src/shell_indexes.c b/src/shell_indexes.c index 33f872efd7..54b59cd421 100644 --- a/src/shell_indexes.c +++ b/src/shell_indexes.c @@ -33,6 +33,7 @@ struct IdxConstraint { int bRange; /* True for range, false for eq */ int iCol; /* Constrained table column */ i64 depmask; /* Dependency mask */ + int bFlag; /* Used by idxFindCompatible() */ IdxConstraint *pNext; /* Next constraint in pEq or pRange list */ IdxConstraint *pLink; /* See above */ }; @@ -413,53 +414,20 @@ static int idxCreateTables( int rc = SQLITE_OK; IdxScan *pIter; for(pIter=pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){ - int nPk = 0; - char *zCols = 0; - char *zPk = 0; - char *zCreate = 0; - int iCol; - rc = idxGetTableInfo(db, pIter, pzErrmsg); - - for(iCol=0; rc==SQLITE_OK && iColpTable->nCol; iCol++){ - IdxColumn *pCol = &pIter->pTable->aCol[iCol]; - if( pCol->iPk>nPk ) nPk = pCol->iPk; - zCols = sqlite3_mprintf("%z%s%Q", zCols, (zCols?", ":""), pCol->zName); - if( zCols==0 ) rc = SQLITE_NOMEM; - } - - for(iCol=1; rc==SQLITE_OK && iCol<=nPk; iCol++){ - int j; - for(j=0; jpTable->nCol; j++){ - IdxColumn *pCol = &pIter->pTable->aCol[j]; - if( pCol->iPk==iCol ){ - zPk = sqlite3_mprintf("%z%s%Q", zPk, (zPk?", ":""), pCol->zName); - if( zPk==0 ) rc = SQLITE_NOMEM; - break; - } - } - } - if( rc==SQLITE_OK ){ - if( zPk ){ - zCreate = sqlite3_mprintf("CREATE TABLE %Q(%s, PRIMARY KEY(%s))", - pIter->zTable, zCols, zPk - ); - }else{ - zCreate = sqlite3_mprintf("CREATE TABLE %Q(%s)", pIter->zTable, zCols); + int rc2; + sqlite3_stmt *pSql = 0; + rc = idxPrintfPrepareStmt(db, &pSql, pzErrmsg, + "SELECT sql FROM sqlite_master WHERE tbl_name = %Q", pIter->zTable + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ + const char *zSql = (const char*)sqlite3_column_text(pSql, 0); + rc = sqlite3_exec(dbm, zSql, 0, 0, pzErrmsg); } - if( zCreate==0 ) rc = SQLITE_NOMEM; + rc2 = sqlite3_finalize(pSql); + if( rc==SQLITE_OK ) rc = rc2; } - - if( rc==SQLITE_OK ){ -#if 0 - printf("/* %s */\n", zCreate); -#endif - rc = sqlite3_exec(dbm, zCreate, 0, 0, pzErrmsg); - } - sqlite3_free(zCols); - sqlite3_free(zPk); - sqlite3_free(zCreate); } return rc; } @@ -501,6 +469,20 @@ static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){ return zRet; } +static int idxIdentifierRequiresQuotes(const char *zId){ + int i; + for(i=0; zId[i]; i++){ + if( !(zId[i]=='_') + && !(zId[i]>='0' && zId[i]<='9') + && !(zId[i]>='a' && zId[i]<='z') + && !(zId[i]>='A' && zId[i]<='Z') + ){ + return 1; + } + } + return 0; +} + static char *idxAppendColDefn( int *pRc, char *zIn, @@ -510,13 +492,100 @@ static char *idxAppendColDefn( char *zRet = zIn; IdxColumn *p = &pTab->aCol[pCons->iCol]; if( zRet ) zRet = idxAppendText(pRc, zRet, ", "); - zRet = idxAppendText(pRc, zRet, "%Q", p->zName); + + if( idxIdentifierRequiresQuotes(p->zName) ){ + zRet = idxAppendText(pRc, zRet, "%Q", p->zName); + }else{ + zRet = idxAppendText(pRc, zRet, "%s", p->zName); + } + if( sqlite3_stricmp(p->zColl, pCons->zColl) ){ - zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl); + if( idxIdentifierRequiresQuotes(pCons->zColl) ){ + zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl); + }else{ + zRet = idxAppendText(pRc, zRet, " COLLATE %s", pCons->zColl); + } } return zRet; } +/* +** Search database dbm for an index compatible with the one idxCreateFromCons() +** would create from arguments pScan, pEq and pTail. If no error occurs and +** such an index is found, return non-zero. Or, if no such index is found, +** return zero. +** +** If an error occurs, set *pRc to an SQLite error code and return zero. +*/ +static int idxFindCompatible( + int *pRc, /* OUT: Error code */ + sqlite3* dbm, /* Database to search */ + IdxScan *pScan, /* Scan for table to search for index on */ + IdxConstraint *pEq, /* List of == constraints */ + IdxConstraint *pTail /* List of range constraints */ +){ + const char *zTbl = pScan->zTable; + sqlite3_stmt *pIdxList = 0; + IdxConstraint *pIter; + int nEq = 0; /* Number of elements in pEq */ + int rc, rc2; + + /* Count the elements in list pEq */ + for(pIter=pEq; pIter; pIter=pIter->pNext) nEq++; + + rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl); + while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){ + int bMatch = 1; + IdxConstraint *pT = pTail; + sqlite3_stmt *pInfo = 0; + const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1); + + /* Zero the IdxConstraint.bFlag values in the pEq list */ + for(pIter=pEq; pIter; pIter=pIter->pNext) pIter->bFlag = 0; + + rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx); + while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){ + int iIdx = sqlite3_column_int(pInfo, 0); + int iCol = sqlite3_column_int(pInfo, 1); + const char *zColl = (const char*)sqlite3_column_text(pInfo, 4); + + if( iIdxpNext){ + if( pIter->bFlag ) continue; + if( pIter->iCol!=iCol ) continue; + if( sqlite3_stricmp(pIter->zColl, zColl) ) continue; + pIter->bFlag = 1; + break; + } + if( pIter==0 ){ + bMatch = 0; + break; + } + }else{ + if( pT ){ + if( pT->iCol!=iCol || sqlite3_stricmp(pT->zColl, zColl) ){ + bMatch = 0; + break; + } + pT = pT->pLink; + } + } + } + rc2 = sqlite3_finalize(pInfo); + if( rc==SQLITE_OK ) rc = rc2; + + if( rc==SQLITE_OK && bMatch ){ + sqlite3_finalize(pIdxList); + return 1; + } + } + rc2 = sqlite3_finalize(pIdxList); + if( rc==SQLITE_OK ) rc = rc2; + + *pRc = rc; + return 0; +} + static int idxCreateFromCons( sqlite3 *dbm, IdxScan *pScan, @@ -524,12 +593,13 @@ static int idxCreateFromCons( IdxConstraint *pTail ){ int rc = SQLITE_OK; - if( pEq || pTail ){ + if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){ IdxTable *pTab = pScan->pTable; char *zCols = 0; char *zIdx = 0; IdxConstraint *pCons; int h = 0; + const char *zFmt; for(pCons=pEq; pCons; pCons=pCons->pLink){ zCols = idxAppendColDefn(&rc, zCols, pTab, pCons); @@ -545,9 +615,12 @@ static int idxCreateFromCons( h += ((h<<3) + zCols[i]); } - zIdx = sqlite3_mprintf("CREATE INDEX IF NOT EXISTS " - "'%q_idx_%08x' ON %Q(%s)", pScan->zTable, h, pScan->zTable, zCols - ); + if( idxIdentifierRequiresQuotes(pScan->zTable) ){ + zFmt = "CREATE INDEX '%q_idx_%08x' ON %Q(%s)"; + }else{ + zFmt = "CREATE INDEX %s_idx_%08x ON %s(%s)"; + } + zIdx = sqlite3_mprintf(zFmt, pScan->zTable, h, pScan->zTable, zCols); if( !zIdx ){ rc = SQLITE_NOMEM; }else{ @@ -665,6 +738,12 @@ static int idxCreateCandidates( } static void idxScanFree(IdxScan *pScan){ + IdxScan *pIter; + IdxScan *pNext; + for(pIter=pScan; pIter; pIter=pNext){ + pNext = pIter->pNextScan; + + } } int idxFindIndexes( @@ -796,12 +875,14 @@ int shellIndexesCommand( rc = idxCreateCandidates(dbm, ctx.pScan, pzErrmsg); } - /* Create candidate indexes within the in-memory database file */ + /* Figure out which of the candidate indexes are preferred by the query + ** planner and report the results to the user. */ if( rc==SQLITE_OK ){ rc = idxFindIndexes(dbm, zSql, xOut, pOutCtx, pzErrmsg); } idxScanFree(ctx.pScan); + sqlite3_finalize(ctx.pInsertMask); sqlite3_close(dbm); return rc; }