Changes to allow indexes to be recommended for queries on SQL views.

FossilOrigin-Name: 0884ff1da2e27b146c764b73cf299a1f2cfe213c4a79bde34dec02d1fc946e70
This commit is contained in:
dan 2017-04-06 18:44:18 +00:00
parent 53761f4d52
commit d8ac297233
4 changed files with 47 additions and 149 deletions

View File

@ -1,5 +1,5 @@
C Add\ssome\ssupport\sfor\sOR\sterms\sto\ssqlite3_whereinfo_hook().
D 2017-04-04T17:50:31.913
C Changes\sto\sallow\sindexes\sto\sbe\srecommended\sfor\squeries\son\sSQL\sviews.
D 2017-04-06T18:44:18.391
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc a4c0613a18663bda56d8cf76079ab6590a7c3602e54befb4bbdef76bcaa38b6a
@ -403,7 +403,7 @@ F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 2496d0cc6368dabe7ad2e4c7f5ed3ad9aa3b4d11cd90f33fa1d1ef72493f43aa
F src/shell.c e524688c2544167f835ba43e24309f8707ca60c8ab6eb5c263a12c8618a233b8
F src/shell_indexes.c d40ea0a81112df7bdccd7232238bee0bbb39699085ea78cc08fd863bf052a63b
F src/shell_indexes.c 1f5ab036ec189411aeea27e6e74ab0009d831764d5d8517455dcb6b6a734beb7
F src/sqlite.h.in ae5c9cbf2e77492c319fca08769575d9695e64718a16d32324944d24e291bcf7
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
@ -1120,7 +1120,7 @@ F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
F test/shell5.test 50a732c1c2158b1cd62cf53975ce1ea7ce6b9dc9
F test/shell6.test 081067c1afcb38da50134ffd5ccc0a59ede14f41959486f733ffbba689c0ccfa
F test/shell6.test f37998b26dfde19beaaf06a4cb60c476f66a7b54affff3870a2a011402c13efc
F test/shell7.test 07751911b294698e0c5df67bcbd29e7d2f0f2907
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
@ -1571,7 +1571,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P a54aef35da11f7508a8888a159372036a362fc52afa1df752dc835db334c4330
R 51e547bc1c25ea79dd375d8f020224f3
P 5cd070000da1d9e399090677b4db75dc5639c33211385d6eb84f14a4d0b617cd
R aa13547c61fd31f43629472eaf9b4008
U dan
Z fe378068686ea107c39185021a17b4ae
Z 2f3b5e2a515dd18e4123d763066c9a33

View File

@ -1 +1 @@
5cd070000da1d9e399090677b4db75dc5639c33211385d6eb84f14a4d0b617cd
0884ff1da2e27b146c764b73cf299a1f2cfe213c4a79bde34dec02d1fc946e70

View File

@ -43,44 +43,18 @@ struct IdxConstraint {
/*
** A WHERE clause. Made up of IdxConstraint objects. Example WHERE clause:
**
** a=? AND b=? AND ((c=? AND d=?) OR e=?) AND (f=? OR g=?) AND h>?
** a=? AND b=? AND c=? AND d=? AND e>? AND f<?
**
** The above is decomposed into 5 AND connected clauses. The first two are
** The above is decomposed into 6 AND connected clauses. The first four are
** added to the IdxWhere.pEq linked list, the following two into
** IdxWhere.pOr and the last into IdxWhere.pRange.
** IdxWhere.pRange.
**
** IdxWhere.pEq and IdxWhere.pRange are simple linked lists of IdxConstraint
** objects linked by the IdxConstraint.pNext field.
**
** The list headed at IdxWhere.pOr and linked by IdxWhere.pNextOr contains
** all "OR" terms that belong to the current WHERE clause. In the example
** above, there are two OR terms:
**
** ((c=? AND d=?) OR e=?)
** (f=? OR g=?)
**
** Within an OR term, the OR connected sub-expressions are termed siblings.
** These are connected into a linked list by the pSibling pointers. Each OR
** term above consists of two siblings.
**
** pOr -> (c=? AND d=?) -> pNextOr -> (f=?)
** | |
** pSibling pSibling
** | |
** V V
** (e=?) (g=?)
**
** IdxWhere.pParent is only used while constructing a tree of IdxWhere
** structures. It is NULL for the root IdxWhere. For all others, the parent
** WHERE clause.
*/
struct IdxWhere {
IdxConstraint *pEq; /* List of == constraints */
IdxConstraint *pRange; /* List of < constraints */
IdxWhere *pOr; /* List of OR constraints */
IdxWhere *pNextOr; /* Next in OR constraints of same IdxWhere */
IdxWhere *pSibling; /* Next branch in single OR constraint */
IdxWhere *pParent; /* Parent object (or NULL) */
};
/*
@ -246,40 +220,6 @@ static void idxDatabaseError(
*pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}
static char *idxQueryToList(
sqlite3 *db,
const char *zBind,
int *pRc,
char **pzErrmsg,
const char *zSql
){
char *zRet = 0;
if( *pRc==SQLITE_OK ){
sqlite3_stmt *pStmt = 0;
int rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_text(pStmt, 1, zBind, -1, SQLITE_TRANSIENT);
while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
const char *z = (const char*)sqlite3_column_text(pStmt, 0);
zRet = sqlite3_mprintf("%z%s%Q", zRet, zRet?", ":"", z);
if( zRet==0 ){
rc = SQLITE_NOMEM;
}
}
rc = sqlite3_finalize(pStmt);
}
if( rc ){
idxDatabaseError(db, pzErrmsg);
sqlite3_free(zRet);
zRet = 0;
}
*pRc = rc;
}
return zRet;
}
static int idxPrepareStmt(
sqlite3 *db, /* Database handle to compile against */
sqlite3_stmt **ppStmt, /* OUT: Compiled SQL statement */
@ -331,7 +271,7 @@ static int idxGetTableInfo(
rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTbl);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
const char *zCol = sqlite3_column_text(p1, 1);
const char *zCol = (const char*)sqlite3_column_text(p1, 1);
nByte += 1 + strlen(zCol);
rc = sqlite3_table_column_metadata(
db, "main", zTbl, zCol, 0, &zCol, 0, 0, 0
@ -354,7 +294,7 @@ static int idxGetTableInfo(
nCol = 0;
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
const char *zCol = sqlite3_column_text(p1, 1);
const char *zCol = (const char*)sqlite3_column_text(p1, 1);
int nCopy = strlen(zCol) + 1;
pNew->aCol[nCol].zName = pCsr;
pNew->aCol[nCol].iPk = sqlite3_column_int(p1, 5);
@ -392,38 +332,24 @@ static int idxCreateTables(
char **pzErrmsg /* OUT: Error message */
){
int rc = SQLITE_OK;
int rc2;
IdxScan *pIter;
sqlite3_stmt *pSql = 0;
/* Copy the entire schema of database [db] into [dbm]. */
rc = idxPrintfPrepareStmt(db, &pSql, pzErrmsg,
"SELECT sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%%'"
);
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);
}
rc2 = sqlite3_finalize(pSql);
if( rc==SQLITE_OK ) rc = rc2;
/* Load IdxTable objects */
for(pIter=pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
rc = idxGetTableInfo(db, pIter, pzErrmsg);
/* Test if table has already been created. If so, jump to the next
** iteration of the loop. */
if( rc==SQLITE_OK ){
sqlite3_stmt *pSql = 0;
rc = idxPrintfPrepareStmt(dbm, &pSql, pzErrmsg,
"SELECT 1 FROM sqlite_master WHERE tbl_name = %Q", pIter->zTable
);
if( rc==SQLITE_OK ){
int bSkip = 0;
if( sqlite3_step(pSql)==SQLITE_ROW ) bSkip = 1;
rc = sqlite3_finalize(pSql);
if( bSkip ) continue;
}
}
if( rc==SQLITE_OK ){
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);
}
rc2 = sqlite3_finalize(pSql);
if( rc==SQLITE_OK ) rc = rc2;
}
}
return rc;
}
@ -655,26 +581,6 @@ static int idxCreateFromWhere(
IdxContext*, i64, IdxScan*, IdxWhere*, IdxConstraint*, IdxConstraint*
);
static int idxCreateForeachOr(
IdxContext *pCtx,
i64 mask, /* Consider only these constraints */
IdxScan *pScan, /* Create indexes for this scan */
IdxWhere *pWhere, /* Read constraints from here */
IdxConstraint *pEq, /* == constraints for inclusion */
IdxConstraint *pTail /* range/ORDER BY constraints for inclusion */
){
int rc = SQLITE_OK;
IdxWhere *p1;
IdxWhere *p2;
for(p1=pWhere->pOr; p1 && rc==SQLITE_OK; p1=p1->pNextOr){
rc = idxCreateFromWhere(pCtx, mask, pScan, p1, pEq, pTail);
for(p2=p1->pSibling; p2 && rc==SQLITE_OK; p2=p2->pSibling){
rc = idxCreateFromWhere(pCtx, mask, pScan, p2, pEq, pTail);
}
}
return rc;
}
/*
** Return true if list pList (linked by IdxConstraint.pLink) contains
** a constraint compatible with *p. Otherwise return false.
@ -695,7 +601,6 @@ static int idxCreateFromWhere(
IdxConstraint *pEq, /* == constraints for inclusion */
IdxConstraint *pTail /* range/ORDER BY constraints for inclusion */
){
sqlite3 *dbm = pCtx->dbm;
IdxConstraint *p1 = pEq;
IdxConstraint *pCon;
int rc;
@ -714,9 +619,6 @@ static int idxCreateFromWhere(
/* Create an index using the == constraints collected above. And the
** range constraint/ORDER BY terms passed in by the caller, if any. */
rc = idxCreateFromCons(pCtx, pScan, p1, pTail);
if( rc==SQLITE_OK ){
rc = idxCreateForeachOr(pCtx, mask, pScan, pWhere, p1, pTail);
}
/* If no range/ORDER BY passed by the caller, create a version of the
** index for each range constraint that matches the mask. */
@ -728,9 +630,6 @@ static int idxCreateFromWhere(
&& idxFindConstraint(pTail, pCon)==0
){
rc = idxCreateFromCons(pCtx, pScan, p1, pCon);
if( rc==SQLITE_OK ){
rc = idxCreateForeachOr(pCtx, mask, pScan, pWhere, p1, pCon);
}
}
}
}
@ -749,7 +648,7 @@ static int idxCreateCandidates(IdxContext *pCtx){
sqlite3_stmt *pDepmask; /* Foreach depmask */
IdxScan *pIter;
rc = idxPrepareStmt(pCtx->dbm, &pDepmask, pCtx->pzErrmsg,
rc = idxPrepareStmt(dbm, &pDepmask, pCtx->pzErrmsg,
"SELECT mask FROM depmask"
);
@ -774,7 +673,6 @@ static void idxScanFree(IdxScan *pScan){
IdxScan *pNext;
for(pIter=pScan; pIter; pIter=pNext){
pNext = pIter->pNextScan;
}
}
@ -841,11 +739,11 @@ int idxFindIndexes(
if( rc==SQLITE_OK ) rc = rc2;
if( rc==SQLITE_OK ){
sqlite3_stmt *pLoop = 0;
rc = idxPrepareStmt(dbm, &pLoop, pzErr, "SELECT name FROM aux.indexes");
rc = idxPrepareStmt(dbm, &pLoop, pzErr,"SELECT name||';' FROM aux.indexes");
if( rc==SQLITE_OK ){
while( SQLITE_ROW==sqlite3_step(pLoop) ){
bFound = 1;
xOut(pOutCtx, sqlite3_column_text(pLoop, 0));
xOut(pOutCtx, (const char*)sqlite3_column_text(pLoop, 0));
}
rc = sqlite3_finalize(pLoop);
}

View File

@ -66,7 +66,7 @@ do_setup_rec_test 1.2 {
} {
SELECT * FROM t1 WHERE b>?;
} {
CREATE INDEX t1_idx_00000062 ON t1(b)
CREATE INDEX t1_idx_00000062 ON t1(b);
0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_00000062 (b>?)
}
@ -75,7 +75,7 @@ do_setup_rec_test 1.3 {
} {
SELECT * FROM t1 WHERE b COLLATE nocase BETWEEN ? AND ?
} {
CREATE INDEX t1_idx_3e094c27 ON t1(b COLLATE NOCASE)
CREATE INDEX t1_idx_3e094c27 ON t1(b COLLATE NOCASE);
0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_3e094c27 (b>? AND b<?)
}
@ -84,7 +84,7 @@ do_setup_rec_test 1.4 {
} {
SELECT a FROM t1 ORDER BY b;
} {
CREATE INDEX t1_idx_00000062 ON t1(b)
CREATE INDEX t1_idx_00000062 ON t1(b);
0|0|0|SCAN TABLE t1 USING INDEX t1_idx_00000062
}
@ -93,7 +93,7 @@ do_setup_rec_test 1.5 {
} {
SELECT a FROM t1 WHERE a=? ORDER BY b;
} {
CREATE INDEX t1_idx_000123a7 ON t1(a, b)
CREATE INDEX t1_idx_000123a7 ON t1(a, b);
0|0|0|SEARCH TABLE t1 USING COVERING INDEX t1_idx_000123a7 (a=?)
}
@ -102,7 +102,7 @@ do_setup_rec_test 1.6 {
} {
SELECT min(a) FROM t1
} {
CREATE INDEX t1_idx_00000061 ON t1(a)
CREATE INDEX t1_idx_00000061 ON t1(a);
0|0|0|SEARCH TABLE t1 USING COVERING INDEX t1_idx_00000061
}
@ -111,7 +111,7 @@ do_setup_rec_test 1.7 {
} {
SELECT * FROM t1 ORDER BY a, b, c;
} {
CREATE INDEX t1_idx_033e95fe ON t1(a, b, c)
CREATE INDEX t1_idx_033e95fe ON t1(a, b, c);
0|0|0|SCAN TABLE t1 USING COVERING INDEX t1_idx_033e95fe
}
@ -120,7 +120,7 @@ do_setup_rec_test 1.8 {
} {
SELECT * FROM t1 ORDER BY a ASC, b COLLATE nocase DESC, c ASC;
} {
CREATE INDEX t1_idx_5be6e222 ON t1(a, b COLLATE NOCASE DESC, c)
CREATE INDEX t1_idx_5be6e222 ON t1(a, b COLLATE NOCASE DESC, c);
0|0|0|SCAN TABLE t1 USING COVERING INDEX t1_idx_5be6e222
}
@ -129,7 +129,7 @@ do_setup_rec_test 1.9 {
} {
SELECT * FROM t1 WHERE a=?
} {
CREATE INDEX t1_idx_00000061 ON t1(a)
CREATE INDEX t1_idx_00000061 ON t1(a);
0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_00000061 (a=?)
}
@ -141,7 +141,7 @@ do_setup_rec_test 8.1 {
} {
SELECT * FROM "t t" WHERE a=?
} {
CREATE INDEX 't t_idx_00000061' ON 't t'(a)
CREATE INDEX 't t_idx_00000061' ON 't t'(a);
0|0|0|SEARCH TABLE t t USING INDEX t t_idx_00000061 (a=?)
}
@ -150,7 +150,7 @@ do_setup_rec_test 8.2 {
} {
SELECT * FROM "t t" WHERE b BETWEEN ? AND ?
} {
CREATE INDEX 't t_idx_00000062' ON 't t'(b)
CREATE INDEX 't t_idx_00000062' ON 't t'(b);
0|0|0|SEARCH TABLE t t USING INDEX t t_idx_00000062 (b>? AND b<?)
}
@ -161,7 +161,7 @@ do_setup_rec_test 9.1 {
} {
SELECT * FROM t3 WHERE "b b" = ?
} {
CREATE INDEX t3_idx_00050c52 ON t3('b b')
CREATE INDEX t3_idx_00050c52 ON t3('b b');
0|0|0|SEARCH TABLE t3 USING INDEX t3_idx_00050c52 (b b=?)
}
@ -170,7 +170,7 @@ do_setup_rec_test 9.2 {
} {
SELECT * FROM t3 ORDER BY "b b"
} {
CREATE INDEX t3_idx_00050c52 ON t3('b b')
CREATE INDEX t3_idx_00050c52 ON t3('b b');
0|0|0|SCAN TABLE t3 USING INDEX t3_idx_00050c52
}
@ -182,8 +182,8 @@ do_setup_rec_test 10.1 {
} {
SELECT * FROM t5, t6 WHERE a=? AND b=c AND c=?
} {
CREATE INDEX t5_idx_000123a7 ON t5(a, b)
CREATE INDEX t6_idx_00000063 ON t6(c)
CREATE INDEX t5_idx_000123a7 ON t5(a, b);
CREATE INDEX t6_idx_00000063 ON t6(c);
0|0|1|SEARCH TABLE t6 USING INDEX t6_idx_00000063 (c=?)
0|1|0|SEARCH TABLE t5 USING COVERING INDEX t5_idx_000123a7 (a=? AND b=?)
}
@ -195,8 +195,8 @@ do_setup_rec_test 11.1 {
} {
SELECT * FROM t7 WHERE a=? OR b=?
} {
CREATE INDEX t7_idx_00000061 ON t7(a)
CREATE INDEX t7_idx_00000062 ON t7(b)
CREATE INDEX t7_idx_00000061 ON t7(a);
CREATE INDEX t7_idx_00000062 ON t7(b);
0|0|0|SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
0|0|0|SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
}