Fix handling of partial indexes in checkindex.c (sqlite3_checker).

FossilOrigin-Name: 31932a9eb8dbb33d5535715ae8bbfdc55ce66b1a1a0abd57cefe720eeb31e231
This commit is contained in:
dan
2017-11-07 19:02:00 +00:00
parent 85e1f46eb9
commit 0e90ad6a37
4 changed files with 116 additions and 49 deletions
+77 -40
View File
@@ -59,6 +59,7 @@ struct CidxColumn {
typedef struct CidxIndex CidxIndex;
struct CidxIndex {
char *zWhere; /* WHERE clause, if any */
int nCol; /* Elements in aCol[] array */
CidxColumn aCol[1]; /* Array of indexed columns */
};
@@ -293,6 +294,7 @@ static void cidxFreeIndex(CidxIndex *pIdx){
for(i=0; i<pIdx->nCol; i++){
sqlite3_free(pIdx->aCol[i].zExpr);
}
sqlite3_free(pIdx->zWhere);
sqlite3_free(pIdx);
}
}
@@ -312,6 +314,24 @@ static int cidx_isident(char c){
#define CIDX_PARSE_OPEN 2 /* "(" */
#define CIDX_PARSE_CLOSE 3 /* ")" */
/*
** Argument zIn points into the start, middle or end of a CREATE INDEX
** statement. If argument pbDoNotTrim is non-NULL, then this function
** scans the input until it finds EOF, a comma (",") or an open or
** close parenthesis character. It then sets (*pzOut) to point to said
** character and returns a CIDX_PARSE_XXX constant as appropriate. The
** parser is smart enough that special characters inside SQL strings
** or comments are not returned for.
**
** Or, if argument pbDoNotTrim is NULL, then this function sets *pzOut
** to point to the first character of the string that is not whitespace
** or part of an SQL comment and returns CIDX_PARSE_EOF.
**
** Additionally, if pbDoNotTrim is not NULL and the element immediately
** before (*pzOut) is an SQL comment of the form "-- comment", then
** (*pbDoNotTrim) is set before returning. In all other cases it is
** cleared.
*/
static int cidxFindNext(
const char *zIn,
const char **pzOut,
@@ -320,6 +340,7 @@ static int cidxFindNext(
const char *z = zIn;
while( 1 ){
while( cidx_isspace(*z) ) z++;
if( z[0]=='-' && z[1]=='-' ){
z += 2;
while( z[0]!='\n' ){
@@ -327,9 +348,18 @@ static int cidxFindNext(
z++;
}
while( cidx_isspace(*z) ) z++;
*pbDoNotTrim = 1;
if( pbDoNotTrim ) *pbDoNotTrim = 1;
}else
if( z[0]=='/' && z[1]=='*' ){
z += 2;
while( z[0]!='*' || z[1]!='/' ){
if( z[1]=='\0' ) return CIDX_PARSE_EOF;
z++;
}
z += 2;
}else{
*pzOut = z;
if( pbDoNotTrim==0 ) return CIDX_PARSE_EOF;
switch( *z ){
case '\0':
return CIDX_PARSE_EOF;
@@ -359,17 +389,6 @@ static int cidxFindNext(
while( *z++!=']' );
break;
case '/':
if( z[1]=='*' ){
z += 2;
while( z[0]!='*' || z[1]!='/' ){
if( z[1]=='\0' ) return CIDX_PARSE_EOF;
z++;
}
z += 2;
break;
}
default:
z++;
break;
@@ -424,6 +443,14 @@ static int cidxParseSQL(CidxCursor *pCsr, CidxIndex *pIdx, const char *zSql){
z++;
}
/* Search for a WHERE clause */
cidxFindNext(z, &z, 0);
if( 0==sqlite3_strnicmp(z, "where", 5) ){
pIdx->zWhere = cidxMprintf(&rc, "%s\n", &z[5]);
}else if( z[0]!='\0' ){
goto parse_error;
}
return rc;
parse_error:
@@ -477,6 +504,7 @@ static int cidxLookupIndex(
p->zExpr = 0;
}
pIdx->nCol = iCol;
pIdx->zWhere = 0;
}
cidxFinalize(&rc, pInfo);
}
@@ -700,36 +728,45 @@ int cidxGenerateScanSql(
rc = cidxDecodeAfter(pCsr, pIdx->nCol, zAfterKey, &azAfter);
}
if( rc || zAfterKey==0 ){
*pzSqlOut = cidxMprintf(&rc,
"SELECT (SELECT %s FROM %Q AS t WHERE %s), %s "
"FROM (SELECT %s FROM %Q ORDER BY %s) AS i",
zSubExpr, zTab, zSubWhere, zCurrentKey,
zSrcList, zTab, zOrderBy
);
}else{
const char *zSep = "";
char *zSql;
int i;
zSql = cidxMprintf(&rc,
"SELECT (SELECT %s FROM %Q WHERE %s), %s FROM (",
zSubExpr, zTab, zSubWhere, zCurrentKey
);
for(i=pIdx->nCol-1; i>=0; i--){
int j;
if( pIdx->aCol[i].bDesc && azAfter[i]==0 ) continue;
for(j=0; j<2; j++){
char *zWhere = cidxWhere(&rc, pIdx->aCol, azAfter, i, j);
zSql = cidxMprintf(&rc, "%z"
"%sSELECT * FROM (SELECT %s FROM %Q WHERE %z ORDER BY %s)",
zSql, zSep, zSrcList, zTab, zWhere, zOrderBy
);
zSep = " UNION ALL ";
if( pIdx->aCol[i].bDesc==0 ) break;
if( rc==SQLITE_OK ){
if( zAfterKey==0 ){
*pzSqlOut = cidxMprintf(&rc,
"SELECT (SELECT %s FROM %Q AS t WHERE %s), %s "
"FROM (SELECT %s FROM %Q INDEXED BY %Q %s%sORDER BY %s) AS i",
zSubExpr, zTab, zSubWhere, zCurrentKey,
zSrcList, zTab, zIdxName,
(pIdx->zWhere ? "WHERE " : ""), (pIdx->zWhere ? pIdx->zWhere : ""),
zOrderBy
);
}else{
const char *zSep = "";
char *zSql;
int i;
zSql = cidxMprintf(&rc,
"SELECT (SELECT %s FROM %Q WHERE %s), %s FROM (",
zSubExpr, zTab, zSubWhere, zCurrentKey
);
for(i=pIdx->nCol-1; i>=0; i--){
int j;
if( pIdx->aCol[i].bDesc && azAfter[i]==0 ) continue;
for(j=0; j<2; j++){
char *zWhere = cidxWhere(&rc, pIdx->aCol, azAfter, i, j);
zSql = cidxMprintf(&rc, "%z"
"%sSELECT * FROM ("
"SELECT %s FROM %Q INDEXED BY %Q WHERE %s%s%z ORDER BY %s"
")",
zSql, zSep, zSrcList, zTab, zIdxName,
pIdx->zWhere ? pIdx->zWhere : "",
pIdx->zWhere ? " AND " : "",
zWhere, zOrderBy
);
zSep = " UNION ALL ";
if( pIdx->aCol[i].bDesc==0 ) break;
}
}
*pzSqlOut = cidxMprintf(&rc, "%z) AS i", zSql);
}
*pzSqlOut = cidxMprintf(&rc, "%z) AS i", zSql);
}
sqlite3_free(zTab);
+31 -1
View File
@@ -60,7 +60,7 @@ do_execsql_test 1.2.2 {
'five',5
i1
{}
{SELECT (SELECT a IS i.i0 FROM 't1' AS t WHERE "rowid" COLLATE BINARY IS i.i1), quote(i0)||','||quote(i1) FROM (SELECT (a) AS i0, ("rowid" COLLATE BINARY) AS i1 FROM 't1' ORDER BY 1,2) AS i}
{SELECT (SELECT a IS i.i0 FROM 't1' AS t WHERE "rowid" COLLATE BINARY IS i.i1), quote(i0)||','||quote(i1) FROM (SELECT (a) AS i0, ("rowid" COLLATE BINARY) AS i1 FROM 't1' INDEXED BY 'i1' ORDER BY 1,2) AS i}
}
do_index_check_test 1.3 i1 {
@@ -319,3 +319,33 @@ do_index_check_test 6.2 t6x3 {
{} 3,2,1
{} 6,5,4
}
#-------------------------------------------------------------------------
#
do_execsql_test 7.0 {
CREATE TABLE t7(x INTEGER PRIMARY KEY, y, z);
INSERT INTO t7 VALUES(1, 1, 1);
INSERT INTO t7 VALUES(2, 2, 0);
INSERT INTO t7 VALUES(3, 3, 1);
INSERT INTO t7 VALUES(4, 4, 0);
CREATE INDEX t7i1 ON t7(y) WHERE z=1;
CREATE INDEX t7i2 ON t7(y) /* hello,world */ WHERE z=1;
CREATE INDEX t7i3 ON t7(y) WHERE -- yep
z=1;
CREATE INDEX t7i4 ON t7(y) WHERE z=1 -- yep;
}
do_index_check_test 7.1 t7i1 {
{} 1,1 {} 3,3
}
do_index_check_test 7.2 t7i2 {
{} 1,1 {} 3,3
}
do_index_check_test 7.3 t7i3 {
{} 1,1 {} 3,3
}
do_index_check_test 7.4 t7i4 {
{} 1,1 {} 3,3
}