xref: /sqlite-3.40.0/ext/expert/sqlite3expert.c (revision 217635f7)
18e0b8e06Sdan /*
296d43a05Sdan ** 2017 April 09
38e0b8e06Sdan **
48e0b8e06Sdan ** The author disclaims copyright to this source code.  In place of
58e0b8e06Sdan ** a legal notice, here is a blessing:
68e0b8e06Sdan **
78e0b8e06Sdan **    May you do good and not evil.
88e0b8e06Sdan **    May you find forgiveness for yourself and forgive others.
98e0b8e06Sdan **    May you share freely, never taking more than you give.
108e0b8e06Sdan **
118e0b8e06Sdan *************************************************************************
128e0b8e06Sdan */
138e0b8e06Sdan #include "sqlite3expert.h"
148e0b8e06Sdan #include <assert.h>
158e0b8e06Sdan #include <string.h>
168e0b8e06Sdan #include <stdio.h>
178e0b8e06Sdan 
1811a9ad56Sdrh #if !defined(SQLITE_AMALGAMATION)
1911a9ad56Sdrh #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
2011a9ad56Sdrh # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
2111a9ad56Sdrh #endif
2211a9ad56Sdrh #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
2311a9ad56Sdrh # define ALWAYS(X)      (1)
2411a9ad56Sdrh # define NEVER(X)       (0)
2511a9ad56Sdrh #elif !defined(NDEBUG)
2611a9ad56Sdrh # define ALWAYS(X)      ((X)?1:(assert(0),0))
2711a9ad56Sdrh # define NEVER(X)       ((X)?(assert(0),1):0)
2811a9ad56Sdrh #else
2911a9ad56Sdrh # define ALWAYS(X)      (X)
3011a9ad56Sdrh # define NEVER(X)       (X)
3111a9ad56Sdrh #endif
3211a9ad56Sdrh #endif /* !defined(SQLITE_AMALGAMATION) */
3311a9ad56Sdrh 
3411a9ad56Sdrh 
35f87ae41fSdan #ifndef SQLITE_OMIT_VIRTUALTABLE
36f87ae41fSdan 
378e0b8e06Sdan typedef sqlite3_int64 i64;
388e0b8e06Sdan typedef sqlite3_uint64 u64;
398e0b8e06Sdan 
4096d43a05Sdan typedef struct IdxColumn IdxColumn;
418e0b8e06Sdan typedef struct IdxConstraint IdxConstraint;
428e0b8e06Sdan typedef struct IdxScan IdxScan;
438e0b8e06Sdan typedef struct IdxStatement IdxStatement;
448e0b8e06Sdan typedef struct IdxTable IdxTable;
45280db65eSdan typedef struct IdxWrite IdxWrite;
468e0b8e06Sdan 
47bd0f1dbdSdrh #define STRLEN  (int)strlen
48bd0f1dbdSdrh 
49c42a0056Sdan /*
50c42a0056Sdan ** A temp table name that we assume no user database will actually use.
51c42a0056Sdan ** If this assumption proves incorrect triggers on the table with the
52c42a0056Sdan ** conflicting name will be ignored.
53c42a0056Sdan */
54e53b4f97Sdan #define UNIQUE_TABLE_NAME "t592690916721053953805701627921227776"
55e53b4f97Sdan 
568e0b8e06Sdan /*
5796d43a05Sdan ** A single constraint. Equivalent to either "col = ?" or "col < ?" (or
5896d43a05Sdan ** any other type of single-ended range constraint on a column).
598e0b8e06Sdan **
608e0b8e06Sdan ** pLink:
618e0b8e06Sdan **   Used to temporarily link IdxConstraint objects into lists while
628e0b8e06Sdan **   creating candidate indexes.
638e0b8e06Sdan */
648e0b8e06Sdan struct IdxConstraint {
658e0b8e06Sdan   char *zColl;                    /* Collation sequence */
668e0b8e06Sdan   int bRange;                     /* True for range, false for eq */
678e0b8e06Sdan   int iCol;                       /* Constrained table column */
688e0b8e06Sdan   int bFlag;                      /* Used by idxFindCompatible() */
698e0b8e06Sdan   int bDesc;                      /* True if ORDER BY <expr> DESC */
708e0b8e06Sdan   IdxConstraint *pNext;           /* Next constraint in pEq or pRange list */
718e0b8e06Sdan   IdxConstraint *pLink;           /* See above */
728e0b8e06Sdan };
738e0b8e06Sdan 
748e0b8e06Sdan /*
758e0b8e06Sdan ** A single scan of a single table.
768e0b8e06Sdan */
778e0b8e06Sdan struct IdxScan {
780824ccf2Sdan   IdxTable *pTab;                 /* Associated table object */
798e0b8e06Sdan   int iDb;                        /* Database containing table zTable */
808e0b8e06Sdan   i64 covering;                   /* Mask of columns required for cov. index */
818e0b8e06Sdan   IdxConstraint *pOrder;          /* ORDER BY columns */
8296d43a05Sdan   IdxConstraint *pEq;             /* List of == constraints */
8396d43a05Sdan   IdxConstraint *pRange;          /* List of < constraints */
8496d43a05Sdan   IdxScan *pNextScan;             /* Next IdxScan object for same analysis */
858e0b8e06Sdan };
868e0b8e06Sdan 
878e0b8e06Sdan /*
8896d43a05Sdan ** Information regarding a single database table. Extracted from
8996d43a05Sdan ** "PRAGMA table_info" by function idxGetTableInfo().
908e0b8e06Sdan */
918e0b8e06Sdan struct IdxColumn {
928e0b8e06Sdan   char *zName;
938e0b8e06Sdan   char *zColl;
948e0b8e06Sdan   int iPk;
958e0b8e06Sdan };
968e0b8e06Sdan struct IdxTable {
978e0b8e06Sdan   int nCol;
980824ccf2Sdan   char *zName;                    /* Table name */
998e0b8e06Sdan   IdxColumn *aCol;
1000824ccf2Sdan   IdxTable *pNext;                /* Next table in linked list of all tables */
1018e0b8e06Sdan };
1028e0b8e06Sdan 
10396d43a05Sdan /*
104280db65eSdan ** An object of the following type is created for each unique table/write-op
105280db65eSdan ** seen. The objects are stored in a singly-linked list beginning at
106280db65eSdan ** sqlite3expert.pWrite.
107280db65eSdan */
108280db65eSdan struct IdxWrite {
109280db65eSdan   IdxTable *pTab;
110280db65eSdan   int eOp;                        /* SQLITE_UPDATE, DELETE or INSERT */
111280db65eSdan   IdxWrite *pNext;
112280db65eSdan };
113280db65eSdan 
114280db65eSdan /*
11596d43a05Sdan ** Each statement being analyzed is represented by an instance of this
11696d43a05Sdan ** structure.
11796d43a05Sdan */
1188e0b8e06Sdan struct IdxStatement {
1198e0b8e06Sdan   int iId;                        /* Statement number */
1208e0b8e06Sdan   char *zSql;                     /* SQL statement */
1218e0b8e06Sdan   char *zIdx;                     /* Indexes */
1228e0b8e06Sdan   char *zEQP;                     /* Plan */
1238e0b8e06Sdan   IdxStatement *pNext;
1248e0b8e06Sdan };
1258e0b8e06Sdan 
12665e67ed1Sdan 
12796d43a05Sdan /*
12896d43a05Sdan ** A hash table for storing strings. With space for a payload string
12996d43a05Sdan ** with each entry. Methods are:
13096d43a05Sdan **
13196d43a05Sdan **   idxHashInit()
13296d43a05Sdan **   idxHashClear()
13396d43a05Sdan **   idxHashAdd()
13496d43a05Sdan **   idxHashSearch()
13596d43a05Sdan */
13665e67ed1Sdan #define IDX_HASH_SIZE 1023
13765e67ed1Sdan typedef struct IdxHashEntry IdxHashEntry;
13865e67ed1Sdan typedef struct IdxHash IdxHash;
13965e67ed1Sdan struct IdxHashEntry {
14065e67ed1Sdan   char *zKey;                     /* nul-terminated key */
14165e67ed1Sdan   char *zVal;                     /* nul-terminated value string */
142a6ed5a4fSdan   char *zVal2;                    /* nul-terminated value string 2 */
14365e67ed1Sdan   IdxHashEntry *pHashNext;        /* Next entry in same hash bucket */
14465e67ed1Sdan   IdxHashEntry *pNext;            /* Next entry in hash */
14565e67ed1Sdan };
14665e67ed1Sdan struct IdxHash {
14765e67ed1Sdan   IdxHashEntry *pFirst;
14865e67ed1Sdan   IdxHashEntry *aHash[IDX_HASH_SIZE];
14965e67ed1Sdan };
15065e67ed1Sdan 
1518e0b8e06Sdan /*
1528e0b8e06Sdan ** sqlite3expert object.
1538e0b8e06Sdan */
1548e0b8e06Sdan struct sqlite3expert {
155e53b4f97Sdan   int iSample;                    /* Percentage of tables to sample for stat1 */
15696d43a05Sdan   sqlite3 *db;                    /* User database */
1578e0b8e06Sdan   sqlite3 *dbm;                   /* In-memory db for this analysis */
1580824ccf2Sdan   sqlite3 *dbv;                   /* Vtab schema for this analysis */
1590824ccf2Sdan   IdxTable *pTable;               /* List of all IdxTable objects */
1608e0b8e06Sdan   IdxScan *pScan;                 /* List of scan objects */
161280db65eSdan   IdxWrite *pWrite;               /* List of write objects */
1628e0b8e06Sdan   IdxStatement *pStatement;       /* List of IdxStatement objects */
163a4e61024Sdan   int bRun;                       /* True once analysis has run */
164a4e61024Sdan   char **pzErrmsg;
1658e0b8e06Sdan   int rc;                         /* Error code from whereinfo hook */
16665e67ed1Sdan   IdxHash hIdx;                   /* Hash containing all candidate indexes */
167a4e61024Sdan   char *zCandidates;              /* For EXPERT_REPORT_CANDIDATES */
1688e0b8e06Sdan };
1698e0b8e06Sdan 
1708e0b8e06Sdan 
1718e0b8e06Sdan /*
1728e0b8e06Sdan ** Allocate and return nByte bytes of zeroed memory using sqlite3_malloc().
1738e0b8e06Sdan ** If the allocation fails, set *pRc to SQLITE_NOMEM and return NULL.
1748e0b8e06Sdan */
idxMalloc(int * pRc,int nByte)1758e0b8e06Sdan static void *idxMalloc(int *pRc, int nByte){
1768e0b8e06Sdan   void *pRet;
1778e0b8e06Sdan   assert( *pRc==SQLITE_OK );
1788e0b8e06Sdan   assert( nByte>0 );
1798e0b8e06Sdan   pRet = sqlite3_malloc(nByte);
1808e0b8e06Sdan   if( pRet ){
1818e0b8e06Sdan     memset(pRet, 0, nByte);
1828e0b8e06Sdan   }else{
1838e0b8e06Sdan     *pRc = SQLITE_NOMEM;
1848e0b8e06Sdan   }
1858e0b8e06Sdan   return pRet;
1868e0b8e06Sdan }
1878e0b8e06Sdan 
18896d43a05Sdan /*
18996d43a05Sdan ** Initialize an IdxHash hash table.
19096d43a05Sdan */
idxHashInit(IdxHash * pHash)19165e67ed1Sdan static void idxHashInit(IdxHash *pHash){
19265e67ed1Sdan   memset(pHash, 0, sizeof(IdxHash));
19365e67ed1Sdan }
19496d43a05Sdan 
19596d43a05Sdan /*
19696d43a05Sdan ** Reset an IdxHash hash table.
19796d43a05Sdan */
idxHashClear(IdxHash * pHash)19865e67ed1Sdan static void idxHashClear(IdxHash *pHash){
19965e67ed1Sdan   int i;
20065e67ed1Sdan   for(i=0; i<IDX_HASH_SIZE; i++){
20165e67ed1Sdan     IdxHashEntry *pEntry;
20265e67ed1Sdan     IdxHashEntry *pNext;
20365e67ed1Sdan     for(pEntry=pHash->aHash[i]; pEntry; pEntry=pNext){
20465e67ed1Sdan       pNext = pEntry->pHashNext;
205a6ed5a4fSdan       sqlite3_free(pEntry->zVal2);
20665e67ed1Sdan       sqlite3_free(pEntry);
20765e67ed1Sdan     }
20865e67ed1Sdan   }
20965e67ed1Sdan   memset(pHash, 0, sizeof(IdxHash));
21065e67ed1Sdan }
21196d43a05Sdan 
21296d43a05Sdan /*
21396d43a05Sdan ** Return the index of the hash bucket that the string specified by the
21496d43a05Sdan ** arguments to this function belongs.
21596d43a05Sdan */
idxHashString(const char * z,int n)21665e67ed1Sdan static int idxHashString(const char *z, int n){
21765e67ed1Sdan   unsigned int ret = 0;
21865e67ed1Sdan   int i;
21965e67ed1Sdan   for(i=0; i<n; i++){
22065e67ed1Sdan     ret += (ret<<3) + (unsigned char)(z[i]);
22165e67ed1Sdan   }
22265e67ed1Sdan   return (int)(ret % IDX_HASH_SIZE);
22365e67ed1Sdan }
22465e67ed1Sdan 
22596d43a05Sdan /*
22696d43a05Sdan ** If zKey is already present in the hash table, return non-zero and do
22796d43a05Sdan ** nothing. Otherwise, add an entry with key zKey and payload string zVal to
22896d43a05Sdan ** the hash table passed as the second argument.
22996d43a05Sdan */
idxHashAdd(int * pRc,IdxHash * pHash,const char * zKey,const char * zVal)23065e67ed1Sdan static int idxHashAdd(
23165e67ed1Sdan   int *pRc,
23265e67ed1Sdan   IdxHash *pHash,
23365e67ed1Sdan   const char *zKey,
23465e67ed1Sdan   const char *zVal
23565e67ed1Sdan ){
236bd0f1dbdSdrh   int nKey = STRLEN(zKey);
23765e67ed1Sdan   int iHash = idxHashString(zKey, nKey);
238bd0f1dbdSdrh   int nVal = (zVal ? STRLEN(zVal) : 0);
23965e67ed1Sdan   IdxHashEntry *pEntry;
24065e67ed1Sdan   assert( iHash>=0 );
24165e67ed1Sdan   for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){
242bd0f1dbdSdrh     if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){
24365e67ed1Sdan       return 1;
24465e67ed1Sdan     }
24565e67ed1Sdan   }
24665e67ed1Sdan   pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + nKey+1 + nVal+1);
24765e67ed1Sdan   if( pEntry ){
24865e67ed1Sdan     pEntry->zKey = (char*)&pEntry[1];
24965e67ed1Sdan     memcpy(pEntry->zKey, zKey, nKey);
25065e67ed1Sdan     if( zVal ){
25165e67ed1Sdan       pEntry->zVal = &pEntry->zKey[nKey+1];
25265e67ed1Sdan       memcpy(pEntry->zVal, zVal, nVal);
25365e67ed1Sdan     }
25465e67ed1Sdan     pEntry->pHashNext = pHash->aHash[iHash];
25565e67ed1Sdan     pHash->aHash[iHash] = pEntry;
25665e67ed1Sdan 
25765e67ed1Sdan     pEntry->pNext = pHash->pFirst;
25865e67ed1Sdan     pHash->pFirst = pEntry;
25965e67ed1Sdan   }
26065e67ed1Sdan   return 0;
26165e67ed1Sdan }
26265e67ed1Sdan 
263c42a0056Sdan /*
264c42a0056Sdan ** If zKey/nKey is present in the hash table, return a pointer to the
265c42a0056Sdan ** hash-entry object.
266c42a0056Sdan */
idxHashFind(IdxHash * pHash,const char * zKey,int nKey)267a6ed5a4fSdan static IdxHashEntry *idxHashFind(IdxHash *pHash, const char *zKey, int nKey){
26865e67ed1Sdan   int iHash;
26965e67ed1Sdan   IdxHashEntry *pEntry;
270bd0f1dbdSdrh   if( nKey<0 ) nKey = STRLEN(zKey);
27165e67ed1Sdan   iHash = idxHashString(zKey, nKey);
27265e67ed1Sdan   assert( iHash>=0 );
27365e67ed1Sdan   for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){
274bd0f1dbdSdrh     if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){
275a6ed5a4fSdan       return pEntry;
27665e67ed1Sdan     }
27765e67ed1Sdan   }
27865e67ed1Sdan   return 0;
27965e67ed1Sdan }
28065e67ed1Sdan 
28165e67ed1Sdan /*
282a6ed5a4fSdan ** If the hash table contains an entry with a key equal to the string
283a6ed5a4fSdan ** passed as the final two arguments to this function, return a pointer
284a6ed5a4fSdan ** to the payload string. Otherwise, if zKey/nKey is not present in the
285a6ed5a4fSdan ** hash table, return NULL.
286a6ed5a4fSdan */
idxHashSearch(IdxHash * pHash,const char * zKey,int nKey)287a6ed5a4fSdan static const char *idxHashSearch(IdxHash *pHash, const char *zKey, int nKey){
288a6ed5a4fSdan   IdxHashEntry *pEntry = idxHashFind(pHash, zKey, nKey);
289a6ed5a4fSdan   if( pEntry ) return pEntry->zVal;
290a6ed5a4fSdan   return 0;
291a6ed5a4fSdan }
292a6ed5a4fSdan 
293a6ed5a4fSdan /*
2948e0b8e06Sdan ** Allocate and return a new IdxConstraint object. Set the IdxConstraint.zColl
2958e0b8e06Sdan ** variable to point to a copy of nul-terminated string zColl.
2968e0b8e06Sdan */
idxNewConstraint(int * pRc,const char * zColl)2978e0b8e06Sdan static IdxConstraint *idxNewConstraint(int *pRc, const char *zColl){
2988e0b8e06Sdan   IdxConstraint *pNew;
299bd0f1dbdSdrh   int nColl = STRLEN(zColl);
3008e0b8e06Sdan 
3018e0b8e06Sdan   assert( *pRc==SQLITE_OK );
3028e0b8e06Sdan   pNew = (IdxConstraint*)idxMalloc(pRc, sizeof(IdxConstraint) * nColl + 1);
3038e0b8e06Sdan   if( pNew ){
3048e0b8e06Sdan     pNew->zColl = (char*)&pNew[1];
3058e0b8e06Sdan     memcpy(pNew->zColl, zColl, nColl+1);
3068e0b8e06Sdan   }
3078e0b8e06Sdan   return pNew;
3088e0b8e06Sdan }
3098e0b8e06Sdan 
3102ed99defSdan /*
3112ed99defSdan ** An error associated with database handle db has just occurred. Pass
3122ed99defSdan ** the error message to callback function xOut.
3132ed99defSdan */
idxDatabaseError(sqlite3 * db,char ** pzErrmsg)3142ed99defSdan static void idxDatabaseError(
3152ed99defSdan   sqlite3 *db,                    /* Database handle */
3162ed99defSdan   char **pzErrmsg                 /* Write error here */
3172ed99defSdan ){
3182ed99defSdan   *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
3192ed99defSdan }
3202ed99defSdan 
3212ed99defSdan /*
3222ed99defSdan ** Prepare an SQL statement.
3232ed99defSdan */
idxPrepareStmt(sqlite3 * db,sqlite3_stmt ** ppStmt,char ** pzErrmsg,const char * zSql)3242ed99defSdan static int idxPrepareStmt(
3252ed99defSdan   sqlite3 *db,                    /* Database handle to compile against */
3262ed99defSdan   sqlite3_stmt **ppStmt,          /* OUT: Compiled SQL statement */
3272ed99defSdan   char **pzErrmsg,                /* OUT: sqlite3_malloc()ed error message */
3282ed99defSdan   const char *zSql                /* SQL statement to compile */
3292ed99defSdan ){
3302ed99defSdan   int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
3312ed99defSdan   if( rc!=SQLITE_OK ){
3322ed99defSdan     *ppStmt = 0;
3332ed99defSdan     idxDatabaseError(db, pzErrmsg);
3342ed99defSdan   }
3352ed99defSdan   return rc;
3362ed99defSdan }
3372ed99defSdan 
3382ed99defSdan /*
3392ed99defSdan ** Prepare an SQL statement using the results of a printf() formatting.
3402ed99defSdan */
idxPrintfPrepareStmt(sqlite3 * db,sqlite3_stmt ** ppStmt,char ** pzErrmsg,const char * zFmt,...)3412ed99defSdan static int idxPrintfPrepareStmt(
3422ed99defSdan   sqlite3 *db,                    /* Database handle to compile against */
3432ed99defSdan   sqlite3_stmt **ppStmt,          /* OUT: Compiled SQL statement */
3442ed99defSdan   char **pzErrmsg,                /* OUT: sqlite3_malloc()ed error message */
3452ed99defSdan   const char *zFmt,               /* printf() format of SQL statement */
3462ed99defSdan   ...                             /* Trailing printf() arguments */
3472ed99defSdan ){
3482ed99defSdan   va_list ap;
3492ed99defSdan   int rc;
3502ed99defSdan   char *zSql;
3512ed99defSdan   va_start(ap, zFmt);
3522ed99defSdan   zSql = sqlite3_vmprintf(zFmt, ap);
3532ed99defSdan   if( zSql==0 ){
3542ed99defSdan     rc = SQLITE_NOMEM;
3552ed99defSdan   }else{
3562ed99defSdan     rc = idxPrepareStmt(db, ppStmt, pzErrmsg, zSql);
3572ed99defSdan     sqlite3_free(zSql);
3582ed99defSdan   }
3592ed99defSdan   va_end(ap);
3602ed99defSdan   return rc;
3612ed99defSdan }
3622ed99defSdan 
3630824ccf2Sdan 
3640824ccf2Sdan /*************************************************************************
3650824ccf2Sdan ** Beginning of virtual table implementation.
3668e0b8e06Sdan */
3670824ccf2Sdan typedef struct ExpertVtab ExpertVtab;
3680824ccf2Sdan struct ExpertVtab {
3690824ccf2Sdan   sqlite3_vtab base;
3700824ccf2Sdan   IdxTable *pTab;
3710824ccf2Sdan   sqlite3expert *pExpert;
3720824ccf2Sdan };
3730824ccf2Sdan 
3742ed99defSdan typedef struct ExpertCsr ExpertCsr;
3752ed99defSdan struct ExpertCsr {
3762ed99defSdan   sqlite3_vtab_cursor base;
3772ed99defSdan   sqlite3_stmt *pData;
3782ed99defSdan };
3792ed99defSdan 
expertDequote(const char * zIn)3800824ccf2Sdan static char *expertDequote(const char *zIn){
381bd0f1dbdSdrh   int n = STRLEN(zIn);
3820824ccf2Sdan   char *zRet = sqlite3_malloc(n);
3830824ccf2Sdan 
3840824ccf2Sdan   assert( zIn[0]=='\'' );
3850824ccf2Sdan   assert( zIn[n-1]=='\'' );
3860824ccf2Sdan 
3870824ccf2Sdan   if( zRet ){
3880824ccf2Sdan     int iOut = 0;
3890824ccf2Sdan     int iIn = 0;
3900824ccf2Sdan     for(iIn=1; iIn<(n-1); iIn++){
3910824ccf2Sdan       if( zIn[iIn]=='\'' ){
3920824ccf2Sdan         assert( zIn[iIn+1]=='\'' );
3930824ccf2Sdan         iIn++;
3940824ccf2Sdan       }
3950824ccf2Sdan       zRet[iOut++] = zIn[iIn];
3960824ccf2Sdan     }
3970824ccf2Sdan     zRet[iOut] = '\0';
3980824ccf2Sdan   }
3990824ccf2Sdan 
4000824ccf2Sdan   return zRet;
4010824ccf2Sdan }
4020824ccf2Sdan 
4030824ccf2Sdan /*
4040824ccf2Sdan ** This function is the implementation of both the xConnect and xCreate
4050824ccf2Sdan ** methods of the r-tree virtual table.
4060824ccf2Sdan **
4070824ccf2Sdan **   argv[0]   -> module name
4080824ccf2Sdan **   argv[1]   -> database name
4090824ccf2Sdan **   argv[2]   -> table name
4100824ccf2Sdan **   argv[...] -> column names...
4110824ccf2Sdan */
expertConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)4120824ccf2Sdan static int expertConnect(
4130824ccf2Sdan   sqlite3 *db,
4140824ccf2Sdan   void *pAux,
4150824ccf2Sdan   int argc, const char *const*argv,
4160824ccf2Sdan   sqlite3_vtab **ppVtab,
4170824ccf2Sdan   char **pzErr
4188e0b8e06Sdan ){
4190824ccf2Sdan   sqlite3expert *pExpert = (sqlite3expert*)pAux;
4200824ccf2Sdan   ExpertVtab *p = 0;
4210824ccf2Sdan   int rc;
4228e0b8e06Sdan 
4230824ccf2Sdan   if( argc!=4 ){
4240824ccf2Sdan     *pzErr = sqlite3_mprintf("internal error!");
4250824ccf2Sdan     rc = SQLITE_ERROR;
4268e0b8e06Sdan   }else{
4270824ccf2Sdan     char *zCreateTable = expertDequote(argv[3]);
4280824ccf2Sdan     if( zCreateTable ){
4290824ccf2Sdan       rc = sqlite3_declare_vtab(db, zCreateTable);
4300824ccf2Sdan       if( rc==SQLITE_OK ){
4310824ccf2Sdan         p = idxMalloc(&rc, sizeof(ExpertVtab));
4328e0b8e06Sdan       }
4330824ccf2Sdan       if( rc==SQLITE_OK ){
4340824ccf2Sdan         p->pExpert = pExpert;
4350824ccf2Sdan         p->pTab = pExpert->pTable;
4360824ccf2Sdan         assert( sqlite3_stricmp(p->pTab->zName, argv[2])==0 );
4378e0b8e06Sdan       }
4380824ccf2Sdan       sqlite3_free(zCreateTable);
4398e0b8e06Sdan     }else{
4400824ccf2Sdan       rc = SQLITE_NOMEM;
4418e0b8e06Sdan     }
4420824ccf2Sdan   }
4430824ccf2Sdan 
4440824ccf2Sdan   *ppVtab = (sqlite3_vtab*)p;
4450824ccf2Sdan   return rc;
4460824ccf2Sdan }
4470824ccf2Sdan 
expertDisconnect(sqlite3_vtab * pVtab)4480824ccf2Sdan static int expertDisconnect(sqlite3_vtab *pVtab){
4490824ccf2Sdan   ExpertVtab *p = (ExpertVtab*)pVtab;
4500824ccf2Sdan   sqlite3_free(p);
4510824ccf2Sdan   return SQLITE_OK;
4520824ccf2Sdan }
4530824ccf2Sdan 
expertBestIndex(sqlite3_vtab * pVtab,sqlite3_index_info * pIdxInfo)4540824ccf2Sdan static int expertBestIndex(sqlite3_vtab *pVtab, sqlite3_index_info *pIdxInfo){
4550824ccf2Sdan   ExpertVtab *p = (ExpertVtab*)pVtab;
4560824ccf2Sdan   int rc = SQLITE_OK;
4570824ccf2Sdan   int n = 0;
4580824ccf2Sdan   IdxScan *pScan;
4590824ccf2Sdan   const int opmask =
4600824ccf2Sdan     SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_GT |
4610824ccf2Sdan     SQLITE_INDEX_CONSTRAINT_LT | SQLITE_INDEX_CONSTRAINT_GE |
4620824ccf2Sdan     SQLITE_INDEX_CONSTRAINT_LE;
4630824ccf2Sdan 
4640824ccf2Sdan   pScan = idxMalloc(&rc, sizeof(IdxScan));
4650824ccf2Sdan   if( pScan ){
4660824ccf2Sdan     int i;
4670824ccf2Sdan 
4680824ccf2Sdan     /* Link the new scan object into the list */
4690824ccf2Sdan     pScan->pTab = p->pTab;
4700824ccf2Sdan     pScan->pNextScan = p->pExpert->pScan;
4710824ccf2Sdan     p->pExpert->pScan = pScan;
4720824ccf2Sdan 
4730824ccf2Sdan     /* Add the constraints to the IdxScan object */
4740824ccf2Sdan     for(i=0; i<pIdxInfo->nConstraint; i++){
47579610f5dSdan       struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
4762ed99defSdan       if( pCons->usable
4772ed99defSdan        && pCons->iColumn>=0
4782ed99defSdan        && p->pTab->aCol[pCons->iColumn].iPk==0
4792ed99defSdan        && (pCons->op & opmask)
4802ed99defSdan       ){
4810824ccf2Sdan         IdxConstraint *pNew;
482efc88d02Sdrh         const char *zColl = sqlite3_vtab_collation(pIdxInfo, i);
4830824ccf2Sdan         pNew = idxNewConstraint(&rc, zColl);
4840824ccf2Sdan         if( pNew ){
48579610f5dSdan           pNew->iCol = pCons->iColumn;
48679610f5dSdan           if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
4870824ccf2Sdan             pNew->pNext = pScan->pEq;
4880824ccf2Sdan             pScan->pEq = pNew;
4890824ccf2Sdan           }else{
4900824ccf2Sdan             pNew->bRange = 1;
4910824ccf2Sdan             pNew->pNext = pScan->pRange;
4920824ccf2Sdan             pScan->pRange = pNew;
4930824ccf2Sdan           }
4940824ccf2Sdan         }
4950824ccf2Sdan         n++;
4960824ccf2Sdan         pIdxInfo->aConstraintUsage[i].argvIndex = n;
4978e0b8e06Sdan       }
4988e0b8e06Sdan     }
4990824ccf2Sdan 
5000824ccf2Sdan     /* Add the ORDER BY to the IdxScan object */
5010824ccf2Sdan     for(i=pIdxInfo->nOrderBy-1; i>=0; i--){
50279610f5dSdan       int iCol = pIdxInfo->aOrderBy[i].iColumn;
5032abf9009Sdan       if( iCol>=0 ){
50479610f5dSdan         IdxConstraint *pNew = idxNewConstraint(&rc, p->pTab->aCol[iCol].zColl);
5050824ccf2Sdan         if( pNew ){
50679610f5dSdan           pNew->iCol = iCol;
5070824ccf2Sdan           pNew->bDesc = pIdxInfo->aOrderBy[i].desc;
5080824ccf2Sdan           pNew->pNext = pScan->pOrder;
5090824ccf2Sdan           pNew->pLink = pScan->pOrder;
5100824ccf2Sdan           pScan->pOrder = pNew;
5110824ccf2Sdan           n++;
5128e0b8e06Sdan         }
5130824ccf2Sdan       }
5140824ccf2Sdan     }
5152abf9009Sdan   }
5160824ccf2Sdan 
517d4bb7c18Sdan   pIdxInfo->estimatedCost = 1000000.0 / (n+1);
5180824ccf2Sdan   return rc;
5190824ccf2Sdan }
5200824ccf2Sdan 
expertUpdate(sqlite3_vtab * pVtab,int nData,sqlite3_value ** azData,sqlite_int64 * pRowid)521280db65eSdan static int expertUpdate(
522280db65eSdan   sqlite3_vtab *pVtab,
523280db65eSdan   int nData,
524280db65eSdan   sqlite3_value **azData,
525280db65eSdan   sqlite_int64 *pRowid
526280db65eSdan ){
527b9685185Sdrh   (void)pVtab;
528b9685185Sdrh   (void)nData;
529b9685185Sdrh   (void)azData;
530b9685185Sdrh   (void)pRowid;
531280db65eSdan   return SQLITE_OK;
532280db65eSdan }
533280db65eSdan 
5342ed99defSdan /*
5352ed99defSdan ** Virtual table module xOpen method.
5362ed99defSdan */
expertOpen(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCursor)5372ed99defSdan static int expertOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
5382ed99defSdan   int rc = SQLITE_OK;
5392ed99defSdan   ExpertCsr *pCsr;
540b9685185Sdrh   (void)pVTab;
5412ed99defSdan   pCsr = idxMalloc(&rc, sizeof(ExpertCsr));
5422ed99defSdan   *ppCursor = (sqlite3_vtab_cursor*)pCsr;
5432ed99defSdan   return rc;
5442ed99defSdan }
5452ed99defSdan 
5462ed99defSdan /*
5472ed99defSdan ** Virtual table module xClose method.
5482ed99defSdan */
expertClose(sqlite3_vtab_cursor * cur)5492ed99defSdan static int expertClose(sqlite3_vtab_cursor *cur){
5502ed99defSdan   ExpertCsr *pCsr = (ExpertCsr*)cur;
5512ed99defSdan   sqlite3_finalize(pCsr->pData);
5522ed99defSdan   sqlite3_free(pCsr);
5532ed99defSdan   return SQLITE_OK;
5542ed99defSdan }
5552ed99defSdan 
5562ed99defSdan /*
5572ed99defSdan ** Virtual table module xEof method.
5582ed99defSdan **
5592ed99defSdan ** Return non-zero if the cursor does not currently point to a valid
5602ed99defSdan ** record (i.e if the scan has finished), or zero otherwise.
5612ed99defSdan */
expertEof(sqlite3_vtab_cursor * cur)5622ed99defSdan static int expertEof(sqlite3_vtab_cursor *cur){
5632ed99defSdan   ExpertCsr *pCsr = (ExpertCsr*)cur;
5642ed99defSdan   return pCsr->pData==0;
5652ed99defSdan }
5662ed99defSdan 
5672ed99defSdan /*
5682ed99defSdan ** Virtual table module xNext method.
5692ed99defSdan */
expertNext(sqlite3_vtab_cursor * cur)5702ed99defSdan static int expertNext(sqlite3_vtab_cursor *cur){
5712ed99defSdan   ExpertCsr *pCsr = (ExpertCsr*)cur;
5722ed99defSdan   int rc = SQLITE_OK;
5732ed99defSdan 
574bc3f784cSdan   assert( pCsr->pData );
5752ed99defSdan   rc = sqlite3_step(pCsr->pData);
5762ed99defSdan   if( rc!=SQLITE_ROW ){
5772ed99defSdan     rc = sqlite3_finalize(pCsr->pData);
5782ed99defSdan     pCsr->pData = 0;
5792ed99defSdan   }else{
5802ed99defSdan     rc = SQLITE_OK;
5812ed99defSdan   }
5822ed99defSdan 
5832ed99defSdan   return rc;
5842ed99defSdan }
5852ed99defSdan 
5862ed99defSdan /*
5872ed99defSdan ** Virtual table module xRowid method.
5882ed99defSdan */
expertRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)5892ed99defSdan static int expertRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
590b9685185Sdrh   (void)cur;
5912ed99defSdan   *pRowid = 0;
5922ed99defSdan   return SQLITE_OK;
5932ed99defSdan }
5942ed99defSdan 
5952ed99defSdan /*
5962ed99defSdan ** Virtual table module xColumn method.
5972ed99defSdan */
expertColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)5982ed99defSdan static int expertColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
5992ed99defSdan   ExpertCsr *pCsr = (ExpertCsr*)cur;
6002ed99defSdan   sqlite3_value *pVal;
6012ed99defSdan   pVal = sqlite3_column_value(pCsr->pData, i);
6022ed99defSdan   if( pVal ){
6032ed99defSdan     sqlite3_result_value(ctx, pVal);
6042ed99defSdan   }
6052ed99defSdan   return SQLITE_OK;
6062ed99defSdan }
6072ed99defSdan 
6082ed99defSdan /*
6092ed99defSdan ** Virtual table module xFilter method.
6102ed99defSdan */
expertFilter(sqlite3_vtab_cursor * cur,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)6112ed99defSdan static int expertFilter(
6122ed99defSdan   sqlite3_vtab_cursor *cur,
6132ed99defSdan   int idxNum, const char *idxStr,
6142ed99defSdan   int argc, sqlite3_value **argv
6152ed99defSdan ){
6162ed99defSdan   ExpertCsr *pCsr = (ExpertCsr*)cur;
6172ed99defSdan   ExpertVtab *pVtab = (ExpertVtab*)(cur->pVtab);
6182ed99defSdan   sqlite3expert *pExpert = pVtab->pExpert;
6192ed99defSdan   int rc;
6202ed99defSdan 
621b9685185Sdrh   (void)idxNum;
622b9685185Sdrh   (void)idxStr;
623b9685185Sdrh   (void)argc;
624b9685185Sdrh   (void)argv;
6252ed99defSdan   rc = sqlite3_finalize(pCsr->pData);
6262ed99defSdan   pCsr->pData = 0;
6272ed99defSdan   if( rc==SQLITE_OK ){
6282ed99defSdan     rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
629bc3f784cSdan         "SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName
6302ed99defSdan     );
6312ed99defSdan   }
6322ed99defSdan 
6332ed99defSdan   if( rc==SQLITE_OK ){
6342ed99defSdan     rc = expertNext(cur);
6352ed99defSdan   }
6362ed99defSdan   return rc;
6372ed99defSdan }
6382ed99defSdan 
idxRegisterVtab(sqlite3expert * p)6390824ccf2Sdan static int idxRegisterVtab(sqlite3expert *p){
6400824ccf2Sdan   static sqlite3_module expertModule = {
6410824ccf2Sdan     2,                            /* iVersion */
6420824ccf2Sdan     expertConnect,                /* xCreate - create a table */
6430824ccf2Sdan     expertConnect,                /* xConnect - connect to an existing table */
6440824ccf2Sdan     expertBestIndex,              /* xBestIndex - Determine search strategy */
6450824ccf2Sdan     expertDisconnect,             /* xDisconnect - Disconnect from a table */
6460824ccf2Sdan     expertDisconnect,             /* xDestroy - Drop a table */
6472ed99defSdan     expertOpen,                   /* xOpen - open a cursor */
6482ed99defSdan     expertClose,                  /* xClose - close a cursor */
6492ed99defSdan     expertFilter,                 /* xFilter - configure scan constraints */
6502ed99defSdan     expertNext,                   /* xNext - advance a cursor */
6512ed99defSdan     expertEof,                    /* xEof */
6522ed99defSdan     expertColumn,                 /* xColumn - read data */
6532ed99defSdan     expertRowid,                  /* xRowid - read data */
654280db65eSdan     expertUpdate,                 /* xUpdate - write data */
6550824ccf2Sdan     0,                            /* xBegin - begin transaction */
6560824ccf2Sdan     0,                            /* xSync - sync transaction */
6570824ccf2Sdan     0,                            /* xCommit - commit transaction */
6580824ccf2Sdan     0,                            /* xRollback - rollback transaction */
6590824ccf2Sdan     0,                            /* xFindFunction - function overloading */
6600824ccf2Sdan     0,                            /* xRename - rename the table */
6610824ccf2Sdan     0,                            /* xSavepoint */
6620824ccf2Sdan     0,                            /* xRelease */
6630824ccf2Sdan     0,                            /* xRollbackTo */
66484c501baSdrh     0,                            /* xShadowName */
6650824ccf2Sdan   };
6660824ccf2Sdan 
6670824ccf2Sdan   return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
6680824ccf2Sdan }
6690824ccf2Sdan /*
6700824ccf2Sdan ** End of virtual table implementation.
6710824ccf2Sdan *************************************************************************/
67296d43a05Sdan /*
67396d43a05Sdan ** Finalize SQL statement pStmt. If (*pRc) is SQLITE_OK when this function
67496d43a05Sdan ** is called, set it to the return value of sqlite3_finalize() before
67596d43a05Sdan ** returning. Otherwise, discard the sqlite3_finalize() return value.
67696d43a05Sdan */
idxFinalize(int * pRc,sqlite3_stmt * pStmt)67765e67ed1Sdan static void idxFinalize(int *pRc, sqlite3_stmt *pStmt){
67865e67ed1Sdan   int rc = sqlite3_finalize(pStmt);
67965e67ed1Sdan   if( *pRc==SQLITE_OK ) *pRc = rc;
68065e67ed1Sdan }
68165e67ed1Sdan 
68296d43a05Sdan /*
68396d43a05Sdan ** Attempt to allocate an IdxTable structure corresponding to table zTab
68496d43a05Sdan ** in the main database of connection db. If successful, set (*ppOut) to
68596d43a05Sdan ** point to the new object and return SQLITE_OK. Otherwise, return an
68696d43a05Sdan ** SQLite error code and set (*ppOut) to NULL. In this case *pzErrmsg may be
68796d43a05Sdan ** set to point to an error string.
68896d43a05Sdan **
68996d43a05Sdan ** It is the responsibility of the caller to eventually free either the
69096d43a05Sdan ** IdxTable object or error message using sqlite3_free().
69196d43a05Sdan */
idxGetTableInfo(sqlite3 * db,const char * zTab,IdxTable ** ppOut,char ** pzErrmsg)6928e0b8e06Sdan static int idxGetTableInfo(
69396d43a05Sdan   sqlite3 *db,                    /* Database connection to read details from */
69496d43a05Sdan   const char *zTab,               /* Table name */
69596d43a05Sdan   IdxTable **ppOut,               /* OUT: New object (if successful) */
69696d43a05Sdan   char **pzErrmsg                 /* OUT: Error message (if not) */
6978e0b8e06Sdan ){
6988e0b8e06Sdan   sqlite3_stmt *p1 = 0;
6998e0b8e06Sdan   int nCol = 0;
700e0adf602Sdrh   int nTab;
701e0adf602Sdrh   int nByte;
7028e0b8e06Sdan   IdxTable *pNew = 0;
7038e0b8e06Sdan   int rc, rc2;
7042ed99defSdan   char *pCsr = 0;
70539c7125aSdan   int nPk = 0;
7068e0b8e06Sdan 
707e0adf602Sdrh   *ppOut = 0;
708e0adf602Sdrh   if( zTab==0 ) return SQLITE_ERROR;
709e0adf602Sdrh   nTab = STRLEN(zTab);
710e0adf602Sdrh   nByte = sizeof(IdxTable) + nTab + 1;
71169871baaSdan   rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_xinfo=%Q", zTab);
7128e0b8e06Sdan   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
7138e0b8e06Sdan     const char *zCol = (const char*)sqlite3_column_text(p1, 1);
71477ea2230Sdrh     const char *zColSeq = 0;
715e0adf602Sdrh     if( zCol==0 ){
716e0adf602Sdrh       rc = SQLITE_ERROR;
717e0adf602Sdrh       break;
718e0adf602Sdrh     }
719bd0f1dbdSdrh     nByte += 1 + STRLEN(zCol);
7208e0b8e06Sdan     rc = sqlite3_table_column_metadata(
72177ea2230Sdrh         db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0
7228e0b8e06Sdan     );
72377ea2230Sdrh     if( zColSeq==0 ) zColSeq = "binary";
72477ea2230Sdrh     nByte += 1 + STRLEN(zColSeq);
7258e0b8e06Sdan     nCol++;
72639c7125aSdan     nPk += (sqlite3_column_int(p1, 5)>0);
7278e0b8e06Sdan   }
7288e0b8e06Sdan   rc2 = sqlite3_reset(p1);
7298e0b8e06Sdan   if( rc==SQLITE_OK ) rc = rc2;
7308e0b8e06Sdan 
7318e0b8e06Sdan   nByte += sizeof(IdxColumn) * nCol;
7328e0b8e06Sdan   if( rc==SQLITE_OK ){
7338e0b8e06Sdan     pNew = idxMalloc(&rc, nByte);
7348e0b8e06Sdan   }
7358e0b8e06Sdan   if( rc==SQLITE_OK ){
7368e0b8e06Sdan     pNew->aCol = (IdxColumn*)&pNew[1];
7378e0b8e06Sdan     pNew->nCol = nCol;
7388e0b8e06Sdan     pCsr = (char*)&pNew->aCol[nCol];
7398e0b8e06Sdan   }
7408e0b8e06Sdan 
7418e0b8e06Sdan   nCol = 0;
7428e0b8e06Sdan   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
7438e0b8e06Sdan     const char *zCol = (const char*)sqlite3_column_text(p1, 1);
74477ea2230Sdrh     const char *zColSeq = 0;
745e0adf602Sdrh     int nCopy;
746e0adf602Sdrh     if( zCol==0 ) continue;
747e0adf602Sdrh     nCopy = STRLEN(zCol) + 1;
7488e0b8e06Sdan     pNew->aCol[nCol].zName = pCsr;
74939c7125aSdan     pNew->aCol[nCol].iPk = (sqlite3_column_int(p1, 5)==1 && nPk==1);
7508e0b8e06Sdan     memcpy(pCsr, zCol, nCopy);
7518e0b8e06Sdan     pCsr += nCopy;
7528e0b8e06Sdan 
7538e0b8e06Sdan     rc = sqlite3_table_column_metadata(
75477ea2230Sdrh         db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0
7558e0b8e06Sdan     );
7568e0b8e06Sdan     if( rc==SQLITE_OK ){
75777ea2230Sdrh       if( zColSeq==0 ) zColSeq = "binary";
75877ea2230Sdrh       nCopy = STRLEN(zColSeq) + 1;
7598e0b8e06Sdan       pNew->aCol[nCol].zColl = pCsr;
76077ea2230Sdrh       memcpy(pCsr, zColSeq, nCopy);
7618e0b8e06Sdan       pCsr += nCopy;
7628e0b8e06Sdan     }
7638e0b8e06Sdan 
7648e0b8e06Sdan     nCol++;
7658e0b8e06Sdan   }
76665e67ed1Sdan   idxFinalize(&rc, p1);
7678e0b8e06Sdan 
76896d43a05Sdan   if( rc!=SQLITE_OK ){
7698e0b8e06Sdan     sqlite3_free(pNew);
77096d43a05Sdan     pNew = 0;
77111a9ad56Sdrh   }else if( ALWAYS(pNew!=0) ){
7720824ccf2Sdan     pNew->zName = pCsr;
77311a9ad56Sdrh     if( ALWAYS(pNew->zName!=0) ) memcpy(pNew->zName, zTab, nTab+1);
7748e0b8e06Sdan   }
7758e0b8e06Sdan 
77696d43a05Sdan   *ppOut = pNew;
7778e0b8e06Sdan   return rc;
7788e0b8e06Sdan }
7798e0b8e06Sdan 
7808e0b8e06Sdan /*
7818e0b8e06Sdan ** This function is a no-op if *pRc is set to anything other than
7828e0b8e06Sdan ** SQLITE_OK when it is called.
7838e0b8e06Sdan **
7848e0b8e06Sdan ** If *pRc is initially set to SQLITE_OK, then the text specified by
7858e0b8e06Sdan ** the printf() style arguments is appended to zIn and the result returned
7868e0b8e06Sdan ** in a buffer allocated by sqlite3_malloc(). sqlite3_free() is called on
7878e0b8e06Sdan ** zIn before returning.
7888e0b8e06Sdan */
idxAppendText(int * pRc,char * zIn,const char * zFmt,...)7898e0b8e06Sdan static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){
7908e0b8e06Sdan   va_list ap;
7918e0b8e06Sdan   char *zAppend = 0;
7928e0b8e06Sdan   char *zRet = 0;
793bd0f1dbdSdrh   int nIn = zIn ? STRLEN(zIn) : 0;
7948e0b8e06Sdan   int nAppend = 0;
7958e0b8e06Sdan   va_start(ap, zFmt);
7968e0b8e06Sdan   if( *pRc==SQLITE_OK ){
7978e0b8e06Sdan     zAppend = sqlite3_vmprintf(zFmt, ap);
7988e0b8e06Sdan     if( zAppend ){
799bd0f1dbdSdrh       nAppend = STRLEN(zAppend);
8008e0b8e06Sdan       zRet = (char*)sqlite3_malloc(nIn + nAppend + 1);
8018e0b8e06Sdan     }
8028e0b8e06Sdan     if( zAppend && zRet ){
803d4bb7c18Sdan       if( nIn ) memcpy(zRet, zIn, nIn);
8048e0b8e06Sdan       memcpy(&zRet[nIn], zAppend, nAppend+1);
8058e0b8e06Sdan     }else{
8068e0b8e06Sdan       sqlite3_free(zRet);
8078e0b8e06Sdan       zRet = 0;
8088e0b8e06Sdan       *pRc = SQLITE_NOMEM;
8098e0b8e06Sdan     }
8108e0b8e06Sdan     sqlite3_free(zAppend);
8118e0b8e06Sdan     sqlite3_free(zIn);
8128e0b8e06Sdan   }
8138e0b8e06Sdan   va_end(ap);
8148e0b8e06Sdan   return zRet;
8158e0b8e06Sdan }
8168e0b8e06Sdan 
81796d43a05Sdan /*
81896d43a05Sdan ** Return true if zId must be quoted in order to use it as an SQL
81996d43a05Sdan ** identifier, or false otherwise.
82096d43a05Sdan */
idxIdentifierRequiresQuotes(const char * zId)8218e0b8e06Sdan static int idxIdentifierRequiresQuotes(const char *zId){
8228e0b8e06Sdan   int i;
823*217635f7Sdan   int nId = STRLEN(zId);
824*217635f7Sdan 
825*217635f7Sdan   if( sqlite3_keyword_check(zId, nId) ) return 1;
826*217635f7Sdan 
8278e0b8e06Sdan   for(i=0; zId[i]; i++){
8288e0b8e06Sdan     if( !(zId[i]=='_')
8298e0b8e06Sdan      && !(zId[i]>='0' && zId[i]<='9')
8308e0b8e06Sdan      && !(zId[i]>='a' && zId[i]<='z')
8318e0b8e06Sdan      && !(zId[i]>='A' && zId[i]<='Z')
8328e0b8e06Sdan     ){
8338e0b8e06Sdan       return 1;
8348e0b8e06Sdan     }
8358e0b8e06Sdan   }
8368e0b8e06Sdan   return 0;
8378e0b8e06Sdan }
8388e0b8e06Sdan 
83996d43a05Sdan /*
84096d43a05Sdan ** This function appends an index column definition suitable for constraint
84196d43a05Sdan ** pCons to the string passed as zIn and returns the result.
84296d43a05Sdan */
idxAppendColDefn(int * pRc,char * zIn,IdxTable * pTab,IdxConstraint * pCons)8438e0b8e06Sdan static char *idxAppendColDefn(
84496d43a05Sdan   int *pRc,                       /* IN/OUT: Error code */
84596d43a05Sdan   char *zIn,                      /* Column defn accumulated so far */
84696d43a05Sdan   IdxTable *pTab,                 /* Table index will be created on */
8478e0b8e06Sdan   IdxConstraint *pCons
8488e0b8e06Sdan ){
8498e0b8e06Sdan   char *zRet = zIn;
8508e0b8e06Sdan   IdxColumn *p = &pTab->aCol[pCons->iCol];
8518e0b8e06Sdan   if( zRet ) zRet = idxAppendText(pRc, zRet, ", ");
8528e0b8e06Sdan 
8538e0b8e06Sdan   if( idxIdentifierRequiresQuotes(p->zName) ){
8548e0b8e06Sdan     zRet = idxAppendText(pRc, zRet, "%Q", p->zName);
8558e0b8e06Sdan   }else{
8568e0b8e06Sdan     zRet = idxAppendText(pRc, zRet, "%s", p->zName);
8578e0b8e06Sdan   }
8588e0b8e06Sdan 
8598e0b8e06Sdan   if( sqlite3_stricmp(p->zColl, pCons->zColl) ){
8608e0b8e06Sdan     if( idxIdentifierRequiresQuotes(pCons->zColl) ){
8618e0b8e06Sdan       zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl);
8628e0b8e06Sdan     }else{
8638e0b8e06Sdan       zRet = idxAppendText(pRc, zRet, " COLLATE %s", pCons->zColl);
8648e0b8e06Sdan     }
8658e0b8e06Sdan   }
8668e0b8e06Sdan 
8678e0b8e06Sdan   if( pCons->bDesc ){
8688e0b8e06Sdan     zRet = idxAppendText(pRc, zRet, " DESC");
8698e0b8e06Sdan   }
8708e0b8e06Sdan   return zRet;
8718e0b8e06Sdan }
8728e0b8e06Sdan 
8738e0b8e06Sdan /*
8748e0b8e06Sdan ** Search database dbm for an index compatible with the one idxCreateFromCons()
8758e0b8e06Sdan ** would create from arguments pScan, pEq and pTail. If no error occurs and
8768e0b8e06Sdan ** such an index is found, return non-zero. Or, if no such index is found,
8778e0b8e06Sdan ** return zero.
8788e0b8e06Sdan **
8798e0b8e06Sdan ** If an error occurs, set *pRc to an SQLite error code and return zero.
8808e0b8e06Sdan */
idxFindCompatible(int * pRc,sqlite3 * dbm,IdxScan * pScan,IdxConstraint * pEq,IdxConstraint * pTail)8818e0b8e06Sdan static int idxFindCompatible(
8828e0b8e06Sdan   int *pRc,                       /* OUT: Error code */
8838e0b8e06Sdan   sqlite3* dbm,                   /* Database to search */
8848e0b8e06Sdan   IdxScan *pScan,                 /* Scan for table to search for index on */
8858e0b8e06Sdan   IdxConstraint *pEq,             /* List of == constraints */
8868e0b8e06Sdan   IdxConstraint *pTail            /* List of range constraints */
8878e0b8e06Sdan ){
8880824ccf2Sdan   const char *zTbl = pScan->pTab->zName;
8898e0b8e06Sdan   sqlite3_stmt *pIdxList = 0;
8908e0b8e06Sdan   IdxConstraint *pIter;
8918e0b8e06Sdan   int nEq = 0;                    /* Number of elements in pEq */
89265e67ed1Sdan   int rc;
8938e0b8e06Sdan 
8948e0b8e06Sdan   /* Count the elements in list pEq */
8958e0b8e06Sdan   for(pIter=pEq; pIter; pIter=pIter->pLink) nEq++;
8968e0b8e06Sdan 
8978e0b8e06Sdan   rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl);
8988e0b8e06Sdan   while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){
8998e0b8e06Sdan     int bMatch = 1;
9008e0b8e06Sdan     IdxConstraint *pT = pTail;
9018e0b8e06Sdan     sqlite3_stmt *pInfo = 0;
9028e0b8e06Sdan     const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1);
903e0adf602Sdrh     if( zIdx==0 ) continue;
9048e0b8e06Sdan 
9058e0b8e06Sdan     /* Zero the IdxConstraint.bFlag values in the pEq list */
9068e0b8e06Sdan     for(pIter=pEq; pIter; pIter=pIter->pLink) pIter->bFlag = 0;
9078e0b8e06Sdan 
9088e0b8e06Sdan     rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx);
9098e0b8e06Sdan     while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){
9108e0b8e06Sdan       int iIdx = sqlite3_column_int(pInfo, 0);
9118e0b8e06Sdan       int iCol = sqlite3_column_int(pInfo, 1);
9128e0b8e06Sdan       const char *zColl = (const char*)sqlite3_column_text(pInfo, 4);
9138e0b8e06Sdan 
9148e0b8e06Sdan       if( iIdx<nEq ){
9158e0b8e06Sdan         for(pIter=pEq; pIter; pIter=pIter->pLink){
9168e0b8e06Sdan           if( pIter->bFlag ) continue;
9178e0b8e06Sdan           if( pIter->iCol!=iCol ) continue;
9188e0b8e06Sdan           if( sqlite3_stricmp(pIter->zColl, zColl) ) continue;
9198e0b8e06Sdan           pIter->bFlag = 1;
9208e0b8e06Sdan           break;
9218e0b8e06Sdan         }
9228e0b8e06Sdan         if( pIter==0 ){
9238e0b8e06Sdan           bMatch = 0;
9248e0b8e06Sdan           break;
9258e0b8e06Sdan         }
9268e0b8e06Sdan       }else{
9278e0b8e06Sdan         if( pT ){
9288e0b8e06Sdan           if( pT->iCol!=iCol || sqlite3_stricmp(pT->zColl, zColl) ){
9298e0b8e06Sdan             bMatch = 0;
9308e0b8e06Sdan             break;
9318e0b8e06Sdan           }
9328e0b8e06Sdan           pT = pT->pLink;
9338e0b8e06Sdan         }
9348e0b8e06Sdan       }
9358e0b8e06Sdan     }
93665e67ed1Sdan     idxFinalize(&rc, pInfo);
9378e0b8e06Sdan 
9388e0b8e06Sdan     if( rc==SQLITE_OK && bMatch ){
9398e0b8e06Sdan       sqlite3_finalize(pIdxList);
9408e0b8e06Sdan       return 1;
9418e0b8e06Sdan     }
9428e0b8e06Sdan   }
94365e67ed1Sdan   idxFinalize(&rc, pIdxList);
9448e0b8e06Sdan 
9458e0b8e06Sdan   *pRc = rc;
9468e0b8e06Sdan   return 0;
9478e0b8e06Sdan }
9488e0b8e06Sdan 
949b565bee6Slarrybr /* Callback for sqlite3_exec() with query with leading count(*) column.
950b565bee6Slarrybr  * The first argument is expected to be an int*, referent to be incremented
951b565bee6Slarrybr  * if that leading column is not exactly '0'.
952b565bee6Slarrybr  */
countNonzeros(void * pCount,int nc,char * azResults[],char * azColumns[])953b565bee6Slarrybr static int countNonzeros(void* pCount, int nc,
954b565bee6Slarrybr                          char* azResults[], char* azColumns[]){
955dd31c033Sdrh   (void)azColumns;  /* Suppress unused parameter warning */
956fd7abcd1Sdrh   if( nc>0 && (azResults[0][0]!='0' || azResults[0][1]!=0) ){
957b565bee6Slarrybr     *((int *)pCount) += 1;
958b565bee6Slarrybr   }
959b565bee6Slarrybr   return 0;
960b565bee6Slarrybr }
961b565bee6Slarrybr 
idxCreateFromCons(sqlite3expert * p,IdxScan * pScan,IdxConstraint * pEq,IdxConstraint * pTail)9628e0b8e06Sdan static int idxCreateFromCons(
9638e0b8e06Sdan   sqlite3expert *p,
9648e0b8e06Sdan   IdxScan *pScan,
9658e0b8e06Sdan   IdxConstraint *pEq,
9668e0b8e06Sdan   IdxConstraint *pTail
9678e0b8e06Sdan ){
9688e0b8e06Sdan   sqlite3 *dbm = p->dbm;
9698e0b8e06Sdan   int rc = SQLITE_OK;
9708e0b8e06Sdan   if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
97179610f5dSdan     IdxTable *pTab = pScan->pTab;
9728e0b8e06Sdan     char *zCols = 0;
9738e0b8e06Sdan     char *zIdx = 0;
9748e0b8e06Sdan     IdxConstraint *pCons;
975d4bb7c18Sdan     unsigned int h = 0;
9768e0b8e06Sdan     const char *zFmt;
9778e0b8e06Sdan 
9788e0b8e06Sdan     for(pCons=pEq; pCons; pCons=pCons->pLink){
9798e0b8e06Sdan       zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
9808e0b8e06Sdan     }
9818e0b8e06Sdan     for(pCons=pTail; pCons; pCons=pCons->pLink){
9828e0b8e06Sdan       zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
9838e0b8e06Sdan     }
9848e0b8e06Sdan 
9858e0b8e06Sdan     if( rc==SQLITE_OK ){
9868e0b8e06Sdan       /* Hash the list of columns to come up with a name for the index */
9870824ccf2Sdan       const char *zTable = pScan->pTab->zName;
988b565bee6Slarrybr       int quoteTable = idxIdentifierRequiresQuotes(zTable);
989b565bee6Slarrybr       char *zName = 0;          /* Index name */
990b565bee6Slarrybr       int collisions = 0;
991b565bee6Slarrybr       do{
9928e0b8e06Sdan         int i;
993b565bee6Slarrybr         char *zFind;
9948e0b8e06Sdan         for(i=0; zCols[i]; i++){
9958e0b8e06Sdan           h += ((h<<3) + zCols[i]);
9968e0b8e06Sdan         }
997b565bee6Slarrybr         sqlite3_free(zName);
9980824ccf2Sdan         zName = sqlite3_mprintf("%s_idx_%08x", zTable, h);
999b565bee6Slarrybr         if( zName==0 ) break;
1000b565bee6Slarrybr         /* Is is unique among table, view and index names? */
1001b565bee6Slarrybr         zFmt = "SELECT count(*) FROM sqlite_schema WHERE name=%Q"
1002b565bee6Slarrybr           " AND type in ('index','table','view')";
1003b565bee6Slarrybr         zFind = sqlite3_mprintf(zFmt, zName);
1004b565bee6Slarrybr         i = 0;
1005b565bee6Slarrybr         rc = sqlite3_exec(dbm, zFind, countNonzeros, &i, 0);
1006b565bee6Slarrybr         assert(rc==SQLITE_OK);
1007b565bee6Slarrybr         sqlite3_free(zFind);
1008b565bee6Slarrybr         if( i==0 ){
1009b565bee6Slarrybr           collisions = 0;
1010b565bee6Slarrybr           break;
1011b565bee6Slarrybr         }
1012b565bee6Slarrybr         ++collisions;
1013b565bee6Slarrybr       }while( collisions<50 && zName!=0 );
1014b565bee6Slarrybr       if( collisions ){
1015b565bee6Slarrybr         /* This return means "Gave up trying to find a unique index name." */
1016b565bee6Slarrybr         rc = SQLITE_BUSY_TIMEOUT;
1017b565bee6Slarrybr       }else if( zName==0 ){
101865e67ed1Sdan         rc = SQLITE_NOMEM;
10198e0b8e06Sdan       }else{
1020b565bee6Slarrybr         if( quoteTable ){
1021b565bee6Slarrybr           zFmt = "CREATE INDEX \"%w\" ON \"%w\"(%s)";
102265e67ed1Sdan         }else{
102365e67ed1Sdan           zFmt = "CREATE INDEX %s ON %s(%s)";
10248e0b8e06Sdan         }
10250824ccf2Sdan         zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols);
10268e0b8e06Sdan         if( !zIdx ){
10278e0b8e06Sdan           rc = SQLITE_NOMEM;
10288e0b8e06Sdan         }else{
10298e0b8e06Sdan           rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg);
1030b565bee6Slarrybr           if( rc!=SQLITE_OK ){
1031b565bee6Slarrybr             rc = SQLITE_BUSY_TIMEOUT;
1032b565bee6Slarrybr           }else{
103365e67ed1Sdan             idxHashAdd(&rc, &p->hIdx, zName, zIdx);
10348e0b8e06Sdan           }
1035b565bee6Slarrybr         }
103665e67ed1Sdan         sqlite3_free(zName);
103765e67ed1Sdan         sqlite3_free(zIdx);
10388e0b8e06Sdan       }
10398e0b8e06Sdan     }
10408e0b8e06Sdan 
10418e0b8e06Sdan     sqlite3_free(zCols);
10428e0b8e06Sdan   }
10438e0b8e06Sdan   return rc;
10448e0b8e06Sdan }
10458e0b8e06Sdan 
10468e0b8e06Sdan /*
10478e0b8e06Sdan ** Return true if list pList (linked by IdxConstraint.pLink) contains
10488e0b8e06Sdan ** a constraint compatible with *p. Otherwise return false.
10498e0b8e06Sdan */
idxFindConstraint(IdxConstraint * pList,IdxConstraint * p)10508e0b8e06Sdan static int idxFindConstraint(IdxConstraint *pList, IdxConstraint *p){
10518e0b8e06Sdan   IdxConstraint *pCmp;
10528e0b8e06Sdan   for(pCmp=pList; pCmp; pCmp=pCmp->pLink){
10538e0b8e06Sdan     if( p->iCol==pCmp->iCol ) return 1;
10548e0b8e06Sdan   }
10558e0b8e06Sdan   return 0;
10568e0b8e06Sdan }
10578e0b8e06Sdan 
idxCreateFromWhere(sqlite3expert * p,IdxScan * pScan,IdxConstraint * pTail)10588e0b8e06Sdan static int idxCreateFromWhere(
10598e0b8e06Sdan   sqlite3expert *p,
10608e0b8e06Sdan   IdxScan *pScan,                 /* Create indexes for this scan */
10618e0b8e06Sdan   IdxConstraint *pTail            /* range/ORDER BY constraints for inclusion */
10628e0b8e06Sdan ){
106379610f5dSdan   IdxConstraint *p1 = 0;
10648e0b8e06Sdan   IdxConstraint *pCon;
10658e0b8e06Sdan   int rc;
10668e0b8e06Sdan 
106779610f5dSdan   /* Gather up all the == constraints. */
106896d43a05Sdan   for(pCon=pScan->pEq; pCon; pCon=pCon->pNext){
106979610f5dSdan     if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){
10708e0b8e06Sdan       pCon->pLink = p1;
10718e0b8e06Sdan       p1 = pCon;
10728e0b8e06Sdan     }
10738e0b8e06Sdan   }
10748e0b8e06Sdan 
10758e0b8e06Sdan   /* Create an index using the == constraints collected above. And the
10768e0b8e06Sdan   ** range constraint/ORDER BY terms passed in by the caller, if any. */
107779610f5dSdan   rc = idxCreateFromCons(p, pScan, p1, pTail);
10788e0b8e06Sdan 
10798e0b8e06Sdan   /* If no range/ORDER BY passed by the caller, create a version of the
108079610f5dSdan   ** index for each range constraint.  */
10818e0b8e06Sdan   if( pTail==0 ){
108296d43a05Sdan     for(pCon=pScan->pRange; rc==SQLITE_OK && pCon; pCon=pCon->pNext){
10838e0b8e06Sdan       assert( pCon->pLink==0 );
108479610f5dSdan       if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){
108579610f5dSdan         rc = idxCreateFromCons(p, pScan, p1, pCon);
10868e0b8e06Sdan       }
10878e0b8e06Sdan     }
10888e0b8e06Sdan   }
10898e0b8e06Sdan 
10908e0b8e06Sdan   return rc;
10918e0b8e06Sdan }
10928e0b8e06Sdan 
10938e0b8e06Sdan /*
10948e0b8e06Sdan ** Create candidate indexes in database [dbm] based on the data in
10958e0b8e06Sdan ** linked-list pScan.
10968e0b8e06Sdan */
idxCreateCandidates(sqlite3expert * p)1097b9685185Sdrh static int idxCreateCandidates(sqlite3expert *p){
10988e0b8e06Sdan   int rc = SQLITE_OK;
10998e0b8e06Sdan   IdxScan *pIter;
11008e0b8e06Sdan 
11018e0b8e06Sdan   for(pIter=p->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
110279610f5dSdan     rc = idxCreateFromWhere(p, pIter, 0);
11038e0b8e06Sdan     if( rc==SQLITE_OK && pIter->pOrder ){
110479610f5dSdan       rc = idxCreateFromWhere(p, pIter, pIter->pOrder);
11058e0b8e06Sdan     }
11068e0b8e06Sdan   }
110765e67ed1Sdan 
11088e0b8e06Sdan   return rc;
11098e0b8e06Sdan }
11108e0b8e06Sdan 
111196d43a05Sdan /*
111296d43a05Sdan ** Free all elements of the linked list starting at pConstraint.
111396d43a05Sdan */
idxConstraintFree(IdxConstraint * pConstraint)1114cd84474eSdan static void idxConstraintFree(IdxConstraint *pConstraint){
1115cd84474eSdan   IdxConstraint *pNext;
1116cd84474eSdan   IdxConstraint *p;
1117cd84474eSdan 
1118cd84474eSdan   for(p=pConstraint; p; p=pNext){
1119cd84474eSdan     pNext = p->pNext;
1120cd84474eSdan     sqlite3_free(p);
1121cd84474eSdan   }
1122cd84474eSdan }
1123cd84474eSdan 
11248e0b8e06Sdan /*
11258e0b8e06Sdan ** Free all elements of the linked list starting from pScan up until pLast
11268e0b8e06Sdan ** (pLast is not freed).
11278e0b8e06Sdan */
idxScanFree(IdxScan * pScan,IdxScan * pLast)11288e0b8e06Sdan static void idxScanFree(IdxScan *pScan, IdxScan *pLast){
1129cd84474eSdan   IdxScan *p;
1130cd84474eSdan   IdxScan *pNext;
1131cd84474eSdan   for(p=pScan; p!=pLast; p=pNext){
1132cd84474eSdan     pNext = p->pNextScan;
1133cd84474eSdan     idxConstraintFree(p->pOrder);
113496d43a05Sdan     idxConstraintFree(p->pEq);
113596d43a05Sdan     idxConstraintFree(p->pRange);
1136cd84474eSdan     sqlite3_free(p);
1137cd84474eSdan   }
11388e0b8e06Sdan }
11398e0b8e06Sdan 
11408e0b8e06Sdan /*
11418e0b8e06Sdan ** Free all elements of the linked list starting from pStatement up
11428e0b8e06Sdan ** until pLast (pLast is not freed).
11438e0b8e06Sdan */
idxStatementFree(IdxStatement * pStatement,IdxStatement * pLast)11448e0b8e06Sdan static void idxStatementFree(IdxStatement *pStatement, IdxStatement *pLast){
1145cd84474eSdan   IdxStatement *p;
1146cd84474eSdan   IdxStatement *pNext;
1147cd84474eSdan   for(p=pStatement; p!=pLast; p=pNext){
1148cd84474eSdan     pNext = p->pNext;
1149cd84474eSdan     sqlite3_free(p->zEQP);
1150cd84474eSdan     sqlite3_free(p->zIdx);
1151cd84474eSdan     sqlite3_free(p);
1152cd84474eSdan   }
11538e0b8e06Sdan }
11548e0b8e06Sdan 
115579610f5dSdan /*
115679610f5dSdan ** Free the linked list of IdxTable objects starting at pTab.
115779610f5dSdan */
idxTableFree(IdxTable * pTab)115879610f5dSdan static void idxTableFree(IdxTable *pTab){
115979610f5dSdan   IdxTable *pIter;
116079610f5dSdan   IdxTable *pNext;
116179610f5dSdan   for(pIter=pTab; pIter; pIter=pNext){
116279610f5dSdan     pNext = pIter->pNext;
116379610f5dSdan     sqlite3_free(pIter);
116479610f5dSdan   }
116579610f5dSdan }
116679610f5dSdan 
1167280db65eSdan /*
1168280db65eSdan ** Free the linked list of IdxWrite objects starting at pTab.
1169280db65eSdan */
idxWriteFree(IdxWrite * pTab)1170280db65eSdan static void idxWriteFree(IdxWrite *pTab){
1171280db65eSdan   IdxWrite *pIter;
1172280db65eSdan   IdxWrite *pNext;
1173280db65eSdan   for(pIter=pTab; pIter; pIter=pNext){
1174280db65eSdan     pNext = pIter->pNext;
1175280db65eSdan     sqlite3_free(pIter);
1176280db65eSdan   }
1177280db65eSdan }
1178280db65eSdan 
1179280db65eSdan 
11808e0b8e06Sdan 
118196d43a05Sdan /*
118296d43a05Sdan ** This function is called after candidate indexes have been created. It
118396d43a05Sdan ** runs all the queries to see which indexes they prefer, and populates
118496d43a05Sdan ** IdxStatement.zIdx and IdxStatement.zEQP with the results.
118596d43a05Sdan */
idxFindIndexes(sqlite3expert * p,char ** pzErr)11864baf43ffSdan static int idxFindIndexes(
11878e0b8e06Sdan   sqlite3expert *p,
11888e0b8e06Sdan   char **pzErr                         /* OUT: Error message (sqlite3_malloc) */
11898e0b8e06Sdan ){
11908e0b8e06Sdan   IdxStatement *pStmt;
11918e0b8e06Sdan   sqlite3 *dbm = p->dbm;
119265e67ed1Sdan   int rc = SQLITE_OK;
11938e0b8e06Sdan 
119465e67ed1Sdan   IdxHash hIdx;
119565e67ed1Sdan   idxHashInit(&hIdx);
11968e0b8e06Sdan 
11978e0b8e06Sdan   for(pStmt=p->pStatement; rc==SQLITE_OK && pStmt; pStmt=pStmt->pNext){
119865e67ed1Sdan     IdxHashEntry *pEntry;
11998e0b8e06Sdan     sqlite3_stmt *pExplain = 0;
120065e67ed1Sdan     idxHashClear(&hIdx);
12018e0b8e06Sdan     rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr,
12028e0b8e06Sdan         "EXPLAIN QUERY PLAN %s", pStmt->zSql
12038e0b8e06Sdan     );
12048e0b8e06Sdan     while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
1205cdf88760Sdrh       /* int iId = sqlite3_column_int(pExplain, 0); */
1206cdf88760Sdrh       /* int iParent = sqlite3_column_int(pExplain, 1); */
1207cdf88760Sdrh       /* int iNotUsed = sqlite3_column_int(pExplain, 2); */
12088e0b8e06Sdan       const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
1209b2c6fe22Sdan       int nDetail;
121065e67ed1Sdan       int i;
12118e0b8e06Sdan 
1212b2c6fe22Sdan       if( !zDetail ) continue;
1213b2c6fe22Sdan       nDetail = STRLEN(zDetail);
1214b2c6fe22Sdan 
12158e0b8e06Sdan       for(i=0; i<nDetail; i++){
12168e0b8e06Sdan         const char *zIdx = 0;
121723e3c340Sdan         if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
12188e0b8e06Sdan           zIdx = &zDetail[i+13];
121923e3c340Sdan         }else if( i+22<nDetail
122023e3c340Sdan             && memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0
122123e3c340Sdan         ){
12228e0b8e06Sdan           zIdx = &zDetail[i+22];
12238e0b8e06Sdan         }
12248e0b8e06Sdan         if( zIdx ){
122565e67ed1Sdan           const char *zSql;
12268e0b8e06Sdan           int nIdx = 0;
12278e0b8e06Sdan           while( zIdx[nIdx]!='\0' && (zIdx[nIdx]!=' ' || zIdx[nIdx+1]!='(') ){
12288e0b8e06Sdan             nIdx++;
12298e0b8e06Sdan           }
123065e67ed1Sdan           zSql = idxHashSearch(&p->hIdx, zIdx, nIdx);
123165e67ed1Sdan           if( zSql ){
123265e67ed1Sdan             idxHashAdd(&rc, &hIdx, zSql, 0);
12338e0b8e06Sdan             if( rc ) goto find_indexes_out;
12348e0b8e06Sdan           }
12358e0b8e06Sdan           break;
12368e0b8e06Sdan         }
12378e0b8e06Sdan       }
12388e0b8e06Sdan 
12391d40cdbdSdan       if( zDetail[0]!='-' ){
1240cdf88760Sdrh         pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%s\n", zDetail);
12418e0b8e06Sdan       }
12421d40cdbdSdan     }
12438e0b8e06Sdan 
124465e67ed1Sdan     for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
1245e7c3aca6Sdan       pStmt->zIdx = idxAppendText(&rc, pStmt->zIdx, "%s;\n", pEntry->zKey);
124665e67ed1Sdan     }
124765e67ed1Sdan 
124865e67ed1Sdan     idxFinalize(&rc, pExplain);
12498e0b8e06Sdan   }
12508e0b8e06Sdan 
12518e0b8e06Sdan  find_indexes_out:
1252cd84474eSdan   idxHashClear(&hIdx);
12538e0b8e06Sdan   return rc;
12548e0b8e06Sdan }
12558e0b8e06Sdan 
idxAuthCallback(void * pCtx,int eOp,const char * z3,const char * z4,const char * zDb,const char * zTrigger)1256280db65eSdan static int idxAuthCallback(
1257280db65eSdan   void *pCtx,
1258280db65eSdan   int eOp,
1259280db65eSdan   const char *z3,
1260280db65eSdan   const char *z4,
1261280db65eSdan   const char *zDb,
1262280db65eSdan   const char *zTrigger
1263280db65eSdan ){
1264280db65eSdan   int rc = SQLITE_OK;
1265b9685185Sdrh   (void)z4;
1266b9685185Sdrh   (void)zTrigger;
1267280db65eSdan   if( eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE || eOp==SQLITE_DELETE ){
1268280db65eSdan     if( sqlite3_stricmp(zDb, "main")==0 ){
1269280db65eSdan       sqlite3expert *p = (sqlite3expert*)pCtx;
1270280db65eSdan       IdxTable *pTab;
1271280db65eSdan       for(pTab=p->pTable; pTab; pTab=pTab->pNext){
1272280db65eSdan         if( 0==sqlite3_stricmp(z3, pTab->zName) ) break;
1273280db65eSdan       }
1274280db65eSdan       if( pTab ){
1275280db65eSdan         IdxWrite *pWrite;
1276280db65eSdan         for(pWrite=p->pWrite; pWrite; pWrite=pWrite->pNext){
1277280db65eSdan           if( pWrite->pTab==pTab && pWrite->eOp==eOp ) break;
1278280db65eSdan         }
1279280db65eSdan         if( pWrite==0 ){
1280280db65eSdan           pWrite = idxMalloc(&rc, sizeof(IdxWrite));
1281280db65eSdan           if( rc==SQLITE_OK ){
1282280db65eSdan             pWrite->pTab = pTab;
1283280db65eSdan             pWrite->eOp = eOp;
1284280db65eSdan             pWrite->pNext = p->pWrite;
1285280db65eSdan             p->pWrite = pWrite;
1286280db65eSdan           }
1287280db65eSdan         }
1288280db65eSdan       }
1289280db65eSdan     }
1290280db65eSdan   }
1291280db65eSdan   return rc;
1292280db65eSdan }
1293280db65eSdan 
idxProcessOneTrigger(sqlite3expert * p,IdxWrite * pWrite,char ** pzErr)1294280db65eSdan static int idxProcessOneTrigger(
1295280db65eSdan   sqlite3expert *p,
1296280db65eSdan   IdxWrite *pWrite,
1297280db65eSdan   char **pzErr
1298280db65eSdan ){
1299e53b4f97Sdan   static const char *zInt = UNIQUE_TABLE_NAME;
1300e53b4f97Sdan   static const char *zDrop = "DROP TABLE " UNIQUE_TABLE_NAME;
1301280db65eSdan   IdxTable *pTab = pWrite->pTab;
1302280db65eSdan   const char *zTab = pTab->zName;
1303280db65eSdan   const char *zSql =
1304067b92baSdrh     "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_schema "
1305280db65eSdan     "WHERE tbl_name = %Q AND type IN ('table', 'trigger') "
1306280db65eSdan     "ORDER BY type;";
1307280db65eSdan   sqlite3_stmt *pSelect = 0;
1308280db65eSdan   int rc = SQLITE_OK;
1309280db65eSdan   char *zWrite = 0;
1310280db65eSdan 
1311280db65eSdan   /* Create the table and its triggers in the temp schema */
1312280db65eSdan   rc = idxPrintfPrepareStmt(p->db, &pSelect, pzErr, zSql, zTab, zTab);
1313280db65eSdan   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSelect) ){
1314280db65eSdan     const char *zCreate = (const char*)sqlite3_column_text(pSelect, 0);
1315e0adf602Sdrh     if( zCreate==0 ) continue;
1316280db65eSdan     rc = sqlite3_exec(p->dbv, zCreate, 0, 0, pzErr);
1317280db65eSdan   }
1318280db65eSdan   idxFinalize(&rc, pSelect);
1319280db65eSdan 
1320280db65eSdan   /* Rename the table in the temp schema to zInt */
1321280db65eSdan   if( rc==SQLITE_OK ){
1322280db65eSdan     char *z = sqlite3_mprintf("ALTER TABLE temp.%Q RENAME TO %Q", zTab, zInt);
1323280db65eSdan     if( z==0 ){
1324280db65eSdan       rc = SQLITE_NOMEM;
1325280db65eSdan     }else{
1326280db65eSdan       rc = sqlite3_exec(p->dbv, z, 0, 0, pzErr);
1327280db65eSdan       sqlite3_free(z);
1328280db65eSdan     }
1329280db65eSdan   }
1330280db65eSdan 
1331280db65eSdan   switch( pWrite->eOp ){
1332280db65eSdan     case SQLITE_INSERT: {
1333280db65eSdan       int i;
1334280db65eSdan       zWrite = idxAppendText(&rc, zWrite, "INSERT INTO %Q VALUES(", zInt);
1335280db65eSdan       for(i=0; i<pTab->nCol; i++){
1336280db65eSdan         zWrite = idxAppendText(&rc, zWrite, "%s?", i==0 ? "" : ", ");
1337280db65eSdan       }
1338280db65eSdan       zWrite = idxAppendText(&rc, zWrite, ")");
1339280db65eSdan       break;
1340280db65eSdan     }
1341280db65eSdan     case SQLITE_UPDATE: {
1342280db65eSdan       int i;
1343280db65eSdan       zWrite = idxAppendText(&rc, zWrite, "UPDATE %Q SET ", zInt);
1344280db65eSdan       for(i=0; i<pTab->nCol; i++){
1345280db65eSdan         zWrite = idxAppendText(&rc, zWrite, "%s%Q=?", i==0 ? "" : ", ",
1346280db65eSdan             pTab->aCol[i].zName
1347280db65eSdan         );
1348280db65eSdan       }
1349280db65eSdan       break;
1350280db65eSdan     }
1351280db65eSdan     default: {
1352280db65eSdan       assert( pWrite->eOp==SQLITE_DELETE );
1353280db65eSdan       if( rc==SQLITE_OK ){
1354280db65eSdan         zWrite = sqlite3_mprintf("DELETE FROM %Q", zInt);
1355280db65eSdan         if( zWrite==0 ) rc = SQLITE_NOMEM;
1356280db65eSdan       }
1357280db65eSdan     }
1358280db65eSdan   }
1359280db65eSdan 
1360280db65eSdan   if( rc==SQLITE_OK ){
1361280db65eSdan     sqlite3_stmt *pX = 0;
1362280db65eSdan     rc = sqlite3_prepare_v2(p->dbv, zWrite, -1, &pX, 0);
1363280db65eSdan     idxFinalize(&rc, pX);
13647853002cSdan     if( rc!=SQLITE_OK ){
13657853002cSdan       idxDatabaseError(p->dbv, pzErr);
13667853002cSdan     }
1367280db65eSdan   }
1368280db65eSdan   sqlite3_free(zWrite);
1369280db65eSdan 
1370280db65eSdan   if( rc==SQLITE_OK ){
1371280db65eSdan     rc = sqlite3_exec(p->dbv, zDrop, 0, 0, pzErr);
1372280db65eSdan   }
1373280db65eSdan 
1374280db65eSdan   return rc;
1375280db65eSdan }
1376280db65eSdan 
idxProcessTriggers(sqlite3expert * p,char ** pzErr)1377280db65eSdan static int idxProcessTriggers(sqlite3expert *p, char **pzErr){
1378280db65eSdan   int rc = SQLITE_OK;
1379280db65eSdan   IdxWrite *pEnd = 0;
1380280db65eSdan   IdxWrite *pFirst = p->pWrite;
1381280db65eSdan 
1382280db65eSdan   while( rc==SQLITE_OK && pFirst!=pEnd ){
1383280db65eSdan     IdxWrite *pIter;
1384280db65eSdan     for(pIter=pFirst; rc==SQLITE_OK && pIter!=pEnd; pIter=pIter->pNext){
1385280db65eSdan       rc = idxProcessOneTrigger(p, pIter, pzErr);
1386280db65eSdan     }
1387280db65eSdan     pEnd = pFirst;
1388280db65eSdan     pFirst = p->pWrite;
1389280db65eSdan   }
1390280db65eSdan 
1391280db65eSdan   return rc;
1392280db65eSdan }
1393280db65eSdan 
1394280db65eSdan 
idxCreateVtabSchema(sqlite3expert * p,char ** pzErrmsg)13950824ccf2Sdan static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
13960824ccf2Sdan   int rc = idxRegisterVtab(p);
13970824ccf2Sdan   sqlite3_stmt *pSchema = 0;
13980824ccf2Sdan 
13990824ccf2Sdan   /* For each table in the main db schema:
14000824ccf2Sdan   **
14010824ccf2Sdan   **   1) Add an entry to the p->pTable list, and
14020824ccf2Sdan   **   2) Create the equivalent virtual table in dbv.
14030824ccf2Sdan   */
14040824ccf2Sdan   rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
1405067b92baSdrh       "SELECT type, name, sql, 1 FROM sqlite_schema "
14067853002cSdan       "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
14077853002cSdan       " UNION ALL "
1408067b92baSdrh       "SELECT type, name, sql, 2 FROM sqlite_schema "
14097853002cSdan       "WHERE type = 'trigger'"
1410067b92baSdrh       "  AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
14117853002cSdan       "ORDER BY 4, 1"
14120824ccf2Sdan   );
14130824ccf2Sdan   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
14140824ccf2Sdan     const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
14150824ccf2Sdan     const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
14160824ccf2Sdan     const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
14170824ccf2Sdan 
1418e0adf602Sdrh     if( zType==0 || zName==0 ) continue;
14197853002cSdan     if( zType[0]=='v' || zType[1]=='r' ){
1420e0adf602Sdrh       if( zSql ) rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
14210824ccf2Sdan     }else{
14220824ccf2Sdan       IdxTable *pTab;
14230824ccf2Sdan       rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
14240824ccf2Sdan       if( rc==SQLITE_OK ){
14250824ccf2Sdan         int i;
14260824ccf2Sdan         char *zInner = 0;
14270824ccf2Sdan         char *zOuter = 0;
14280824ccf2Sdan         pTab->pNext = p->pTable;
14290824ccf2Sdan         p->pTable = pTab;
14300824ccf2Sdan 
14310824ccf2Sdan         /* The statement the vtab will pass to sqlite3_declare_vtab() */
14320824ccf2Sdan         zInner = idxAppendText(&rc, 0, "CREATE TABLE x(");
14330824ccf2Sdan         for(i=0; i<pTab->nCol; i++){
14340824ccf2Sdan           zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s",
14350824ccf2Sdan               (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl
14360824ccf2Sdan           );
14370824ccf2Sdan         }
14380824ccf2Sdan         zInner = idxAppendText(&rc, zInner, ")");
14390824ccf2Sdan 
14400824ccf2Sdan         /* The CVT statement to create the vtab */
14410824ccf2Sdan         zOuter = idxAppendText(&rc, 0,
14420824ccf2Sdan             "CREATE VIRTUAL TABLE %Q USING expert(%Q)", zName, zInner
14430824ccf2Sdan         );
14440824ccf2Sdan         if( rc==SQLITE_OK ){
14450824ccf2Sdan           rc = sqlite3_exec(p->dbv, zOuter, 0, 0, pzErrmsg);
14460824ccf2Sdan         }
14470824ccf2Sdan         sqlite3_free(zInner);
14480824ccf2Sdan         sqlite3_free(zOuter);
14490824ccf2Sdan       }
14500824ccf2Sdan     }
14510824ccf2Sdan   }
145279610f5dSdan   idxFinalize(&rc, pSchema);
14530824ccf2Sdan   return rc;
14540824ccf2Sdan }
14550824ccf2Sdan 
1456e53b4f97Sdan struct IdxSampleCtx {
1457e53b4f97Sdan   int iTarget;
1458e53b4f97Sdan   double target;                  /* Target nRet/nRow value */
1459e53b4f97Sdan   double nRow;                    /* Number of rows seen */
1460e53b4f97Sdan   double nRet;                    /* Number of rows returned */
1461e53b4f97Sdan };
1462e53b4f97Sdan 
idxSampleFunc(sqlite3_context * pCtx,int argc,sqlite3_value ** argv)1463e53b4f97Sdan static void idxSampleFunc(
1464e53b4f97Sdan   sqlite3_context *pCtx,
1465e53b4f97Sdan   int argc,
1466e53b4f97Sdan   sqlite3_value **argv
1467e53b4f97Sdan ){
1468e53b4f97Sdan   struct IdxSampleCtx *p = (struct IdxSampleCtx*)sqlite3_user_data(pCtx);
1469e53b4f97Sdan   int bRet;
1470e53b4f97Sdan 
1471b9685185Sdrh   (void)argv;
1472e53b4f97Sdan   assert( argc==0 );
1473e53b4f97Sdan   if( p->nRow==0.0 ){
1474e53b4f97Sdan     bRet = 1;
1475e53b4f97Sdan   }else{
1476e53b4f97Sdan     bRet = (p->nRet / p->nRow) <= p->target;
1477e53b4f97Sdan     if( bRet==0 ){
1478e53b4f97Sdan       unsigned short rnd;
1479e53b4f97Sdan       sqlite3_randomness(2, (void*)&rnd);
1480e53b4f97Sdan       bRet = ((int)rnd % 100) <= p->iTarget;
1481e53b4f97Sdan     }
1482e53b4f97Sdan   }
1483e53b4f97Sdan 
1484e53b4f97Sdan   sqlite3_result_int(pCtx, bRet);
1485e53b4f97Sdan   p->nRow += 1.0;
1486e53b4f97Sdan   p->nRet += (double)bRet;
1487e53b4f97Sdan }
1488e53b4f97Sdan 
1489a6ed5a4fSdan struct IdxRemCtx {
1490a6ed5a4fSdan   int nSlot;
1491a6ed5a4fSdan   struct IdxRemSlot {
1492a6ed5a4fSdan     int eType;                    /* SQLITE_NULL, INTEGER, REAL, TEXT, BLOB */
1493a6ed5a4fSdan     i64 iVal;                     /* SQLITE_INTEGER value */
1494a6ed5a4fSdan     double rVal;                  /* SQLITE_FLOAT value */
1495a6ed5a4fSdan     int nByte;                    /* Bytes of space allocated at z */
1496a6ed5a4fSdan     int n;                        /* Size of buffer z */
1497a6ed5a4fSdan     char *z;                      /* SQLITE_TEXT/BLOB value */
1498a6ed5a4fSdan   } aSlot[1];
1499a6ed5a4fSdan };
1500a6ed5a4fSdan 
1501a6ed5a4fSdan /*
1502a6ed5a4fSdan ** Implementation of scalar function rem().
1503a6ed5a4fSdan */
idxRemFunc(sqlite3_context * pCtx,int argc,sqlite3_value ** argv)1504a6ed5a4fSdan static void idxRemFunc(
1505a6ed5a4fSdan   sqlite3_context *pCtx,
1506a6ed5a4fSdan   int argc,
1507a6ed5a4fSdan   sqlite3_value **argv
1508a6ed5a4fSdan ){
1509a6ed5a4fSdan   struct IdxRemCtx *p = (struct IdxRemCtx*)sqlite3_user_data(pCtx);
1510a6ed5a4fSdan   struct IdxRemSlot *pSlot;
1511a6ed5a4fSdan   int iSlot;
1512a6ed5a4fSdan   assert( argc==2 );
1513a6ed5a4fSdan 
1514a6ed5a4fSdan   iSlot = sqlite3_value_int(argv[0]);
1515a6ed5a4fSdan   assert( iSlot<=p->nSlot );
1516a6ed5a4fSdan   pSlot = &p->aSlot[iSlot];
1517a6ed5a4fSdan 
1518a6ed5a4fSdan   switch( pSlot->eType ){
1519a6ed5a4fSdan     case SQLITE_NULL:
1520a6ed5a4fSdan       /* no-op */
1521a6ed5a4fSdan       break;
1522a6ed5a4fSdan 
1523a6ed5a4fSdan     case SQLITE_INTEGER:
1524a6ed5a4fSdan       sqlite3_result_int64(pCtx, pSlot->iVal);
1525a6ed5a4fSdan       break;
1526a6ed5a4fSdan 
1527a6ed5a4fSdan     case SQLITE_FLOAT:
1528a6ed5a4fSdan       sqlite3_result_double(pCtx, pSlot->rVal);
1529a6ed5a4fSdan       break;
1530a6ed5a4fSdan 
1531a6ed5a4fSdan     case SQLITE_BLOB:
1532a6ed5a4fSdan       sqlite3_result_blob(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
1533a6ed5a4fSdan       break;
1534a6ed5a4fSdan 
1535a6ed5a4fSdan     case SQLITE_TEXT:
1536a6ed5a4fSdan       sqlite3_result_text(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
1537a6ed5a4fSdan       break;
1538a6ed5a4fSdan   }
1539a6ed5a4fSdan 
1540a6ed5a4fSdan   pSlot->eType = sqlite3_value_type(argv[1]);
1541a6ed5a4fSdan   switch( pSlot->eType ){
1542a6ed5a4fSdan     case SQLITE_NULL:
1543a6ed5a4fSdan       /* no-op */
1544a6ed5a4fSdan       break;
1545a6ed5a4fSdan 
1546a6ed5a4fSdan     case SQLITE_INTEGER:
1547a6ed5a4fSdan       pSlot->iVal = sqlite3_value_int64(argv[1]);
1548a6ed5a4fSdan       break;
1549a6ed5a4fSdan 
1550a6ed5a4fSdan     case SQLITE_FLOAT:
1551a6ed5a4fSdan       pSlot->rVal = sqlite3_value_double(argv[1]);
1552a6ed5a4fSdan       break;
1553a6ed5a4fSdan 
1554a6ed5a4fSdan     case SQLITE_BLOB:
1555a6ed5a4fSdan     case SQLITE_TEXT: {
1556a6ed5a4fSdan       int nByte = sqlite3_value_bytes(argv[1]);
1557e0adf602Sdrh       const void *pData = 0;
1558a6ed5a4fSdan       if( nByte>pSlot->nByte ){
1559a6ed5a4fSdan         char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2);
1560a6ed5a4fSdan         if( zNew==0 ){
1561a6ed5a4fSdan           sqlite3_result_error_nomem(pCtx);
1562a6ed5a4fSdan           return;
1563a6ed5a4fSdan         }
1564a6ed5a4fSdan         pSlot->nByte = nByte*2;
1565a6ed5a4fSdan         pSlot->z = zNew;
1566a6ed5a4fSdan       }
1567a6ed5a4fSdan       pSlot->n = nByte;
1568a6ed5a4fSdan       if( pSlot->eType==SQLITE_BLOB ){
1569e0adf602Sdrh         pData = sqlite3_value_blob(argv[1]);
1570e0adf602Sdrh         if( pData ) memcpy(pSlot->z, pData, nByte);
1571a6ed5a4fSdan       }else{
1572e0adf602Sdrh         pData = sqlite3_value_text(argv[1]);
1573e0adf602Sdrh         memcpy(pSlot->z, pData, nByte);
1574a6ed5a4fSdan       }
1575a6ed5a4fSdan       break;
1576a6ed5a4fSdan     }
1577a6ed5a4fSdan   }
1578a6ed5a4fSdan }
1579a6ed5a4fSdan 
idxLargestIndex(sqlite3 * db,int * pnMax,char ** pzErr)1580a6ed5a4fSdan static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){
1581a6ed5a4fSdan   int rc = SQLITE_OK;
1582a6ed5a4fSdan   const char *zMax =
1583a6ed5a4fSdan     "SELECT max(i.seqno) FROM "
1584067b92baSdrh     "  sqlite_schema AS s, "
1585a6ed5a4fSdan     "  pragma_index_list(s.name) AS l, "
1586a6ed5a4fSdan     "  pragma_index_info(l.name) AS i "
1587a6ed5a4fSdan     "WHERE s.type = 'table'";
1588a6ed5a4fSdan   sqlite3_stmt *pMax = 0;
1589a6ed5a4fSdan 
1590a6ed5a4fSdan   *pnMax = 0;
1591a6ed5a4fSdan   rc = idxPrepareStmt(db, &pMax, pzErr, zMax);
1592a6ed5a4fSdan   if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){
1593a6ed5a4fSdan     *pnMax = sqlite3_column_int(pMax, 0) + 1;
1594a6ed5a4fSdan   }
1595a6ed5a4fSdan   idxFinalize(&rc, pMax);
1596a6ed5a4fSdan 
1597a6ed5a4fSdan   return rc;
1598a6ed5a4fSdan }
1599a6ed5a4fSdan 
idxPopulateOneStat1(sqlite3expert * p,sqlite3_stmt * pIndexXInfo,sqlite3_stmt * pWriteStat,const char * zTab,const char * zIdx,char ** pzErr)1600a6ed5a4fSdan static int idxPopulateOneStat1(
1601a6ed5a4fSdan   sqlite3expert *p,
1602a6ed5a4fSdan   sqlite3_stmt *pIndexXInfo,
1603a6ed5a4fSdan   sqlite3_stmt *pWriteStat,
1604a6ed5a4fSdan   const char *zTab,
1605a6ed5a4fSdan   const char *zIdx,
1606a6ed5a4fSdan   char **pzErr
1607a6ed5a4fSdan ){
1608a6ed5a4fSdan   char *zCols = 0;
1609a6ed5a4fSdan   char *zOrder = 0;
1610a6ed5a4fSdan   char *zQuery = 0;
1611a6ed5a4fSdan   int nCol = 0;
1612a6ed5a4fSdan   int i;
1613a6ed5a4fSdan   sqlite3_stmt *pQuery = 0;
1614a6ed5a4fSdan   int *aStat = 0;
1615a6ed5a4fSdan   int rc = SQLITE_OK;
1616a6ed5a4fSdan 
1617e53b4f97Sdan   assert( p->iSample>0 );
1618e53b4f97Sdan 
1619a6ed5a4fSdan   /* Formulate the query text */
1620a6ed5a4fSdan   sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
1621a6ed5a4fSdan   while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
1622a6ed5a4fSdan     const char *zComma = zCols==0 ? "" : ", ";
1623a6ed5a4fSdan     const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
1624a6ed5a4fSdan     const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
1625a6ed5a4fSdan     zCols = idxAppendText(&rc, zCols,
1626a6ed5a4fSdan         "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl
1627a6ed5a4fSdan     );
1628a6ed5a4fSdan     zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
1629a6ed5a4fSdan   }
1630c48e0271Sdan   sqlite3_reset(pIndexXInfo);
1631a6ed5a4fSdan   if( rc==SQLITE_OK ){
1632e53b4f97Sdan     if( p->iSample==100 ){
1633a6ed5a4fSdan       zQuery = sqlite3_mprintf(
1634a6ed5a4fSdan           "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder
1635a6ed5a4fSdan       );
1636e53b4f97Sdan     }else{
1637e53b4f97Sdan       zQuery = sqlite3_mprintf(
1638e53b4f97Sdan           "SELECT %s FROM temp."UNIQUE_TABLE_NAME" x ORDER BY %s", zCols, zOrder
1639e53b4f97Sdan       );
1640e53b4f97Sdan     }
1641a6ed5a4fSdan   }
1642a6ed5a4fSdan   sqlite3_free(zCols);
1643a6ed5a4fSdan   sqlite3_free(zOrder);
1644a6ed5a4fSdan 
1645a6ed5a4fSdan   /* Formulate the query text */
1646a6ed5a4fSdan   if( rc==SQLITE_OK ){
16472ed99defSdan     sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
16482ed99defSdan     rc = idxPrepareStmt(dbrem, &pQuery, pzErr, zQuery);
1649a6ed5a4fSdan   }
1650a6ed5a4fSdan   sqlite3_free(zQuery);
1651a6ed5a4fSdan 
1652a6ed5a4fSdan   if( rc==SQLITE_OK ){
1653a6ed5a4fSdan     aStat = (int*)idxMalloc(&rc, sizeof(int)*(nCol+1));
1654a6ed5a4fSdan   }
1655a6ed5a4fSdan   if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
1656a6ed5a4fSdan     IdxHashEntry *pEntry;
1657a6ed5a4fSdan     char *zStat = 0;
1658a6ed5a4fSdan     for(i=0; i<=nCol; i++) aStat[i] = 1;
1659a6ed5a4fSdan     while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
1660a6ed5a4fSdan       aStat[0]++;
1661a6ed5a4fSdan       for(i=0; i<nCol; i++){
1662a6ed5a4fSdan         if( sqlite3_column_int(pQuery, i)==0 ) break;
1663a6ed5a4fSdan       }
1664a6ed5a4fSdan       for(/*no-op*/; i<nCol; i++){
1665a6ed5a4fSdan         aStat[i+1]++;
1666a6ed5a4fSdan       }
1667a6ed5a4fSdan     }
1668a6ed5a4fSdan 
1669a6ed5a4fSdan     if( rc==SQLITE_OK ){
1670a6ed5a4fSdan       int s0 = aStat[0];
1671a6ed5a4fSdan       zStat = sqlite3_mprintf("%d", s0);
1672a6ed5a4fSdan       if( zStat==0 ) rc = SQLITE_NOMEM;
1673a6ed5a4fSdan       for(i=1; rc==SQLITE_OK && i<=nCol; i++){
1674a6ed5a4fSdan         zStat = idxAppendText(&rc, zStat, " %d", (s0+aStat[i]/2) / aStat[i]);
1675a6ed5a4fSdan       }
1676a6ed5a4fSdan     }
1677a6ed5a4fSdan 
1678a6ed5a4fSdan     if( rc==SQLITE_OK ){
1679a6ed5a4fSdan       sqlite3_bind_text(pWriteStat, 1, zTab, -1, SQLITE_STATIC);
1680a6ed5a4fSdan       sqlite3_bind_text(pWriteStat, 2, zIdx, -1, SQLITE_STATIC);
1681a6ed5a4fSdan       sqlite3_bind_text(pWriteStat, 3, zStat, -1, SQLITE_STATIC);
1682a6ed5a4fSdan       sqlite3_step(pWriteStat);
1683a6ed5a4fSdan       rc = sqlite3_reset(pWriteStat);
1684a6ed5a4fSdan     }
1685a6ed5a4fSdan 
1686bd0f1dbdSdrh     pEntry = idxHashFind(&p->hIdx, zIdx, STRLEN(zIdx));
1687a6ed5a4fSdan     if( pEntry ){
1688a6ed5a4fSdan       assert( pEntry->zVal2==0 );
1689a6ed5a4fSdan       pEntry->zVal2 = zStat;
1690a6ed5a4fSdan     }else{
1691a6ed5a4fSdan       sqlite3_free(zStat);
1692a6ed5a4fSdan     }
1693a6ed5a4fSdan   }
1694a6ed5a4fSdan   sqlite3_free(aStat);
1695a6ed5a4fSdan   idxFinalize(&rc, pQuery);
1696a6ed5a4fSdan 
1697a6ed5a4fSdan   return rc;
1698a6ed5a4fSdan }
1699a6ed5a4fSdan 
idxBuildSampleTable(sqlite3expert * p,const char * zTab)1700e53b4f97Sdan static int idxBuildSampleTable(sqlite3expert *p, const char *zTab){
1701e53b4f97Sdan   int rc;
1702e53b4f97Sdan   char *zSql;
1703e53b4f97Sdan 
17042ed99defSdan   rc = sqlite3_exec(p->dbv,"DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
1705e53b4f97Sdan   if( rc!=SQLITE_OK ) return rc;
1706e53b4f97Sdan 
1707e53b4f97Sdan   zSql = sqlite3_mprintf(
17082ed99defSdan       "CREATE TABLE temp." UNIQUE_TABLE_NAME " AS SELECT * FROM %Q", zTab
1709e53b4f97Sdan   );
1710e53b4f97Sdan   if( zSql==0 ) return SQLITE_NOMEM;
17112ed99defSdan   rc = sqlite3_exec(p->dbv, zSql, 0, 0, 0);
1712e53b4f97Sdan   sqlite3_free(zSql);
1713e53b4f97Sdan 
1714e53b4f97Sdan   return rc;
1715e53b4f97Sdan }
1716e53b4f97Sdan 
1717a6ed5a4fSdan /*
1718a6ed5a4fSdan ** This function is called as part of sqlite3_expert_analyze(). Candidate
1719a6ed5a4fSdan ** indexes have already been created in database sqlite3expert.dbm, this
1720a6ed5a4fSdan ** function populates sqlite_stat1 table in the same database.
1721a6ed5a4fSdan **
1722a6ed5a4fSdan ** The stat1 data is generated by querying the
1723a6ed5a4fSdan */
idxPopulateStat1(sqlite3expert * p,char ** pzErr)1724a6ed5a4fSdan static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
1725a6ed5a4fSdan   int rc = SQLITE_OK;
1726a6ed5a4fSdan   int nMax =0;
1727a6ed5a4fSdan   struct IdxRemCtx *pCtx = 0;
1728e53b4f97Sdan   struct IdxSampleCtx samplectx;
1729a6ed5a4fSdan   int i;
1730e53b4f97Sdan   i64 iPrev = -100000;
1731a6ed5a4fSdan   sqlite3_stmt *pAllIndex = 0;
1732a6ed5a4fSdan   sqlite3_stmt *pIndexXInfo = 0;
1733a6ed5a4fSdan   sqlite3_stmt *pWrite = 0;
1734a6ed5a4fSdan 
1735a6ed5a4fSdan   const char *zAllIndex =
1736e53b4f97Sdan     "SELECT s.rowid, s.name, l.name FROM "
1737067b92baSdrh     "  sqlite_schema AS s, "
1738a6ed5a4fSdan     "  pragma_index_list(s.name) AS l "
1739a6ed5a4fSdan     "WHERE s.type = 'table'";
1740a6ed5a4fSdan   const char *zIndexXInfo =
1741a6ed5a4fSdan     "SELECT name, coll FROM pragma_index_xinfo(?) WHERE key";
1742a6ed5a4fSdan   const char *zWrite = "INSERT INTO sqlite_stat1 VALUES(?, ?, ?)";
1743a6ed5a4fSdan 
1744e53b4f97Sdan   /* If iSample==0, no sqlite_stat1 data is required. */
1745e53b4f97Sdan   if( p->iSample==0 ) return SQLITE_OK;
1746e53b4f97Sdan 
1747a6ed5a4fSdan   rc = idxLargestIndex(p->dbm, &nMax, pzErr);
1748a6ed5a4fSdan   if( nMax<=0 || rc!=SQLITE_OK ) return rc;
1749a6ed5a4fSdan 
1750a6ed5a4fSdan   rc = sqlite3_exec(p->dbm, "ANALYZE; PRAGMA writable_schema=1", 0, 0, 0);
1751a6ed5a4fSdan 
1752a6ed5a4fSdan   if( rc==SQLITE_OK ){
1753a6ed5a4fSdan     int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
1754a6ed5a4fSdan     pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte);
1755a6ed5a4fSdan   }
1756a6ed5a4fSdan 
1757a6ed5a4fSdan   if( rc==SQLITE_OK ){
17582ed99defSdan     sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
1759a6ed5a4fSdan     rc = sqlite3_create_function(
17602ed99defSdan         dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
1761a6ed5a4fSdan     );
1762a6ed5a4fSdan   }
1763e53b4f97Sdan   if( rc==SQLITE_OK ){
1764e53b4f97Sdan     rc = sqlite3_create_function(
1765e53b4f97Sdan         p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
1766e53b4f97Sdan     );
1767e53b4f97Sdan   }
1768a6ed5a4fSdan 
1769a6ed5a4fSdan   if( rc==SQLITE_OK ){
1770a6ed5a4fSdan     pCtx->nSlot = nMax+1;
1771a6ed5a4fSdan     rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex);
1772a6ed5a4fSdan   }
1773a6ed5a4fSdan   if( rc==SQLITE_OK ){
1774a6ed5a4fSdan     rc = idxPrepareStmt(p->dbm, &pIndexXInfo, pzErr, zIndexXInfo);
1775a6ed5a4fSdan   }
1776a6ed5a4fSdan   if( rc==SQLITE_OK ){
1777a6ed5a4fSdan     rc = idxPrepareStmt(p->dbm, &pWrite, pzErr, zWrite);
1778a6ed5a4fSdan   }
1779a6ed5a4fSdan 
1780a6ed5a4fSdan   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pAllIndex) ){
1781e53b4f97Sdan     i64 iRowid = sqlite3_column_int64(pAllIndex, 0);
1782e53b4f97Sdan     const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1);
1783e53b4f97Sdan     const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2);
1784e0adf602Sdrh     if( zTab==0 || zIdx==0 ) continue;
1785e53b4f97Sdan     if( p->iSample<100 && iPrev!=iRowid ){
1786e53b4f97Sdan       samplectx.target = (double)p->iSample / 100.0;
1787e53b4f97Sdan       samplectx.iTarget = p->iSample;
1788e53b4f97Sdan       samplectx.nRow = 0.0;
1789e53b4f97Sdan       samplectx.nRet = 0.0;
1790e53b4f97Sdan       rc = idxBuildSampleTable(p, zTab);
1791e53b4f97Sdan       if( rc!=SQLITE_OK ) break;
1792e53b4f97Sdan     }
1793a6ed5a4fSdan     rc = idxPopulateOneStat1(p, pIndexXInfo, pWrite, zTab, zIdx, pzErr);
1794e53b4f97Sdan     iPrev = iRowid;
1795e53b4f97Sdan   }
1796bc3f784cSdan   if( rc==SQLITE_OK && p->iSample<100 ){
1797bc3f784cSdan     rc = sqlite3_exec(p->dbv,
1798bc3f784cSdan         "DROP TABLE IF EXISTS temp." UNIQUE_TABLE_NAME, 0,0,0
1799e53b4f97Sdan     );
1800a6ed5a4fSdan   }
1801a6ed5a4fSdan 
1802a6ed5a4fSdan   idxFinalize(&rc, pAllIndex);
1803a6ed5a4fSdan   idxFinalize(&rc, pIndexXInfo);
1804a6ed5a4fSdan   idxFinalize(&rc, pWrite);
1805a6ed5a4fSdan 
18064338000dSmistachkin   if( pCtx ){
1807a6ed5a4fSdan     for(i=0; i<pCtx->nSlot; i++){
1808a6ed5a4fSdan       sqlite3_free(pCtx->aSlot[i].z);
1809a6ed5a4fSdan     }
1810a6ed5a4fSdan     sqlite3_free(pCtx);
18114338000dSmistachkin   }
1812a6ed5a4fSdan 
1813a6ed5a4fSdan   if( rc==SQLITE_OK ){
1814067b92baSdrh     rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
1815a6ed5a4fSdan   }
1816e53b4f97Sdan 
1817e53b4f97Sdan   sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
1818a6ed5a4fSdan   return rc;
1819a6ed5a4fSdan }
1820a6ed5a4fSdan 
18218e0b8e06Sdan /*
18228e0b8e06Sdan ** Allocate a new sqlite3expert object.
18238e0b8e06Sdan */
sqlite3_expert_new(sqlite3 * db,char ** pzErrmsg)18248e0b8e06Sdan sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
18258e0b8e06Sdan   int rc = SQLITE_OK;
18268e0b8e06Sdan   sqlite3expert *pNew;
18278e0b8e06Sdan 
18288e0b8e06Sdan   pNew = (sqlite3expert*)idxMalloc(&rc, sizeof(sqlite3expert));
18298e0b8e06Sdan 
18300824ccf2Sdan   /* Open two in-memory databases to work with. The "vtab database" (dbv)
18310824ccf2Sdan   ** will contain a virtual table corresponding to each real table in
18320824ccf2Sdan   ** the user database schema, and a copy of each view. It is used to
18330824ccf2Sdan   ** collect information regarding the WHERE, ORDER BY and other clauses
18340824ccf2Sdan   ** of the user's query.
18350824ccf2Sdan   */
18360824ccf2Sdan   if( rc==SQLITE_OK ){
18370824ccf2Sdan     pNew->db = db;
1838e53b4f97Sdan     pNew->iSample = 100;
18390824ccf2Sdan     rc = sqlite3_open(":memory:", &pNew->dbv);
18400824ccf2Sdan   }
18410824ccf2Sdan   if( rc==SQLITE_OK ){
18428e0b8e06Sdan     rc = sqlite3_open(":memory:", &pNew->dbm);
1843280db65eSdan     if( rc==SQLITE_OK ){
184436e31c69Sdrh       sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0);
18450824ccf2Sdan     }
1846280db65eSdan   }
1847280db65eSdan 
18488e0b8e06Sdan 
18498e0b8e06Sdan   /* Copy the entire schema of database [db] into [dbm]. */
18508e0b8e06Sdan   if( rc==SQLITE_OK ){
1851e0adf602Sdrh     sqlite3_stmt *pSql = 0;
18528e0b8e06Sdan     rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
1853067b92baSdrh         "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
1854138bd6dfSdrh         " AND sql NOT LIKE 'CREATE VIRTUAL %%'"
18558e0b8e06Sdan     );
18568e0b8e06Sdan     while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
18578e0b8e06Sdan       const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
1858e0adf602Sdrh       if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
18598e0b8e06Sdan     }
186065e67ed1Sdan     idxFinalize(&rc, pSql);
18618e0b8e06Sdan   }
18628e0b8e06Sdan 
18630824ccf2Sdan   /* Create the vtab schema */
18640824ccf2Sdan   if( rc==SQLITE_OK ){
18650824ccf2Sdan     rc = idxCreateVtabSchema(pNew, pzErrmsg);
18660824ccf2Sdan   }
18670824ccf2Sdan 
1868280db65eSdan   /* Register the auth callback with dbv */
1869280db65eSdan   if( rc==SQLITE_OK ){
1870280db65eSdan     sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew);
1871280db65eSdan   }
1872280db65eSdan 
18738e0b8e06Sdan   /* If an error has occurred, free the new object and reutrn NULL. Otherwise,
18748e0b8e06Sdan   ** return the new sqlite3expert handle.  */
18758e0b8e06Sdan   if( rc!=SQLITE_OK ){
18768e0b8e06Sdan     sqlite3_expert_destroy(pNew);
18778e0b8e06Sdan     pNew = 0;
18788e0b8e06Sdan   }
18798e0b8e06Sdan   return pNew;
18808e0b8e06Sdan }
18818e0b8e06Sdan 
18828e0b8e06Sdan /*
1883e53b4f97Sdan ** Configure an sqlite3expert object.
1884e53b4f97Sdan */
sqlite3_expert_config(sqlite3expert * p,int op,...)1885e53b4f97Sdan int sqlite3_expert_config(sqlite3expert *p, int op, ...){
1886e53b4f97Sdan   int rc = SQLITE_OK;
1887e53b4f97Sdan   va_list ap;
1888e53b4f97Sdan   va_start(ap, op);
1889e53b4f97Sdan   switch( op ){
1890e53b4f97Sdan     case EXPERT_CONFIG_SAMPLE: {
1891e53b4f97Sdan       int iVal = va_arg(ap, int);
1892e53b4f97Sdan       if( iVal<0 ) iVal = 0;
1893e53b4f97Sdan       if( iVal>100 ) iVal = 100;
1894e53b4f97Sdan       p->iSample = iVal;
1895e53b4f97Sdan       break;
1896e53b4f97Sdan     }
1897e53b4f97Sdan     default:
1898e53b4f97Sdan       rc = SQLITE_NOTFOUND;
1899e53b4f97Sdan       break;
1900e53b4f97Sdan   }
1901e53b4f97Sdan 
1902e53b4f97Sdan   va_end(ap);
1903e53b4f97Sdan   return rc;
1904e53b4f97Sdan }
1905e53b4f97Sdan 
1906e53b4f97Sdan /*
19078e0b8e06Sdan ** Add an SQL statement to the analysis.
19088e0b8e06Sdan */
sqlite3_expert_sql(sqlite3expert * p,const char * zSql,char ** pzErr)19098e0b8e06Sdan int sqlite3_expert_sql(
19108e0b8e06Sdan   sqlite3expert *p,               /* From sqlite3_expert_new() */
19118e0b8e06Sdan   const char *zSql,               /* SQL statement to add */
19128e0b8e06Sdan   char **pzErr                    /* OUT: Error message (if any) */
19138e0b8e06Sdan ){
19148e0b8e06Sdan   IdxScan *pScanOrig = p->pScan;
19158e0b8e06Sdan   IdxStatement *pStmtOrig = p->pStatement;
19168e0b8e06Sdan   int rc = SQLITE_OK;
19178e0b8e06Sdan   const char *zStmt = zSql;
19188e0b8e06Sdan 
19198e0b8e06Sdan   if( p->bRun ) return SQLITE_MISUSE;
19208e0b8e06Sdan 
19218e0b8e06Sdan   while( rc==SQLITE_OK && zStmt && zStmt[0] ){
19228e0b8e06Sdan     sqlite3_stmt *pStmt = 0;
19230824ccf2Sdan     rc = sqlite3_prepare_v2(p->dbv, zStmt, -1, &pStmt, &zStmt);
19248e0b8e06Sdan     if( rc==SQLITE_OK ){
19258e0b8e06Sdan       if( pStmt ){
19268e0b8e06Sdan         IdxStatement *pNew;
19278e0b8e06Sdan         const char *z = sqlite3_sql(pStmt);
1928bd0f1dbdSdrh         int n = STRLEN(z);
19298e0b8e06Sdan         pNew = (IdxStatement*)idxMalloc(&rc, sizeof(IdxStatement) + n+1);
19308e0b8e06Sdan         if( rc==SQLITE_OK ){
19318e0b8e06Sdan           pNew->zSql = (char*)&pNew[1];
19328e0b8e06Sdan           memcpy(pNew->zSql, z, n+1);
19338e0b8e06Sdan           pNew->pNext = p->pStatement;
19348e0b8e06Sdan           if( p->pStatement ) pNew->iId = p->pStatement->iId+1;
19358e0b8e06Sdan           p->pStatement = pNew;
19368e0b8e06Sdan         }
19378e0b8e06Sdan         sqlite3_finalize(pStmt);
19388e0b8e06Sdan       }
19398e0b8e06Sdan     }else{
1940280db65eSdan       idxDatabaseError(p->dbv, pzErr);
19418e0b8e06Sdan     }
19428e0b8e06Sdan   }
19438e0b8e06Sdan 
19448e0b8e06Sdan   if( rc!=SQLITE_OK ){
19458e0b8e06Sdan     idxScanFree(p->pScan, pScanOrig);
19468e0b8e06Sdan     idxStatementFree(p->pStatement, pStmtOrig);
19478e0b8e06Sdan     p->pScan = pScanOrig;
19488e0b8e06Sdan     p->pStatement = pStmtOrig;
19498e0b8e06Sdan   }
19508e0b8e06Sdan 
19518e0b8e06Sdan   return rc;
19528e0b8e06Sdan }
19538e0b8e06Sdan 
sqlite3_expert_analyze(sqlite3expert * p,char ** pzErr)19548e0b8e06Sdan int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr){
195596d43a05Sdan   int rc;
1956a4e61024Sdan   IdxHashEntry *pEntry;
19578e0b8e06Sdan 
1958a6ed5a4fSdan   /* Do trigger processing to collect any extra IdxScan structures */
1959280db65eSdan   rc = idxProcessTriggers(p, pzErr);
1960280db65eSdan 
19618e0b8e06Sdan   /* Create candidate indexes within the in-memory database file */
1962280db65eSdan   if( rc==SQLITE_OK ){
1963b9685185Sdrh     rc = idxCreateCandidates(p);
1964b565bee6Slarrybr   }else if ( rc==SQLITE_BUSY_TIMEOUT ){
1965b565bee6Slarrybr     if( pzErr )
1966b565bee6Slarrybr       *pzErr = sqlite3_mprintf("Cannot find a unique index name to propose.");
1967b565bee6Slarrybr     return rc;
1968280db65eSdan   }
19698e0b8e06Sdan 
1970a6ed5a4fSdan   /* Generate the stat1 data */
1971a6ed5a4fSdan   if( rc==SQLITE_OK ){
1972a6ed5a4fSdan     rc = idxPopulateStat1(p, pzErr);
1973a6ed5a4fSdan   }
1974a6ed5a4fSdan 
19750824ccf2Sdan   /* Formulate the EXPERT_REPORT_CANDIDATES text */
1976a4e61024Sdan   for(pEntry=p->hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
1977a6ed5a4fSdan     p->zCandidates = idxAppendText(&rc, p->zCandidates,
1978a6ed5a4fSdan         "%s;%s%s\n", pEntry->zVal,
1979a6ed5a4fSdan         pEntry->zVal2 ? " -- stat1: " : "", pEntry->zVal2
1980a6ed5a4fSdan     );
1981a4e61024Sdan   }
1982a4e61024Sdan 
19838e0b8e06Sdan   /* Figure out which of the candidate indexes are preferred by the query
19848e0b8e06Sdan   ** planner and report the results to the user.  */
19858e0b8e06Sdan   if( rc==SQLITE_OK ){
19868e0b8e06Sdan     rc = idxFindIndexes(p, pzErr);
19878e0b8e06Sdan   }
19888e0b8e06Sdan 
19898e0b8e06Sdan   if( rc==SQLITE_OK ){
19908e0b8e06Sdan     p->bRun = 1;
19918e0b8e06Sdan   }
19928e0b8e06Sdan   return rc;
19938e0b8e06Sdan }
19948e0b8e06Sdan 
1995cd84474eSdan /*
1996cd84474eSdan ** Return the total number of statements that have been added to this
1997cd84474eSdan ** sqlite3expert using sqlite3_expert_sql().
1998cd84474eSdan */
sqlite3_expert_count(sqlite3expert * p)19998e0b8e06Sdan int sqlite3_expert_count(sqlite3expert *p){
20008e0b8e06Sdan   int nRet = 0;
20018e0b8e06Sdan   if( p->pStatement ) nRet = p->pStatement->iId+1;
20028e0b8e06Sdan   return nRet;
20038e0b8e06Sdan }
20048e0b8e06Sdan 
2005cd84474eSdan /*
2006cd84474eSdan ** Return a component of the report.
2007cd84474eSdan */
sqlite3_expert_report(sqlite3expert * p,int iStmt,int eReport)20088e0b8e06Sdan const char *sqlite3_expert_report(sqlite3expert *p, int iStmt, int eReport){
20098e0b8e06Sdan   const char *zRet = 0;
20108e0b8e06Sdan   IdxStatement *pStmt;
20118e0b8e06Sdan 
20128e0b8e06Sdan   if( p->bRun==0 ) return 0;
20138e0b8e06Sdan   for(pStmt=p->pStatement; pStmt && pStmt->iId!=iStmt; pStmt=pStmt->pNext);
20148e0b8e06Sdan   switch( eReport ){
20158e0b8e06Sdan     case EXPERT_REPORT_SQL:
2016a4e61024Sdan       if( pStmt ) zRet = pStmt->zSql;
20178e0b8e06Sdan       break;
20188e0b8e06Sdan     case EXPERT_REPORT_INDEXES:
2019a4e61024Sdan       if( pStmt ) zRet = pStmt->zIdx;
20208e0b8e06Sdan       break;
20218e0b8e06Sdan     case EXPERT_REPORT_PLAN:
2022a4e61024Sdan       if( pStmt ) zRet = pStmt->zEQP;
20238e0b8e06Sdan       break;
2024a4e61024Sdan     case EXPERT_REPORT_CANDIDATES:
2025a4e61024Sdan       zRet = p->zCandidates;
2026a4e61024Sdan       break;
20278e0b8e06Sdan   }
20288e0b8e06Sdan   return zRet;
20298e0b8e06Sdan }
20308e0b8e06Sdan 
20318e0b8e06Sdan /*
20328e0b8e06Sdan ** Free an sqlite3expert object.
20338e0b8e06Sdan */
sqlite3_expert_destroy(sqlite3expert * p)20348e0b8e06Sdan void sqlite3_expert_destroy(sqlite3expert *p){
20350824ccf2Sdan   if( p ){
20368e0b8e06Sdan     sqlite3_close(p->dbm);
20370824ccf2Sdan     sqlite3_close(p->dbv);
20388e0b8e06Sdan     idxScanFree(p->pScan, 0);
20398e0b8e06Sdan     idxStatementFree(p->pStatement, 0);
204079610f5dSdan     idxTableFree(p->pTable);
2041280db65eSdan     idxWriteFree(p->pWrite);
2042cd84474eSdan     idxHashClear(&p->hIdx);
204379610f5dSdan     sqlite3_free(p->zCandidates);
20448e0b8e06Sdan     sqlite3_free(p);
20458e0b8e06Sdan   }
20460824ccf2Sdan }
2047f87ae41fSdan 
2048d48eafb9Sdan #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
2049