mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-16 23:02:26 +03:00
Have the schemalint output distinguish between existing and recommended indexes.
FossilOrigin-Name: 4ab3df25f1fee7c8fea19d0c64b3e0e4d3b9c3cf
This commit is contained in:
12
manifest
12
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Schemalint\schanges:\sAvoid\screating\scandidate\sindexes\sif\sa\scompatible\sindex\sexists.\sDo\snot\squote\sidentifiers\sthat\sdo\snot\srequire\sit.
|
C Have\sthe\sschemalint\soutput\sdistinguish\sbetween\sexisting\sand\srecommended\sindexes.
|
||||||
D 2016-02-17T20:06:12.566
|
D 2016-02-18T19:10:02.440
|
||||||
F Makefile.in dac2776c84e0d533b158a9af6e57e05c4a6b19f3
|
F Makefile.in dac2776c84e0d533b158a9af6e57e05c4a6b19f3
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc b0493f10caddb8adf992a4e6f1943141fc7c6816
|
F Makefile.msc b0493f10caddb8adf992a4e6f1943141fc7c6816
|
||||||
@@ -350,7 +350,7 @@ F src/resolve.c 9f7ce3a3c087afb7597b7c916c99126ff3f12f0c
|
|||||||
F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
|
F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
|
||||||
F src/select.c ff80004a9a6ece891a8d9327a88e7b6e2588ee6d
|
F src/select.c ff80004a9a6ece891a8d9327a88e7b6e2588ee6d
|
||||||
F src/shell.c 2cde87e03712204231167c4a6c61b0eb5129e105
|
F src/shell.c 2cde87e03712204231167c4a6c61b0eb5129e105
|
||||||
F src/shell_indexes.c 6cc207072469f1ded8c3bb9de1d4b6590a28abb8
|
F src/shell_indexes.c 277eb75b8cfb3c2bcf76e062baaa419779f824e7
|
||||||
F src/sqlite.h.in c7db059d3b810b70b83d9ed1436fa813eba22462
|
F src/sqlite.h.in c7db059d3b810b70b83d9ed1436fa813eba22462
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
|
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
|
||||||
@@ -1430,7 +1430,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P 73a7f010937828c5195a198604f976e8458cef73
|
P cf0f7eeb4f6490b1e3f05b45e83b87cd64640846
|
||||||
R 3a9a4af7276c9c00e5b2666c0bfe324e
|
R f54b8a1f9b5e206798931d383b1eb3a6
|
||||||
U dan
|
U dan
|
||||||
Z 82976e1002963ffa4a1c502f357a9ae9
|
Z 5c18fceb59d8462f5aec79ee219a18a2
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
cf0f7eeb4f6490b1e3f05b45e83b87cd64640846
|
4ab3df25f1fee7c8fea19d0c64b3e0e4d3b9c3cf
|
||||||
@@ -98,12 +98,14 @@ struct IdxScan {
|
|||||||
** Context object passed to idxWhereInfo()
|
** Context object passed to idxWhereInfo()
|
||||||
*/
|
*/
|
||||||
struct IdxContext {
|
struct IdxContext {
|
||||||
|
char **pzErrmsg;
|
||||||
IdxWhere *pCurrent; /* Current where clause */
|
IdxWhere *pCurrent; /* Current where clause */
|
||||||
int rc; /* Error code (if error has occurred) */
|
int rc; /* Error code (if error has occurred) */
|
||||||
IdxScan *pScan; /* List of scan objects */
|
IdxScan *pScan; /* List of scan objects */
|
||||||
sqlite3 *dbm; /* In-memory db for this analysis */
|
sqlite3 *dbm; /* In-memory db for this analysis */
|
||||||
sqlite3 *db; /* User database under analysis */
|
sqlite3 *db; /* User database under analysis */
|
||||||
sqlite3_stmt *pInsertMask; /* To write to aux.depmask */
|
sqlite3_stmt *pInsertMask; /* To write to aux.depmask */
|
||||||
|
i64 iIdxRowid; /* Rowid of first index created */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -587,11 +589,12 @@ static int idxFindCompatible(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int idxCreateFromCons(
|
static int idxCreateFromCons(
|
||||||
sqlite3 *dbm,
|
IdxContext *pCtx,
|
||||||
IdxScan *pScan,
|
IdxScan *pScan,
|
||||||
IdxConstraint *pEq,
|
IdxConstraint *pEq,
|
||||||
IdxConstraint *pTail
|
IdxConstraint *pTail
|
||||||
){
|
){
|
||||||
|
sqlite3 *dbm = pCtx->dbm;
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
|
if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
|
||||||
IdxTable *pTab = pScan->pTable;
|
IdxTable *pTab = pScan->pTable;
|
||||||
@@ -608,8 +611,8 @@ static int idxCreateFromCons(
|
|||||||
zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
|
zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hash the list of columns to come up with a name for the index */
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
|
/* Hash the list of columns to come up with a name for the index */
|
||||||
int i;
|
int i;
|
||||||
for(i=0; zCols[i]; i++){
|
for(i=0; zCols[i]; i++){
|
||||||
h += ((h<<3) + zCols[i]);
|
h += ((h<<3) + zCols[i]);
|
||||||
@@ -630,6 +633,18 @@ static int idxCreateFromCons(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( rc==SQLITE_OK && pCtx->iIdxRowid==0 ){
|
||||||
|
int rc2;
|
||||||
|
sqlite3_stmt *pLast = 0;
|
||||||
|
rc = idxPrepareStmt(dbm, &pLast, pCtx->pzErrmsg,
|
||||||
|
"SELECT max(rowid) FROM sqlite_master"
|
||||||
|
);
|
||||||
|
if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLast) ){
|
||||||
|
pCtx->iIdxRowid = sqlite3_column_int64(pLast, 0);
|
||||||
|
}
|
||||||
|
rc2 = sqlite3_finalize(pLast);
|
||||||
|
if( rc==SQLITE_OK ) rc = rc2;
|
||||||
|
}
|
||||||
|
|
||||||
sqlite3_free(zIdx);
|
sqlite3_free(zIdx);
|
||||||
sqlite3_free(zCols);
|
sqlite3_free(zCols);
|
||||||
@@ -638,11 +653,11 @@ static int idxCreateFromCons(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int idxCreateFromWhere(
|
static int idxCreateFromWhere(
|
||||||
sqlite3*, i64, IdxScan*, IdxWhere*, IdxConstraint*, IdxConstraint*
|
IdxContext*, i64, IdxScan*, IdxWhere*, IdxConstraint*, IdxConstraint*
|
||||||
);
|
);
|
||||||
|
|
||||||
static int idxCreateForeachOr(
|
static int idxCreateForeachOr(
|
||||||
sqlite3 *dbm,
|
IdxContext *pCtx,
|
||||||
i64 mask, /* Consider only these constraints */
|
i64 mask, /* Consider only these constraints */
|
||||||
IdxScan *pScan, /* Create indexes for this scan */
|
IdxScan *pScan, /* Create indexes for this scan */
|
||||||
IdxWhere *pWhere, /* Read constraints from here */
|
IdxWhere *pWhere, /* Read constraints from here */
|
||||||
@@ -653,22 +668,23 @@ static int idxCreateForeachOr(
|
|||||||
IdxWhere *p1;
|
IdxWhere *p1;
|
||||||
IdxWhere *p2;
|
IdxWhere *p2;
|
||||||
for(p1=pWhere->pOr; p1 && rc==SQLITE_OK; p1=p1->pNextOr){
|
for(p1=pWhere->pOr; p1 && rc==SQLITE_OK; p1=p1->pNextOr){
|
||||||
rc = idxCreateFromWhere(dbm, mask, pScan, p1, pEq, pTail);
|
rc = idxCreateFromWhere(pCtx, mask, pScan, p1, pEq, pTail);
|
||||||
for(p2=p1->pSibling; p2 && rc==SQLITE_OK; p2=p2->pSibling){
|
for(p2=p1->pSibling; p2 && rc==SQLITE_OK; p2=p2->pSibling){
|
||||||
rc = idxCreateFromWhere(dbm, mask, pScan, p2, pEq, pTail);
|
rc = idxCreateFromWhere(pCtx, mask, pScan, p2, pEq, pTail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int idxCreateFromWhere(
|
static int idxCreateFromWhere(
|
||||||
sqlite3 *dbm,
|
IdxContext *pCtx,
|
||||||
i64 mask, /* Consider only these constraints */
|
i64 mask, /* Consider only these constraints */
|
||||||
IdxScan *pScan, /* Create indexes for this scan */
|
IdxScan *pScan, /* Create indexes for this scan */
|
||||||
IdxWhere *pWhere, /* Read constraints from here */
|
IdxWhere *pWhere, /* Read constraints from here */
|
||||||
IdxConstraint *pEq, /* == constraints for inclusion */
|
IdxConstraint *pEq, /* == constraints for inclusion */
|
||||||
IdxConstraint *pTail /* range/ORDER BY constraints for inclusion */
|
IdxConstraint *pTail /* range/ORDER BY constraints for inclusion */
|
||||||
){
|
){
|
||||||
|
sqlite3 *dbm = pCtx->dbm;
|
||||||
IdxConstraint *p1 = pEq;
|
IdxConstraint *p1 = pEq;
|
||||||
IdxConstraint *pCon;
|
IdxConstraint *pCon;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -683,9 +699,9 @@ static int idxCreateFromWhere(
|
|||||||
|
|
||||||
/* Create an index using the == constraints collected above. And the
|
/* Create an index using the == constraints collected above. And the
|
||||||
** range constraint/ORDER BY terms passed in by the caller, if any. */
|
** range constraint/ORDER BY terms passed in by the caller, if any. */
|
||||||
rc = idxCreateFromCons(dbm, pScan, p1, pTail);
|
rc = idxCreateFromCons(pCtx, pScan, p1, pTail);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = idxCreateForeachOr(dbm, mask, pScan, pWhere, p1, pTail);
|
rc = idxCreateForeachOr(pCtx, mask, pScan, pWhere, p1, pTail);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no range/ORDER BY passed by the caller, create a version of the
|
/* If no range/ORDER BY passed by the caller, create a version of the
|
||||||
@@ -694,9 +710,9 @@ static int idxCreateFromWhere(
|
|||||||
for(pCon=pWhere->pRange; rc==SQLITE_OK && pCon; pCon=pCon->pNext){
|
for(pCon=pWhere->pRange; rc==SQLITE_OK && pCon; pCon=pCon->pNext){
|
||||||
assert( pCon->pLink==0 );
|
assert( pCon->pLink==0 );
|
||||||
if( (mask & pCon->depmask)==pCon->depmask ){
|
if( (mask & pCon->depmask)==pCon->depmask ){
|
||||||
rc = idxCreateFromCons(dbm, pScan, p1, pCon);
|
rc = idxCreateFromCons(pCtx, pScan, p1, pCon);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = idxCreateForeachOr(dbm, mask, pScan, pWhere, p1, pCon);
|
rc = idxCreateForeachOr(pCtx, mask, pScan, pWhere, p1, pCon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -709,25 +725,24 @@ static int idxCreateFromWhere(
|
|||||||
** Create candidate indexes in database [dbm] based on the data in
|
** Create candidate indexes in database [dbm] based on the data in
|
||||||
** linked-list pScan.
|
** linked-list pScan.
|
||||||
*/
|
*/
|
||||||
static int idxCreateCandidates(
|
static int idxCreateCandidates(IdxContext *pCtx){
|
||||||
sqlite3 *dbm,
|
sqlite3 *dbm = pCtx->dbm;
|
||||||
IdxScan *pScan,
|
|
||||||
char **pzErrmsg
|
|
||||||
){
|
|
||||||
int rc2;
|
int rc2;
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
sqlite3_stmt *pDepmask; /* Foreach depmask */
|
sqlite3_stmt *pDepmask; /* Foreach depmask */
|
||||||
IdxScan *pIter;
|
IdxScan *pIter;
|
||||||
|
|
||||||
rc = idxPrepareStmt(dbm, &pDepmask, pzErrmsg, "SELECT mask FROM depmask");
|
rc = idxPrepareStmt(pCtx->dbm, &pDepmask, pCtx->pzErrmsg,
|
||||||
|
"SELECT mask FROM depmask"
|
||||||
|
);
|
||||||
|
|
||||||
for(pIter=pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
|
for(pIter=pCtx->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
|
||||||
IdxWhere *pWhere = &pIter->where;
|
IdxWhere *pWhere = &pIter->where;
|
||||||
while( SQLITE_ROW==sqlite3_step(pDepmask) && rc==SQLITE_OK ){
|
while( SQLITE_ROW==sqlite3_step(pDepmask) && rc==SQLITE_OK ){
|
||||||
i64 mask = sqlite3_column_int64(pDepmask, 0);
|
i64 mask = sqlite3_column_int64(pDepmask, 0);
|
||||||
rc = idxCreateFromWhere(dbm, mask, pIter, pWhere, 0, 0);
|
rc = idxCreateFromWhere(pCtx, mask, pIter, pWhere, 0, 0);
|
||||||
if( rc==SQLITE_OK && pIter->pOrder ){
|
if( rc==SQLITE_OK && pIter->pOrder ){
|
||||||
rc = idxCreateFromWhere(dbm, mask, pIter, pWhere, 0, pIter->pOrder);
|
rc = idxCreateFromWhere(pCtx, mask, pIter, pWhere, 0, pIter->pOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -747,20 +762,22 @@ static void idxScanFree(IdxScan *pScan){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int idxFindIndexes(
|
int idxFindIndexes(
|
||||||
sqlite3 *dbm, /* Database handle */
|
IdxContext *pCtx,
|
||||||
const char *zSql, /* SQL to find indexes for */
|
const char *zSql, /* SQL to find indexes for */
|
||||||
void (*xOut)(void*, const char*), /* Output callback */
|
void (*xOut)(void*, const char*), /* Output callback */
|
||||||
void *pOutCtx, /* Context for xOut() */
|
void *pOutCtx, /* Context for xOut() */
|
||||||
char **pzErr /* OUT: Error message (sqlite3_malloc) */
|
char **pzErr /* OUT: Error message (sqlite3_malloc) */
|
||||||
){
|
){
|
||||||
|
sqlite3 *dbm = pCtx->dbm;
|
||||||
sqlite3_stmt *pExplain = 0;
|
sqlite3_stmt *pExplain = 0;
|
||||||
sqlite3_stmt *pSelect = 0;
|
sqlite3_stmt *pSelect = 0;
|
||||||
int rc, rc2;
|
int rc, rc2;
|
||||||
|
int bFound = 0;
|
||||||
|
|
||||||
rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr,"EXPLAIN QUERY PLAN %s",zSql);
|
rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr,"EXPLAIN QUERY PLAN %s",zSql);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = idxPrepareStmt(dbm, &pSelect, pzErr,
|
rc = idxPrepareStmt(dbm, &pSelect, pzErr,
|
||||||
"SELECT sql FROM sqlite_master WHERE name = ?"
|
"SELECT rowid, sql FROM sqlite_master WHERE name = ?"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,7 +793,12 @@ int idxFindIndexes(
|
|||||||
while( zIdx[nIdx]!='\0' && zIdx[nIdx]!=' ' ) nIdx++;
|
while( zIdx[nIdx]!='\0' && zIdx[nIdx]!=' ' ) nIdx++;
|
||||||
sqlite3_bind_text(pSelect, 1, zIdx, nIdx, SQLITE_STATIC);
|
sqlite3_bind_text(pSelect, 1, zIdx, nIdx, SQLITE_STATIC);
|
||||||
if( SQLITE_ROW==sqlite3_step(pSelect) ){
|
if( SQLITE_ROW==sqlite3_step(pSelect) ){
|
||||||
xOut(pOutCtx, sqlite3_column_text(pSelect, 0));
|
i64 iRowid = sqlite3_column_int64(pSelect, 0);
|
||||||
|
const char *zSql = (const char*)sqlite3_column_text(pSelect, 1);
|
||||||
|
if( iRowid>=pCtx->iIdxRowid ){
|
||||||
|
xOut(pOutCtx, zSql);
|
||||||
|
bFound = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rc = sqlite3_reset(pSelect);
|
rc = sqlite3_reset(pSelect);
|
||||||
break;
|
break;
|
||||||
@@ -785,7 +807,10 @@ int idxFindIndexes(
|
|||||||
}
|
}
|
||||||
rc2 = sqlite3_reset(pExplain);
|
rc2 = sqlite3_reset(pExplain);
|
||||||
if( rc==SQLITE_OK ) rc = rc2;
|
if( rc==SQLITE_OK ) rc = rc2;
|
||||||
if( rc==SQLITE_OK ) xOut(pOutCtx, "");
|
if( rc==SQLITE_OK ){
|
||||||
|
if( bFound==0 ) xOut(pOutCtx, "(no new indexes)");
|
||||||
|
xOut(pOutCtx, "");
|
||||||
|
}
|
||||||
|
|
||||||
while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
|
while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
|
||||||
int iSelectid = sqlite3_column_int(pExplain, 0);
|
int iSelectid = sqlite3_column_int(pExplain, 0);
|
||||||
@@ -841,6 +866,7 @@ int shellIndexesCommand(
|
|||||||
rc = sqlite3_exec(dbm,
|
rc = sqlite3_exec(dbm,
|
||||||
"ATTACH ':memory:' AS aux;"
|
"ATTACH ':memory:' AS aux;"
|
||||||
"CREATE TABLE aux.depmask(mask PRIMARY KEY) WITHOUT ROWID;"
|
"CREATE TABLE aux.depmask(mask PRIMARY KEY) WITHOUT ROWID;"
|
||||||
|
"CREATE TABLE aux.indexes(name PRIMARY KEY) WITHOUT ROWID;"
|
||||||
"INSERT INTO aux.depmask VALUES(0);"
|
"INSERT INTO aux.depmask VALUES(0);"
|
||||||
, 0, 0, pzErrmsg
|
, 0, 0, pzErrmsg
|
||||||
);
|
);
|
||||||
@@ -872,13 +898,13 @@ int shellIndexesCommand(
|
|||||||
|
|
||||||
/* Create candidate indexes within the in-memory database file */
|
/* Create candidate indexes within the in-memory database file */
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = idxCreateCandidates(dbm, ctx.pScan, pzErrmsg);
|
rc = idxCreateCandidates(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out which of the candidate indexes are preferred by the query
|
/* Figure out which of the candidate indexes are preferred by the query
|
||||||
** planner and report the results to the user. */
|
** planner and report the results to the user. */
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = idxFindIndexes(dbm, zSql, xOut, pOutCtx, pzErrmsg);
|
rc = idxFindIndexes(&ctx, zSql, xOut, pOutCtx, pzErrmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
idxScanFree(ctx.pScan);
|
idxScanFree(ctx.pScan);
|
||||||
|
|||||||
Reference in New Issue
Block a user