xref: /sqlite-3.40.0/ext/repair/checkindex.c (revision 067b92ba)
1 /*
2 ** 2017 October 27
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 */
13 
14 #include "sqlite3ext.h"
15 SQLITE_EXTENSION_INIT1
16 
17 /*
18 ** Stuff that is available inside the amalgamation, but which we need to
19 ** declare ourselves if this module is compiled separately.
20 */
21 #ifndef SQLITE_AMALGAMATION
22 # include <string.h>
23 # include <stdio.h>
24 # include <stdlib.h>
25 # include <assert.h>
26 typedef unsigned char u8;
27 typedef unsigned short u16;
28 typedef unsigned int u32;
29 #define get4byte(x) (        \
30     ((u32)((x)[0])<<24) +    \
31     ((u32)((x)[1])<<16) +    \
32     ((u32)((x)[2])<<8) +     \
33     ((u32)((x)[3]))          \
34 )
35 #endif
36 
37 typedef struct CidxTable CidxTable;
38 typedef struct CidxCursor CidxCursor;
39 
40 struct CidxTable {
41   sqlite3_vtab base;              /* Base class.  Must be first */
42   sqlite3 *db;
43 };
44 
45 struct CidxCursor {
46   sqlite3_vtab_cursor base;       /* Base class.  Must be first */
47   sqlite3_int64 iRowid;           /* Row number of the output */
48   char *zIdxName;                 /* Copy of the index_name parameter */
49   char *zAfterKey;                /* Copy of the after_key parameter */
50   sqlite3_stmt *pStmt;            /* SQL statement that generates the output */
51 };
52 
53 typedef struct CidxColumn CidxColumn;
54 struct CidxColumn {
55   char *zExpr;                    /* Text for indexed expression */
56   int bDesc;                      /* True for DESC columns, otherwise false */
57   int bKey;                       /* Part of index, not PK */
58 };
59 
60 typedef struct CidxIndex CidxIndex;
61 struct CidxIndex {
62   char *zWhere;                   /* WHERE clause, if any */
63   int nCol;                       /* Elements in aCol[] array */
64   CidxColumn aCol[1];             /* Array of indexed columns */
65 };
66 
cidxMalloc(int * pRc,int n)67 static void *cidxMalloc(int *pRc, int n){
68   void *pRet = 0;
69   assert( n!=0 );
70   if( *pRc==SQLITE_OK ){
71     pRet = sqlite3_malloc(n);
72     if( pRet ){
73       memset(pRet, 0, n);
74     }else{
75       *pRc = SQLITE_NOMEM;
76     }
77   }
78   return pRet;
79 }
80 
cidxCursorError(CidxCursor * pCsr,const char * zFmt,...)81 static void cidxCursorError(CidxCursor *pCsr, const char *zFmt, ...){
82   va_list ap;
83   va_start(ap, zFmt);
84   assert( pCsr->base.pVtab->zErrMsg==0 );
85   pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
86   va_end(ap);
87 }
88 
89 /*
90 ** Connect to the incremental_index_check virtual table.
91 */
cidxConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)92 static int cidxConnect(
93   sqlite3 *db,
94   void *pAux,
95   int argc, const char *const*argv,
96   sqlite3_vtab **ppVtab,
97   char **pzErr
98 ){
99   int rc = SQLITE_OK;
100   CidxTable *pRet;
101 
102 #define IIC_ERRMSG        0
103 #define IIC_CURRENT_KEY   1
104 #define IIC_INDEX_NAME    2
105 #define IIC_AFTER_KEY     3
106 #define IIC_SCANNER_SQL   4
107   rc = sqlite3_declare_vtab(db,
108       "CREATE TABLE xyz("
109       " errmsg TEXT,"            /* Error message or NULL if everything is ok */
110       " current_key TEXT,"       /* SQLite quote() text of key values */
111       " index_name HIDDEN,"      /* IN: name of the index being scanned */
112       " after_key HIDDEN,"       /* IN: Start scanning after this key */
113       " scanner_sql HIDDEN"      /* debuggingn info: SQL used for scanner */
114       ")"
115   );
116   pRet = cidxMalloc(&rc, sizeof(CidxTable));
117   if( pRet ){
118     pRet->db = db;
119   }
120 
121   *ppVtab = (sqlite3_vtab*)pRet;
122   return rc;
123 }
124 
125 /*
126 ** Disconnect from or destroy an incremental_index_check virtual table.
127 */
cidxDisconnect(sqlite3_vtab * pVtab)128 static int cidxDisconnect(sqlite3_vtab *pVtab){
129   CidxTable *pTab = (CidxTable*)pVtab;
130   sqlite3_free(pTab);
131   return SQLITE_OK;
132 }
133 
134 /*
135 ** idxNum and idxStr are not used.  There are only three possible plans,
136 ** which are all distinguished by the number of parameters.
137 **
138 **   No parameters:         A degenerate plan.  The result is zero rows.
139 **   1 Parameter:           Scan all of the index starting with first entry
140 **   2 parameters:          Scan the index starting after the "after_key".
141 **
142 ** Provide successively smaller costs for each of these plans to encourage
143 ** the query planner to select the one with the most parameters.
144 */
cidxBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pInfo)145 static int cidxBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pInfo){
146   int iIdxName = -1;
147   int iAfterKey = -1;
148   int i;
149 
150   for(i=0; i<pInfo->nConstraint; i++){
151     struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
152     if( p->usable==0 ) continue;
153     if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
154 
155     if( p->iColumn==IIC_INDEX_NAME ){
156       iIdxName = i;
157     }
158     if( p->iColumn==IIC_AFTER_KEY ){
159       iAfterKey = i;
160     }
161   }
162 
163   if( iIdxName<0 ){
164     pInfo->estimatedCost = 1000000000.0;
165   }else{
166     pInfo->aConstraintUsage[iIdxName].argvIndex = 1;
167     pInfo->aConstraintUsage[iIdxName].omit = 1;
168     if( iAfterKey<0 ){
169       pInfo->estimatedCost = 1000000.0;
170     }else{
171       pInfo->aConstraintUsage[iAfterKey].argvIndex = 2;
172       pInfo->aConstraintUsage[iAfterKey].omit = 1;
173       pInfo->estimatedCost = 1000.0;
174     }
175   }
176 
177   return SQLITE_OK;
178 }
179 
180 /*
181 ** Open a new btreeinfo cursor.
182 */
cidxOpen(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCursor)183 static int cidxOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
184   CidxCursor *pRet;
185   int rc = SQLITE_OK;
186 
187   pRet = cidxMalloc(&rc, sizeof(CidxCursor));
188 
189   *ppCursor = (sqlite3_vtab_cursor*)pRet;
190   return rc;
191 }
192 
193 /*
194 ** Close a btreeinfo cursor.
195 */
cidxClose(sqlite3_vtab_cursor * pCursor)196 static int cidxClose(sqlite3_vtab_cursor *pCursor){
197   CidxCursor *pCsr = (CidxCursor*)pCursor;
198   sqlite3_finalize(pCsr->pStmt);
199   sqlite3_free(pCsr->zIdxName);
200   sqlite3_free(pCsr->zAfterKey);
201   sqlite3_free(pCsr);
202   return SQLITE_OK;
203 }
204 
205 /*
206 ** Move a btreeinfo cursor to the next entry in the file.
207 */
cidxNext(sqlite3_vtab_cursor * pCursor)208 static int cidxNext(sqlite3_vtab_cursor *pCursor){
209   CidxCursor *pCsr = (CidxCursor*)pCursor;
210   int rc = sqlite3_step(pCsr->pStmt);
211   if( rc!=SQLITE_ROW ){
212     rc = sqlite3_finalize(pCsr->pStmt);
213     pCsr->pStmt = 0;
214     if( rc!=SQLITE_OK ){
215       sqlite3 *db = ((CidxTable*)pCsr->base.pVtab)->db;
216       cidxCursorError(pCsr, "Cursor error: %s", sqlite3_errmsg(db));
217     }
218   }else{
219     pCsr->iRowid++;
220     rc = SQLITE_OK;
221   }
222   return rc;
223 }
224 
225 /* We have reached EOF if previous sqlite3_step() returned
226 ** anything other than SQLITE_ROW;
227 */
cidxEof(sqlite3_vtab_cursor * pCursor)228 static int cidxEof(sqlite3_vtab_cursor *pCursor){
229   CidxCursor *pCsr = (CidxCursor*)pCursor;
230   return pCsr->pStmt==0;
231 }
232 
cidxMprintf(int * pRc,const char * zFmt,...)233 static char *cidxMprintf(int *pRc, const char *zFmt, ...){
234   char *zRet = 0;
235   va_list ap;
236   va_start(ap, zFmt);
237   zRet = sqlite3_vmprintf(zFmt, ap);
238   if( *pRc==SQLITE_OK ){
239     if( zRet==0 ){
240       *pRc = SQLITE_NOMEM;
241     }
242   }else{
243     sqlite3_free(zRet);
244     zRet = 0;
245   }
246   va_end(ap);
247   return zRet;
248 }
249 
cidxPrepare(int * pRc,CidxCursor * pCsr,const char * zFmt,...)250 static sqlite3_stmt *cidxPrepare(
251   int *pRc, CidxCursor *pCsr, const char *zFmt, ...
252 ){
253   sqlite3_stmt *pRet = 0;
254   char *zSql;
255   va_list ap;                     /* ... printf arguments */
256   va_start(ap, zFmt);
257 
258   zSql = sqlite3_vmprintf(zFmt, ap);
259   if( *pRc==SQLITE_OK ){
260     if( zSql==0 ){
261       *pRc = SQLITE_NOMEM;
262     }else{
263       sqlite3 *db = ((CidxTable*)pCsr->base.pVtab)->db;
264       *pRc = sqlite3_prepare_v2(db, zSql, -1, &pRet, 0);
265       if( *pRc!=SQLITE_OK ){
266         cidxCursorError(pCsr, "SQL error: %s", sqlite3_errmsg(db));
267       }
268     }
269   }
270   sqlite3_free(zSql);
271   va_end(ap);
272 
273   return pRet;
274 }
275 
cidxFinalize(int * pRc,sqlite3_stmt * pStmt)276 static void cidxFinalize(int *pRc, sqlite3_stmt *pStmt){
277   int rc = sqlite3_finalize(pStmt);
278   if( *pRc==SQLITE_OK ) *pRc = rc;
279 }
280 
cidxStrdup(int * pRc,const char * zStr)281 char *cidxStrdup(int *pRc, const char *zStr){
282   char *zRet = 0;
283   if( *pRc==SQLITE_OK ){
284     int n = (int)strlen(zStr);
285     zRet = cidxMalloc(pRc, n+1);
286     if( zRet ) memcpy(zRet, zStr, n+1);
287   }
288   return zRet;
289 }
290 
cidxFreeIndex(CidxIndex * pIdx)291 static void cidxFreeIndex(CidxIndex *pIdx){
292   if( pIdx ){
293     int i;
294     for(i=0; i<pIdx->nCol; i++){
295       sqlite3_free(pIdx->aCol[i].zExpr);
296     }
297     sqlite3_free(pIdx->zWhere);
298     sqlite3_free(pIdx);
299   }
300 }
301 
cidx_isspace(char c)302 static int cidx_isspace(char c){
303   return c==' ' || c=='\t' || c=='\r' || c=='\n';
304 }
305 
cidx_isident(char c)306 static int cidx_isident(char c){
307   return c<0
308     || (c>='0' && c<='9') || (c>='a' && c<='z')
309     || (c>='A' && c<='Z') || c=='_';
310 }
311 
312 #define CIDX_PARSE_EOF   0
313 #define CIDX_PARSE_COMMA 1      /*  "," */
314 #define CIDX_PARSE_OPEN  2      /*  "(" */
315 #define CIDX_PARSE_CLOSE 3      /*  ")" */
316 
317 /*
318 ** Argument zIn points into the start, middle or end of a CREATE INDEX
319 ** statement. If argument pbDoNotTrim is non-NULL, then this function
320 ** scans the input until it finds EOF, a comma (",") or an open or
321 ** close parenthesis character. It then sets (*pzOut) to point to said
322 ** character and returns a CIDX_PARSE_XXX constant as appropriate. The
323 ** parser is smart enough that special characters inside SQL strings
324 ** or comments are not returned for.
325 **
326 ** Or, if argument pbDoNotTrim is NULL, then this function sets *pzOut
327 ** to point to the first character of the string that is not whitespace
328 ** or part of an SQL comment and returns CIDX_PARSE_EOF.
329 **
330 ** Additionally, if pbDoNotTrim is not NULL and the element immediately
331 ** before (*pzOut) is an SQL comment of the form "-- comment", then
332 ** (*pbDoNotTrim) is set before returning. In all other cases it is
333 ** cleared.
334 */
cidxFindNext(const char * zIn,const char ** pzOut,int * pbDoNotTrim)335 static int cidxFindNext(
336   const char *zIn,
337   const char **pzOut,
338   int *pbDoNotTrim                /* OUT: True if prev is -- comment */
339 ){
340   const char *z = zIn;
341 
342   while( 1 ){
343     while( cidx_isspace(*z) ) z++;
344     if( z[0]=='-' && z[1]=='-' ){
345       z += 2;
346       while( z[0]!='\n' ){
347         if( z[0]=='\0' ) return CIDX_PARSE_EOF;
348         z++;
349       }
350       while( cidx_isspace(*z) ) z++;
351       if( pbDoNotTrim ) *pbDoNotTrim = 1;
352     }else
353     if( z[0]=='/' && z[1]=='*' ){
354       z += 2;
355       while( z[0]!='*' || z[1]!='/' ){
356         if( z[1]=='\0' ) return CIDX_PARSE_EOF;
357         z++;
358       }
359       z += 2;
360     }else{
361       *pzOut = z;
362       if( pbDoNotTrim==0 ) return CIDX_PARSE_EOF;
363       switch( *z ){
364         case '\0':
365           return CIDX_PARSE_EOF;
366         case '(':
367           return CIDX_PARSE_OPEN;
368         case ')':
369           return CIDX_PARSE_CLOSE;
370         case ',':
371           return CIDX_PARSE_COMMA;
372 
373         case '"':
374         case '\'':
375         case '`': {
376           char q = *z;
377           z++;
378           while( *z ){
379             if( *z==q ){
380               z++;
381               if( *z!=q ) break;
382             }
383             z++;
384           }
385           break;
386         }
387 
388         case '[':
389           while( *z++!=']' );
390           break;
391 
392         default:
393           z++;
394           break;
395       }
396       *pbDoNotTrim = 0;
397     }
398   }
399 
400   assert( 0 );
401   return -1;
402 }
403 
cidxParseSQL(CidxCursor * pCsr,CidxIndex * pIdx,const char * zSql)404 static int cidxParseSQL(CidxCursor *pCsr, CidxIndex *pIdx, const char *zSql){
405   const char *z = zSql;
406   const char *z1;
407   int e;
408   int rc = SQLITE_OK;
409   int nParen = 1;
410   int bDoNotTrim = 0;
411   CidxColumn *pCol = pIdx->aCol;
412 
413   e = cidxFindNext(z, &z, &bDoNotTrim);
414   if( e!=CIDX_PARSE_OPEN ) goto parse_error;
415   z1 = z+1;
416   z++;
417   while( nParen>0 ){
418     e = cidxFindNext(z, &z, &bDoNotTrim);
419     if( e==CIDX_PARSE_EOF ) goto parse_error;
420     if( (e==CIDX_PARSE_COMMA || e==CIDX_PARSE_CLOSE) && nParen==1 ){
421       const char *z2 = z;
422       if( pCol->zExpr ) goto parse_error;
423 
424       if( bDoNotTrim==0 ){
425         while( cidx_isspace(z[-1]) ) z--;
426         if( !sqlite3_strnicmp(&z[-3], "asc", 3) && 0==cidx_isident(z[-4]) ){
427           z -= 3;
428           while( cidx_isspace(z[-1]) ) z--;
429         }else
430           if( !sqlite3_strnicmp(&z[-4], "desc", 4) && 0==cidx_isident(z[-5]) ){
431             z -= 4;
432             while( cidx_isspace(z[-1]) ) z--;
433           }
434         while( cidx_isspace(z1[0]) ) z1++;
435       }
436 
437       pCol->zExpr = cidxMprintf(&rc, "%.*s", z-z1, z1);
438       pCol++;
439       z = z1 = z2+1;
440     }
441     if( e==CIDX_PARSE_OPEN ) nParen++;
442     if( e==CIDX_PARSE_CLOSE ) nParen--;
443     z++;
444   }
445 
446   /* Search for a WHERE clause */
447   cidxFindNext(z, &z, 0);
448   if( 0==sqlite3_strnicmp(z, "where", 5) ){
449     pIdx->zWhere = cidxMprintf(&rc, "%s\n", &z[5]);
450   }else if( z[0]!='\0' ){
451     goto parse_error;
452   }
453 
454   return rc;
455 
456  parse_error:
457   cidxCursorError(pCsr, "Parse error in: %s", zSql);
458   return SQLITE_ERROR;
459 }
460 
cidxLookupIndex(CidxCursor * pCsr,const char * zIdx,CidxIndex ** ppIdx,char ** pzTab)461 static int cidxLookupIndex(
462   CidxCursor *pCsr,               /* Cursor object */
463   const char *zIdx,               /* Name of index to look up */
464   CidxIndex **ppIdx,              /* OUT: Description of columns */
465   char **pzTab                    /* OUT: Table name */
466 ){
467   int rc = SQLITE_OK;
468   char *zTab = 0;
469   CidxIndex *pIdx = 0;
470 
471   sqlite3_stmt *pFindTab = 0;
472   sqlite3_stmt *pInfo = 0;
473 
474   /* Find the table for this index. */
475   pFindTab = cidxPrepare(&rc, pCsr,
476       "SELECT tbl_name, sql FROM sqlite_schema WHERE name=%Q AND type='index'",
477       zIdx
478   );
479   if( rc==SQLITE_OK && sqlite3_step(pFindTab)==SQLITE_ROW ){
480     const char *zSql = (const char*)sqlite3_column_text(pFindTab, 1);
481     zTab = cidxStrdup(&rc, (const char*)sqlite3_column_text(pFindTab, 0));
482 
483     pInfo = cidxPrepare(&rc, pCsr, "PRAGMA index_xinfo(%Q)", zIdx);
484     if( rc==SQLITE_OK ){
485       int nAlloc = 0;
486       int iCol = 0;
487 
488       while( sqlite3_step(pInfo)==SQLITE_ROW ){
489         const char *zName = (const char*)sqlite3_column_text(pInfo, 2);
490         const char *zColl = (const char*)sqlite3_column_text(pInfo, 4);
491         CidxColumn *p;
492         if( zName==0 ) zName = "rowid";
493         if( iCol==nAlloc ){
494           int nByte = sizeof(CidxIndex) + sizeof(CidxColumn)*(nAlloc+8);
495           pIdx = (CidxIndex*)sqlite3_realloc(pIdx, nByte);
496           nAlloc += 8;
497         }
498         p = &pIdx->aCol[iCol++];
499         p->bDesc = sqlite3_column_int(pInfo, 3);
500         p->bKey = sqlite3_column_int(pInfo, 5);
501         if( zSql==0 || p->bKey==0 ){
502           p->zExpr = cidxMprintf(&rc, "\"%w\" COLLATE %s",zName,zColl);
503         }else{
504           p->zExpr = 0;
505         }
506         pIdx->nCol = iCol;
507         pIdx->zWhere = 0;
508       }
509       cidxFinalize(&rc, pInfo);
510     }
511 
512     if( rc==SQLITE_OK && zSql ){
513       rc = cidxParseSQL(pCsr, pIdx, zSql);
514     }
515   }
516 
517   cidxFinalize(&rc, pFindTab);
518   if( rc==SQLITE_OK && zTab==0 ){
519     rc = SQLITE_ERROR;
520   }
521 
522   if( rc!=SQLITE_OK ){
523     sqlite3_free(zTab);
524     cidxFreeIndex(pIdx);
525   }else{
526     *pzTab = zTab;
527     *ppIdx = pIdx;
528   }
529 
530   return rc;
531 }
532 
cidxDecodeAfter(CidxCursor * pCsr,int nCol,const char * zAfterKey,char *** pazAfter)533 static int cidxDecodeAfter(
534   CidxCursor *pCsr,
535   int nCol,
536   const char *zAfterKey,
537   char ***pazAfter
538 ){
539   char **azAfter;
540   int rc = SQLITE_OK;
541   int nAfterKey = (int)strlen(zAfterKey);
542 
543   azAfter = cidxMalloc(&rc, sizeof(char*)*nCol + nAfterKey+1);
544   if( rc==SQLITE_OK ){
545     int i;
546     char *zCopy = (char*)&azAfter[nCol];
547     char *p = zCopy;
548     memcpy(zCopy, zAfterKey, nAfterKey+1);
549     for(i=0; i<nCol; i++){
550       while( *p==' ' ) p++;
551 
552       /* Check NULL values */
553       if( *p=='N' ){
554         if( memcmp(p, "NULL", 4) ) goto parse_error;
555         p += 4;
556       }
557 
558       /* Check strings and blob literals */
559       else if( *p=='X' || *p=='\'' ){
560         azAfter[i] = p;
561         if( *p=='X' ) p++;
562         if( *p!='\'' ) goto parse_error;
563         p++;
564         while( 1 ){
565           if( *p=='\0' ) goto parse_error;
566           if( *p=='\'' ){
567             p++;
568             if( *p!='\'' ) break;
569           }
570           p++;
571         }
572       }
573 
574       /* Check numbers */
575       else{
576         azAfter[i] = p;
577         while( (*p>='0' && *p<='9')
578             || *p=='.' || *p=='+' || *p=='-' || *p=='e' || *p=='E'
579         ){
580           p++;
581         }
582       }
583 
584       while( *p==' ' ) p++;
585       if( *p!=(i==(nCol-1) ? '\0' : ',') ){
586         goto parse_error;
587       }
588       *p++ = '\0';
589     }
590   }
591 
592   *pazAfter = azAfter;
593   return rc;
594 
595  parse_error:
596   sqlite3_free(azAfter);
597   *pazAfter = 0;
598   cidxCursorError(pCsr, "%s", "error parsing after value");
599   return SQLITE_ERROR;
600 }
601 
cidxWhere(int * pRc,CidxColumn * aCol,char ** azAfter,int iGt,int bLastIsNull)602 static char *cidxWhere(
603   int *pRc, CidxColumn *aCol, char **azAfter, int iGt, int bLastIsNull
604 ){
605   char *zRet = 0;
606   const char *zSep = "";
607   int i;
608 
609   for(i=0; i<iGt; i++){
610     zRet = cidxMprintf(pRc, "%z%s(%s) IS %s", zRet,
611         zSep, aCol[i].zExpr, (azAfter[i] ? azAfter[i] : "NULL")
612     );
613     zSep = " AND ";
614   }
615 
616   if( bLastIsNull ){
617     zRet = cidxMprintf(pRc, "%z%s(%s) IS NULL", zRet, zSep, aCol[iGt].zExpr);
618   }
619   else if( azAfter[iGt] ){
620     zRet = cidxMprintf(pRc, "%z%s(%s) %s %s", zRet,
621         zSep, aCol[iGt].zExpr, (aCol[iGt].bDesc ? "<" : ">"),
622         azAfter[iGt]
623     );
624   }else{
625     zRet = cidxMprintf(pRc, "%z%s(%s) IS NOT NULL", zRet, zSep,aCol[iGt].zExpr);
626   }
627 
628   return zRet;
629 }
630 
631 #define CIDX_CLIST_ALL         0
632 #define CIDX_CLIST_ORDERBY     1
633 #define CIDX_CLIST_CURRENT_KEY 2
634 #define CIDX_CLIST_SUBWHERE    3
635 #define CIDX_CLIST_SUBEXPR     4
636 
637 /*
638 ** This function returns various strings based on the contents of the
639 ** CidxIndex structure and the eType parameter.
640 */
cidxColumnList(int * pRc,const char * zIdx,CidxIndex * pIdx,int eType)641 static char *cidxColumnList(
642   int *pRc,                       /* IN/OUT: Error code */
643   const char *zIdx,
644   CidxIndex *pIdx,                /* Indexed columns */
645   int eType                       /* True to include ASC/DESC */
646 ){
647   char *zRet = 0;
648   if( *pRc==SQLITE_OK ){
649     const char *aDir[2] = {"", " DESC"};
650     int i;
651     const char *zSep = "";
652 
653     for(i=0; i<pIdx->nCol; i++){
654       CidxColumn *p = &pIdx->aCol[i];
655       assert( pIdx->aCol[i].bDesc==0 || pIdx->aCol[i].bDesc==1 );
656       switch( eType ){
657 
658         case CIDX_CLIST_ORDERBY:
659           zRet = cidxMprintf(pRc, "%z%s%d%s", zRet, zSep, i+1, aDir[p->bDesc]);
660           zSep = ",";
661           break;
662 
663         case CIDX_CLIST_CURRENT_KEY:
664           zRet = cidxMprintf(pRc, "%z%squote(i%d)", zRet, zSep, i);
665           zSep = "||','||";
666           break;
667 
668         case CIDX_CLIST_SUBWHERE:
669           if( p->bKey==0 ){
670             zRet = cidxMprintf(pRc, "%z%s%s IS i.i%d", zRet,
671                 zSep, p->zExpr, i
672             );
673             zSep = " AND ";
674           }
675           break;
676 
677         case CIDX_CLIST_SUBEXPR:
678           if( p->bKey==1 ){
679             zRet = cidxMprintf(pRc, "%z%s%s IS i.i%d", zRet,
680                 zSep, p->zExpr, i
681             );
682             zSep = " AND ";
683           }
684           break;
685 
686         default:
687           assert( eType==CIDX_CLIST_ALL );
688           zRet = cidxMprintf(pRc, "%z%s(%s) AS i%d", zRet, zSep, p->zExpr, i);
689           zSep = ", ";
690           break;
691       }
692     }
693   }
694 
695   return zRet;
696 }
697 
698 /*
699 ** Generate SQL (in memory obtained from sqlite3_malloc()) that will
700 ** continue the index scan for zIdxName starting after zAfterKey.
701 */
cidxGenerateScanSql(CidxCursor * pCsr,const char * zIdxName,const char * zAfterKey,char ** pzSqlOut)702 int cidxGenerateScanSql(
703   CidxCursor *pCsr,           /* The cursor which needs the new statement */
704   const char *zIdxName,       /* index to be scanned */
705   const char *zAfterKey,      /* start after this key, if not NULL */
706   char **pzSqlOut             /* OUT: Write the generated SQL here */
707 ){
708   int rc;
709   char *zTab = 0;
710   char *zCurrentKey = 0;
711   char *zOrderBy = 0;
712   char *zSubWhere = 0;
713   char *zSubExpr = 0;
714   char *zSrcList = 0;
715   char **azAfter = 0;
716   CidxIndex *pIdx = 0;
717 
718   *pzSqlOut = 0;
719   rc = cidxLookupIndex(pCsr, zIdxName, &pIdx, &zTab);
720 
721   zOrderBy = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_ORDERBY);
722   zCurrentKey = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_CURRENT_KEY);
723   zSubWhere = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_SUBWHERE);
724   zSubExpr = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_SUBEXPR);
725   zSrcList = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_ALL);
726 
727   if( rc==SQLITE_OK && zAfterKey ){
728     rc = cidxDecodeAfter(pCsr, pIdx->nCol, zAfterKey, &azAfter);
729   }
730 
731   if( rc==SQLITE_OK ){
732     if( zAfterKey==0 ){
733       *pzSqlOut = cidxMprintf(&rc,
734           "SELECT (SELECT %s FROM %Q AS t WHERE %s), %s "
735           "FROM (SELECT %s FROM %Q INDEXED BY %Q %s%sORDER BY %s) AS i",
736           zSubExpr, zTab, zSubWhere, zCurrentKey,
737           zSrcList, zTab, zIdxName,
738           (pIdx->zWhere ? "WHERE " : ""), (pIdx->zWhere ? pIdx->zWhere : ""),
739           zOrderBy
740       );
741     }else{
742       const char *zSep = "";
743       char *zSql;
744       int i;
745 
746       zSql = cidxMprintf(&rc,
747           "SELECT (SELECT %s FROM %Q WHERE %s), %s FROM (",
748           zSubExpr, zTab, zSubWhere, zCurrentKey
749       );
750       for(i=pIdx->nCol-1; i>=0; i--){
751         int j;
752         if( pIdx->aCol[i].bDesc && azAfter[i]==0 ) continue;
753         for(j=0; j<2; j++){
754           char *zWhere = cidxWhere(&rc, pIdx->aCol, azAfter, i, j);
755           zSql = cidxMprintf(&rc, "%z"
756               "%sSELECT * FROM ("
757                 "SELECT %s FROM %Q INDEXED BY %Q WHERE %s%s%z ORDER BY %s"
758               ")",
759               zSql, zSep, zSrcList, zTab, zIdxName,
760               pIdx->zWhere ? pIdx->zWhere : "",
761               pIdx->zWhere ? " AND " : "",
762               zWhere, zOrderBy
763           );
764           zSep = " UNION ALL ";
765           if( pIdx->aCol[i].bDesc==0 ) break;
766         }
767       }
768       *pzSqlOut = cidxMprintf(&rc, "%z) AS i", zSql);
769     }
770   }
771 
772   sqlite3_free(zTab);
773   sqlite3_free(zCurrentKey);
774   sqlite3_free(zOrderBy);
775   sqlite3_free(zSubWhere);
776   sqlite3_free(zSubExpr);
777   sqlite3_free(zSrcList);
778   cidxFreeIndex(pIdx);
779   sqlite3_free(azAfter);
780   return rc;
781 }
782 
783 
784 /*
785 ** Position a cursor back to the beginning.
786 */
cidxFilter(sqlite3_vtab_cursor * pCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)787 static int cidxFilter(
788   sqlite3_vtab_cursor *pCursor,
789   int idxNum, const char *idxStr,
790   int argc, sqlite3_value **argv
791 ){
792   int rc = SQLITE_OK;
793   CidxCursor *pCsr = (CidxCursor*)pCursor;
794   const char *zIdxName = 0;
795   const char *zAfterKey = 0;
796 
797   sqlite3_free(pCsr->zIdxName);
798   pCsr->zIdxName = 0;
799   sqlite3_free(pCsr->zAfterKey);
800   pCsr->zAfterKey = 0;
801   sqlite3_finalize(pCsr->pStmt);
802   pCsr->pStmt = 0;
803 
804   if( argc>0 ){
805     zIdxName = (const char*)sqlite3_value_text(argv[0]);
806     if( argc>1 ){
807       zAfterKey = (const char*)sqlite3_value_text(argv[1]);
808     }
809   }
810 
811   if( zIdxName ){
812     char *zSql = 0;
813     pCsr->zIdxName = sqlite3_mprintf("%s", zIdxName);
814     pCsr->zAfterKey = zAfterKey ? sqlite3_mprintf("%s", zAfterKey) : 0;
815     rc = cidxGenerateScanSql(pCsr, zIdxName, zAfterKey, &zSql);
816     if( zSql ){
817       pCsr->pStmt = cidxPrepare(&rc, pCsr, "%z", zSql);
818     }
819   }
820 
821   if( pCsr->pStmt ){
822     assert( rc==SQLITE_OK );
823     rc = cidxNext(pCursor);
824   }
825   pCsr->iRowid = 1;
826   return rc;
827 }
828 
829 /*
830 ** Return a column value.
831 */
cidxColumn(sqlite3_vtab_cursor * pCursor,sqlite3_context * ctx,int iCol)832 static int cidxColumn(
833   sqlite3_vtab_cursor *pCursor,
834   sqlite3_context *ctx,
835   int iCol
836 ){
837   CidxCursor *pCsr = (CidxCursor*)pCursor;
838   assert( iCol>=IIC_ERRMSG && iCol<=IIC_SCANNER_SQL );
839   switch( iCol ){
840     case IIC_ERRMSG: {
841       const char *zVal = 0;
842       if( sqlite3_column_type(pCsr->pStmt, 0)==SQLITE_INTEGER ){
843         if( sqlite3_column_int(pCsr->pStmt, 0)==0 ){
844           zVal = "row data mismatch";
845         }
846       }else{
847         zVal = "row missing";
848       }
849       sqlite3_result_text(ctx, zVal, -1, SQLITE_STATIC);
850       break;
851     }
852     case IIC_CURRENT_KEY: {
853       sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, 1));
854       break;
855     }
856     case IIC_INDEX_NAME: {
857       sqlite3_result_text(ctx, pCsr->zIdxName, -1, SQLITE_TRANSIENT);
858       break;
859     }
860     case IIC_AFTER_KEY: {
861       sqlite3_result_text(ctx, pCsr->zAfterKey, -1, SQLITE_TRANSIENT);
862       break;
863     }
864     case IIC_SCANNER_SQL: {
865       char *zSql = 0;
866       cidxGenerateScanSql(pCsr, pCsr->zIdxName, pCsr->zAfterKey, &zSql);
867       sqlite3_result_text(ctx, zSql, -1, sqlite3_free);
868       break;
869     }
870   }
871   return SQLITE_OK;
872 }
873 
874 /* Return the ROWID for the sqlite_btreeinfo table */
cidxRowid(sqlite3_vtab_cursor * pCursor,sqlite_int64 * pRowid)875 static int cidxRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
876   CidxCursor *pCsr = (CidxCursor*)pCursor;
877   *pRowid = pCsr->iRowid;
878   return SQLITE_OK;
879 }
880 
881 /*
882 ** Register the virtual table modules with the database handle passed
883 ** as the only argument.
884 */
ciInit(sqlite3 * db)885 static int ciInit(sqlite3 *db){
886   static sqlite3_module cidx_module = {
887     0,                            /* iVersion */
888     0,                            /* xCreate */
889     cidxConnect,                  /* xConnect */
890     cidxBestIndex,                /* xBestIndex */
891     cidxDisconnect,               /* xDisconnect */
892     0,                            /* xDestroy */
893     cidxOpen,                     /* xOpen - open a cursor */
894     cidxClose,                    /* xClose - close a cursor */
895     cidxFilter,                   /* xFilter - configure scan constraints */
896     cidxNext,                     /* xNext - advance a cursor */
897     cidxEof,                      /* xEof - check for end of scan */
898     cidxColumn,                   /* xColumn - read data */
899     cidxRowid,                    /* xRowid - read data */
900     0,                            /* xUpdate */
901     0,                            /* xBegin */
902     0,                            /* xSync */
903     0,                            /* xCommit */
904     0,                            /* xRollback */
905     0,                            /* xFindMethod */
906     0,                            /* xRename */
907     0,                            /* xSavepoint */
908     0,                            /* xRelease */
909     0,                            /* xRollbackTo */
910   };
911   return sqlite3_create_module(db, "incremental_index_check", &cidx_module, 0);
912 }
913 
914 /*
915 ** Extension load function.
916 */
917 #ifdef _WIN32
918 __declspec(dllexport)
919 #endif
sqlite3_checkindex_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)920 int sqlite3_checkindex_init(
921   sqlite3 *db,
922   char **pzErrMsg,
923   const sqlite3_api_routines *pApi
924 ){
925   SQLITE_EXTENSION_INIT2(pApi);
926   return ciInit(db);
927 }
928