drh | 9f18e8a | 2005-07-08 12:13:04 +0000 | [diff] [blame] | 1 | /* |
| 2 | ** 2005 July 8 |
| 3 | ** |
| 4 | ** The author disclaims copyright to this source code. In place of |
| 5 | ** a legal notice, here is a blessing: |
| 6 | ** |
| 7 | ** May you do good and not evil. |
| 8 | ** May you find forgiveness for yourself and forgive others. |
| 9 | ** May you share freely, never taking more than you give. |
| 10 | ** |
| 11 | ************************************************************************* |
| 12 | ** This file contains code associated with the ANALYZE command. |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 13 | ** |
| 14 | ** The ANALYZE command gather statistics about the content of tables |
| 15 | ** and indices. These statistics are made available to the query planner |
| 16 | ** to help it make better decisions about how to perform queries. |
| 17 | ** |
| 18 | ** The following system tables are or have been supported: |
| 19 | ** |
| 20 | ** CREATE TABLE sqlite_stat1(tbl, idx, stat); |
| 21 | ** CREATE TABLE sqlite_stat2(tbl, idx, sampleno, sample); |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 22 | ** CREATE TABLE sqlite_stat3(tbl, idx, nEq, nLt, nDLt, sample); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 23 | ** |
| 24 | ** Additional tables might be added in future releases of SQLite. |
| 25 | ** The sqlite_stat2 table is not created or used unless the SQLite version |
drh | d3ed734 | 2011-09-21 00:09:41 +0000 | [diff] [blame] | 26 | ** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 27 | ** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated. |
| 28 | ** The sqlite_stat2 table is superceded by sqlite_stat3, which is only |
drh | d3ed734 | 2011-09-21 00:09:41 +0000 | [diff] [blame] | 29 | ** created and used by SQLite versions 3.7.9 and later and with |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 30 | ** SQLITE_ENABLE_STAT3 defined. The fucntionality of sqlite_stat3 |
| 31 | ** is a superset of sqlite_stat2. |
| 32 | ** |
| 33 | ** Format of sqlite_stat1: |
| 34 | ** |
| 35 | ** There is normally one row per index, with the index identified by the |
| 36 | ** name in the idx column. The tbl column is the name of the table to |
| 37 | ** which the index belongs. In each such row, the stat column will be |
| 38 | ** a string consisting of a list of integers. The first integer in this |
| 39 | ** list is the number of rows in the index and in the table. The second |
| 40 | ** integer is the average number of rows in the index that have the same |
| 41 | ** value in the first column of the index. The third integer is the average |
| 42 | ** number of rows in the index that have the same value for the first two |
| 43 | ** columns. The N-th integer (for N>1) is the average number of rows in |
| 44 | ** the index which have the same value for the first N-1 columns. For |
| 45 | ** a K-column index, there will be K+1 integers in the stat column. If |
| 46 | ** the index is unique, then the last integer will be 1. |
| 47 | ** |
| 48 | ** The list of integers in the stat column can optionally be followed |
| 49 | ** by the keyword "unordered". The "unordered" keyword, if it is present, |
| 50 | ** must be separated from the last integer by a single space. If the |
| 51 | ** "unordered" keyword is present, then the query planner assumes that |
| 52 | ** the index is unordered and will not use the index for a range query. |
| 53 | ** |
| 54 | ** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat |
| 55 | ** column contains a single integer which is the (estimated) number of |
| 56 | ** rows in the table identified by sqlite_stat1.tbl. |
| 57 | ** |
| 58 | ** Format of sqlite_stat2: |
| 59 | ** |
| 60 | ** The sqlite_stat2 is only created and is only used if SQLite is compiled |
| 61 | ** with SQLITE_ENABLE_STAT2 and if the SQLite version number is between |
drh | d3ed734 | 2011-09-21 00:09:41 +0000 | [diff] [blame] | 62 | ** 3.6.18 and 3.7.8. The "stat2" table contains additional information |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 63 | ** about the distribution of keys within an index. The index is identified by |
| 64 | ** the "idx" column and the "tbl" column is the name of the table to which |
| 65 | ** the index belongs. There are usually 10 rows in the sqlite_stat2 |
| 66 | ** table for each index. |
| 67 | ** |
dan | 23e7c4d | 2011-08-15 12:02:21 +0000 | [diff] [blame] | 68 | ** The sqlite_stat2 entries for an index that have sampleno between 0 and 9 |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 69 | ** inclusive are samples of the left-most key value in the index taken at |
| 70 | ** evenly spaced points along the index. Let the number of samples be S |
| 71 | ** (10 in the standard build) and let C be the number of rows in the index. |
| 72 | ** Then the sampled rows are given by: |
| 73 | ** |
| 74 | ** rownumber = (i*C*2 + C)/(S*2) |
| 75 | ** |
| 76 | ** For i between 0 and S-1. Conceptually, the index space is divided into |
| 77 | ** S uniform buckets and the samples are the middle row from each bucket. |
| 78 | ** |
| 79 | ** The format for sqlite_stat2 is recorded here for legacy reference. This |
| 80 | ** version of SQLite does not support sqlite_stat2. It neither reads nor |
| 81 | ** writes the sqlite_stat2 table. This version of SQLite only supports |
| 82 | ** sqlite_stat3. |
| 83 | ** |
| 84 | ** Format for sqlite_stat3: |
| 85 | ** |
| 86 | ** The sqlite_stat3 is an enhancement to sqlite_stat2. A new name is |
| 87 | ** used to avoid compatibility problems. |
| 88 | ** |
drh | d3ed734 | 2011-09-21 00:09:41 +0000 | [diff] [blame] | 89 | ** The format of the sqlite_stat3 table is similar to the format of |
| 90 | ** the sqlite_stat2 table. There are multiple entries for each index. |
| 91 | ** The idx column names the index and the tbl column is the table of the |
| 92 | ** index. If the idx and tbl columns are the same, then the sample is |
| 93 | ** of the INTEGER PRIMARY KEY. The sample column is a value taken from |
| 94 | ** the left-most column of the index. The nEq column is the approximate |
| 95 | ** number of entires in the index whose left-most column exactly matches |
| 96 | ** the sample. nLt is the approximate number of entires whose left-most |
drh | 3699801 | 2011-09-23 13:25:03 +0000 | [diff] [blame] | 97 | ** column is less than the sample. The nDLt column is the approximate |
drh | d3ed734 | 2011-09-21 00:09:41 +0000 | [diff] [blame] | 98 | ** number of distinct left-most entries in the index that are less than |
drh | 3699801 | 2011-09-23 13:25:03 +0000 | [diff] [blame] | 99 | ** the sample. |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 100 | ** |
drh | d3ed734 | 2011-09-21 00:09:41 +0000 | [diff] [blame] | 101 | ** Future versions of SQLite might change to store a string containing |
| 102 | ** multiple integers values in the nDLt column of sqlite_stat3. The first |
| 103 | ** integer will be the number of prior index entires that are distinct in |
| 104 | ** the left-most column. The second integer will be the number of prior index |
| 105 | ** entries that are distinct in the first two columns. The third integer |
| 106 | ** will be the number of prior index entries that are distinct in the first |
| 107 | ** three columns. And so forth. With that extension, the nDLt field is |
| 108 | ** similar in function to the sqlite_stat1.stat field. |
| 109 | ** |
| 110 | ** There can be an arbitrary number of sqlite_stat3 entries per index. |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 111 | ** The ANALYZE command will typically generate sqlite_stat3 tables |
| 112 | ** that contain between 10 and 40 samples which are distributed across |
| 113 | ** the key space, though not uniformly, and which include samples with |
| 114 | ** largest possible nEq values. |
drh | 9f18e8a | 2005-07-08 12:13:04 +0000 | [diff] [blame] | 115 | */ |
| 116 | #ifndef SQLITE_OMIT_ANALYZE |
| 117 | #include "sqliteInt.h" |
| 118 | |
| 119 | /* |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 120 | ** This routine generates code that opens the sqlite_stat1 table for |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 121 | ** writing with cursor iStatCur. If the library was built with the |
drh | 74e7c8f | 2011-10-21 19:06:32 +0000 | [diff] [blame] | 122 | ** SQLITE_ENABLE_STAT3 macro defined, then the sqlite_stat3 table is |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 123 | ** opened for writing using cursor (iStatCur+1) |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 124 | ** |
| 125 | ** If the sqlite_stat1 tables does not previously exist, it is created. |
drh | 74e7c8f | 2011-10-21 19:06:32 +0000 | [diff] [blame] | 126 | ** Similarly, if the sqlite_stat3 table does not exist and the library |
| 127 | ** is compiled with SQLITE_ENABLE_STAT3 defined, it is created. |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 128 | ** |
| 129 | ** Argument zWhere may be a pointer to a buffer containing a table name, |
| 130 | ** or it may be a NULL pointer. If it is not NULL, then all entries in |
drh | 74e7c8f | 2011-10-21 19:06:32 +0000 | [diff] [blame] | 131 | ** the sqlite_stat1 and (if applicable) sqlite_stat3 tables associated |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 132 | ** with the named table are deleted. If zWhere==0, then code is generated |
| 133 | ** to delete all stat table entries. |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 134 | */ |
| 135 | static void openStatTable( |
| 136 | Parse *pParse, /* Parsing context */ |
| 137 | int iDb, /* The database we are looking in */ |
| 138 | int iStatCur, /* Open the sqlite_stat1 table on this cursor */ |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 139 | const char *zWhere, /* Delete entries for this table or index */ |
| 140 | const char *zWhereType /* Either "tbl" or "idx" */ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 141 | ){ |
dan | 558814f | 2010-06-02 05:53:53 +0000 | [diff] [blame] | 142 | static const struct { |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 143 | const char *zName; |
| 144 | const char *zCols; |
| 145 | } aTable[] = { |
| 146 | { "sqlite_stat1", "tbl,idx,stat" }, |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 147 | #ifdef SQLITE_ENABLE_STAT3 |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 148 | { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" }, |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 149 | #endif |
| 150 | }; |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 151 | |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 152 | int aRoot[] = {0, 0}; |
shane | cea72b2 | 2009-09-07 04:38:36 +0000 | [diff] [blame] | 153 | u8 aCreateTbl[] = {0, 0}; |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 154 | |
| 155 | int i; |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 156 | sqlite3 *db = pParse->db; |
| 157 | Db *pDb; |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 158 | Vdbe *v = sqlite3GetVdbe(pParse); |
drh | cf1be45 | 2007-05-12 12:08:51 +0000 | [diff] [blame] | 159 | if( v==0 ) return; |
drh | 1fee73e | 2007-08-29 04:00:57 +0000 | [diff] [blame] | 160 | assert( sqlite3BtreeHoldsAllMutexes(db) ); |
| 161 | assert( sqlite3VdbeDb(v)==db ); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 162 | pDb = &db->aDb[iDb]; |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 163 | |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 164 | /* Create new statistic tables if they do not exist, or clear them |
| 165 | ** if they do already exist. |
| 166 | */ |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 167 | for(i=0; i<ArraySize(aTable); i++){ |
| 168 | const char *zTab = aTable[i].zName; |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 169 | Table *pStat; |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 170 | if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){ |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 171 | /* The sqlite_stat[12] table does not exist. Create it. Note that a |
| 172 | ** side-effect of the CREATE TABLE statement is to leave the rootpage |
| 173 | ** of the new table in register pParse->regRoot. This is important |
| 174 | ** because the OpenWrite opcode below will be needing it. */ |
| 175 | sqlite3NestedParse(pParse, |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 176 | "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 177 | ); |
| 178 | aRoot[i] = pParse->regRoot; |
| 179 | aCreateTbl[i] = 1; |
| 180 | }else{ |
| 181 | /* The table already exists. If zWhere is not NULL, delete all entries |
| 182 | ** associated with the table zWhere. If zWhere is NULL, delete the |
| 183 | ** entire contents of the table. */ |
| 184 | aRoot[i] = pStat->tnum; |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 185 | sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 186 | if( zWhere ){ |
| 187 | sqlite3NestedParse(pParse, |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 188 | "DELETE FROM %Q.%s WHERE %s=%Q", pDb->zName, zTab, zWhereType, zWhere |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 189 | ); |
| 190 | }else{ |
| 191 | /* The sqlite_stat[12] table already exists. Delete all rows. */ |
| 192 | sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); |
| 193 | } |
| 194 | } |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 195 | } |
| 196 | |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 197 | /* Open the sqlite_stat[13] tables for writing. */ |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 198 | for(i=0; i<ArraySize(aTable); i++){ |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 199 | sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb); |
| 200 | sqlite3VdbeChangeP4(v, -1, (char *)3, P4_INT32); |
| 201 | sqlite3VdbeChangeP5(v, aCreateTbl[i]); |
danielk1977 | c00da10 | 2006-01-07 13:21:04 +0000 | [diff] [blame] | 202 | } |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | /* |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 206 | ** Recommended number of samples for sqlite_stat3 |
| 207 | */ |
| 208 | #ifndef SQLITE_STAT3_SAMPLES |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 209 | # define SQLITE_STAT3_SAMPLES 24 |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 210 | #endif |
| 211 | |
| 212 | /* |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 213 | ** Three SQL functions - stat3_init(), stat3_push(), and stat3_pop() - |
| 214 | ** share an instance of the following structure to hold their state |
| 215 | ** information. |
| 216 | */ |
| 217 | typedef struct Stat3Accum Stat3Accum; |
| 218 | struct Stat3Accum { |
| 219 | tRowcnt nRow; /* Number of rows in the entire table */ |
| 220 | tRowcnt nPSample; /* How often to do a periodic sample */ |
| 221 | int iMin; /* Index of entry with minimum nEq and hash */ |
| 222 | int mxSample; /* Maximum number of samples to accumulate */ |
| 223 | int nSample; /* Current number of samples */ |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 224 | u32 iPrn; /* Pseudo-random number used for sampling */ |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 225 | struct Stat3Sample { |
| 226 | i64 iRowid; /* Rowid in main table of the key */ |
| 227 | tRowcnt nEq; /* sqlite_stat3.nEq */ |
| 228 | tRowcnt nLt; /* sqlite_stat3.nLt */ |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 229 | tRowcnt nDLt; /* sqlite_stat3.nDLt */ |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 230 | u8 isPSample; /* True if a periodic sample */ |
| 231 | u32 iHash; /* Tiebreaker hash */ |
| 232 | } *a; /* An array of samples */ |
| 233 | }; |
| 234 | |
| 235 | #ifdef SQLITE_ENABLE_STAT3 |
| 236 | /* |
| 237 | ** Implementation of the stat3_init(C,S) SQL function. The two parameters |
| 238 | ** are the number of rows in the table or index (C) and the number of samples |
| 239 | ** to accumulate (S). |
| 240 | ** |
| 241 | ** This routine allocates the Stat3Accum object. |
| 242 | ** |
| 243 | ** The return value is the Stat3Accum object (P). |
| 244 | */ |
| 245 | static void stat3Init( |
| 246 | sqlite3_context *context, |
| 247 | int argc, |
| 248 | sqlite3_value **argv |
| 249 | ){ |
| 250 | Stat3Accum *p; |
| 251 | tRowcnt nRow; |
| 252 | int mxSample; |
| 253 | int n; |
| 254 | |
drh | 6825719 | 2011-08-16 17:06:21 +0000 | [diff] [blame] | 255 | UNUSED_PARAMETER(argc); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 256 | nRow = (tRowcnt)sqlite3_value_int64(argv[0]); |
| 257 | mxSample = sqlite3_value_int(argv[1]); |
| 258 | n = sizeof(*p) + sizeof(p->a[0])*mxSample; |
| 259 | p = sqlite3_malloc( n ); |
| 260 | if( p==0 ){ |
| 261 | sqlite3_result_error_nomem(context); |
| 262 | return; |
| 263 | } |
| 264 | memset(p, 0, n); |
| 265 | p->a = (struct Stat3Sample*)&p[1]; |
| 266 | p->nRow = nRow; |
| 267 | p->mxSample = mxSample; |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 268 | p->nPSample = p->nRow/(mxSample/3+1) + 1; |
| 269 | sqlite3_randomness(sizeof(p->iPrn), &p->iPrn); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 270 | sqlite3_result_blob(context, p, sizeof(p), sqlite3_free); |
| 271 | } |
| 272 | static const FuncDef stat3InitFuncdef = { |
| 273 | 2, /* nArg */ |
| 274 | SQLITE_UTF8, /* iPrefEnc */ |
| 275 | 0, /* flags */ |
| 276 | 0, /* pUserData */ |
| 277 | 0, /* pNext */ |
| 278 | stat3Init, /* xFunc */ |
| 279 | 0, /* xStep */ |
| 280 | 0, /* xFinalize */ |
| 281 | "stat3_init", /* zName */ |
| 282 | 0, /* pHash */ |
| 283 | 0 /* pDestructor */ |
| 284 | }; |
| 285 | |
| 286 | |
| 287 | /* |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 288 | ** Implementation of the stat3_push(nEq,nLt,nDLt,rowid,P) SQL function. The |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 289 | ** arguments describe a single key instance. This routine makes the |
| 290 | ** decision about whether or not to retain this key for the sqlite_stat3 |
| 291 | ** table. |
| 292 | ** |
| 293 | ** The return value is NULL. |
| 294 | */ |
| 295 | static void stat3Push( |
| 296 | sqlite3_context *context, |
| 297 | int argc, |
| 298 | sqlite3_value **argv |
| 299 | ){ |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 300 | Stat3Accum *p = (Stat3Accum*)sqlite3_value_blob(argv[4]); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 301 | tRowcnt nEq = sqlite3_value_int64(argv[0]); |
| 302 | tRowcnt nLt = sqlite3_value_int64(argv[1]); |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 303 | tRowcnt nDLt = sqlite3_value_int64(argv[2]); |
| 304 | i64 rowid = sqlite3_value_int64(argv[3]); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 305 | u8 isPSample = 0; |
| 306 | u8 doInsert = 0; |
| 307 | int iMin = p->iMin; |
| 308 | struct Stat3Sample *pSample; |
| 309 | int i; |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 310 | u32 h; |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 311 | |
drh | 6825719 | 2011-08-16 17:06:21 +0000 | [diff] [blame] | 312 | UNUSED_PARAMETER(context); |
| 313 | UNUSED_PARAMETER(argc); |
| 314 | if( nEq==0 ) return; |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 315 | h = p->iPrn = p->iPrn*1103515245 + 12345; |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 316 | if( (nLt/p->nPSample)!=((nEq+nLt)/p->nPSample) ){ |
| 317 | doInsert = isPSample = 1; |
| 318 | }else if( p->nSample<p->mxSample ){ |
| 319 | doInsert = 1; |
| 320 | }else{ |
| 321 | if( nEq>p->a[iMin].nEq || (nEq==p->a[iMin].nEq && h>p->a[iMin].iHash) ){ |
| 322 | doInsert = 1; |
| 323 | } |
| 324 | } |
| 325 | if( !doInsert ) return; |
| 326 | if( p->nSample==p->mxSample ){ |
drh | 5c62486 | 2011-09-22 18:46:34 +0000 | [diff] [blame] | 327 | assert( p->nSample - iMin - 1 >= 0 ); |
| 328 | memmove(&p->a[iMin], &p->a[iMin+1], sizeof(p->a[0])*(p->nSample-iMin-1)); |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 329 | pSample = &p->a[p->nSample-1]; |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 330 | }else{ |
| 331 | pSample = &p->a[p->nSample++]; |
| 332 | } |
| 333 | pSample->iRowid = rowid; |
| 334 | pSample->nEq = nEq; |
| 335 | pSample->nLt = nLt; |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 336 | pSample->nDLt = nDLt; |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 337 | pSample->iHash = h; |
| 338 | pSample->isPSample = isPSample; |
| 339 | |
| 340 | /* Find the new minimum */ |
| 341 | if( p->nSample==p->mxSample ){ |
| 342 | pSample = p->a; |
| 343 | i = 0; |
| 344 | while( pSample->isPSample ){ |
| 345 | i++; |
| 346 | pSample++; |
| 347 | assert( i<p->nSample ); |
| 348 | } |
| 349 | nEq = pSample->nEq; |
| 350 | h = pSample->iHash; |
| 351 | iMin = i; |
| 352 | for(i++, pSample++; i<p->nSample; i++, pSample++){ |
| 353 | if( pSample->isPSample ) continue; |
| 354 | if( pSample->nEq<nEq |
| 355 | || (pSample->nEq==nEq && pSample->iHash<h) |
| 356 | ){ |
| 357 | iMin = i; |
| 358 | nEq = pSample->nEq; |
| 359 | h = pSample->iHash; |
| 360 | } |
| 361 | } |
| 362 | p->iMin = iMin; |
| 363 | } |
| 364 | } |
| 365 | static const FuncDef stat3PushFuncdef = { |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 366 | 5, /* nArg */ |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 367 | SQLITE_UTF8, /* iPrefEnc */ |
| 368 | 0, /* flags */ |
| 369 | 0, /* pUserData */ |
| 370 | 0, /* pNext */ |
| 371 | stat3Push, /* xFunc */ |
| 372 | 0, /* xStep */ |
| 373 | 0, /* xFinalize */ |
| 374 | "stat3_push", /* zName */ |
| 375 | 0, /* pHash */ |
| 376 | 0 /* pDestructor */ |
| 377 | }; |
| 378 | |
| 379 | /* |
| 380 | ** Implementation of the stat3_get(P,N,...) SQL function. This routine is |
| 381 | ** used to query the results. Content is returned for the Nth sqlite_stat3 |
| 382 | ** row where N is between 0 and S-1 and S is the number of samples. The |
| 383 | ** value returned depends on the number of arguments. |
| 384 | ** |
| 385 | ** argc==2 result: rowid |
| 386 | ** argc==3 result: nEq |
| 387 | ** argc==4 result: nLt |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 388 | ** argc==5 result: nDLt |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 389 | */ |
| 390 | static void stat3Get( |
| 391 | sqlite3_context *context, |
| 392 | int argc, |
| 393 | sqlite3_value **argv |
| 394 | ){ |
| 395 | int n = sqlite3_value_int(argv[1]); |
| 396 | Stat3Accum *p = (Stat3Accum*)sqlite3_value_blob(argv[0]); |
| 397 | |
| 398 | assert( p!=0 ); |
| 399 | if( p->nSample<=n ) return; |
| 400 | switch( argc ){ |
drh | 5c62486 | 2011-09-22 18:46:34 +0000 | [diff] [blame] | 401 | case 2: sqlite3_result_int64(context, p->a[n].iRowid); break; |
| 402 | case 3: sqlite3_result_int64(context, p->a[n].nEq); break; |
| 403 | case 4: sqlite3_result_int64(context, p->a[n].nLt); break; |
| 404 | default: sqlite3_result_int64(context, p->a[n].nDLt); break; |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 405 | } |
| 406 | } |
| 407 | static const FuncDef stat3GetFuncdef = { |
| 408 | -1, /* nArg */ |
| 409 | SQLITE_UTF8, /* iPrefEnc */ |
| 410 | 0, /* flags */ |
| 411 | 0, /* pUserData */ |
| 412 | 0, /* pNext */ |
| 413 | stat3Get, /* xFunc */ |
| 414 | 0, /* xStep */ |
| 415 | 0, /* xFinalize */ |
| 416 | "stat3_get", /* zName */ |
| 417 | 0, /* pHash */ |
| 418 | 0 /* pDestructor */ |
| 419 | }; |
| 420 | #endif /* SQLITE_ENABLE_STAT3 */ |
| 421 | |
| 422 | |
| 423 | |
| 424 | |
| 425 | /* |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 426 | ** Generate code to do an analysis of all indices associated with |
| 427 | ** a single table. |
| 428 | */ |
| 429 | static void analyzeOneTable( |
| 430 | Parse *pParse, /* Parser context */ |
| 431 | Table *pTab, /* Table whose indices are to be analyzed */ |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 432 | Index *pOnlyIdx, /* If not NULL, only analyze this one index */ |
drh | dfe88ec | 2008-11-03 20:55:06 +0000 | [diff] [blame] | 433 | int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 434 | int iMem /* Available memory locations begin here */ |
| 435 | ){ |
dan | 0f9a34e | 2009-08-19 16:34:31 +0000 | [diff] [blame] | 436 | sqlite3 *db = pParse->db; /* Database handle */ |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 437 | Index *pIdx; /* An index to being analyzed */ |
| 438 | int iIdxCur; /* Cursor open on index being analyzed */ |
| 439 | Vdbe *v; /* The virtual machine being built up */ |
| 440 | int i; /* Loop counter */ |
| 441 | int topOfLoop; /* The top of the loop */ |
| 442 | int endOfLoop; /* The end of the loop */ |
drh | f6cf1ff | 2011-03-30 14:54:05 +0000 | [diff] [blame] | 443 | int jZeroRows = -1; /* Jump from here if number of rows is zero */ |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 444 | int iDb; /* Index of database containing pTab */ |
dan | e275dc3 | 2009-08-18 16:24:58 +0000 | [diff] [blame] | 445 | int regTabname = iMem++; /* Register containing table name */ |
| 446 | int regIdxname = iMem++; /* Register containing index name */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 447 | int regStat1 = iMem++; /* The stat column of sqlite_stat1 */ |
| 448 | #ifdef SQLITE_ENABLE_STAT3 |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 449 | int regNumEq = regStat1; /* Number of instances. Same as regStat1 */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 450 | int regNumLt = iMem++; /* Number of keys less than regSample */ |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 451 | int regNumDLt = iMem++; /* Number of distinct keys less than regSample */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 452 | int regSample = iMem++; /* The next sample value */ |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 453 | int regRowid = regSample; /* Rowid of a sample */ |
| 454 | int regAccum = iMem++; /* Register to hold Stat3Accum object */ |
| 455 | int regLoop = iMem++; /* Loop counter */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 456 | int regCount = iMem++; /* Number of rows in the table or index */ |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 457 | int regTemp1 = iMem++; /* Intermediate register */ |
| 458 | int regTemp2 = iMem++; /* Intermediate register */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 459 | int once = 1; /* One-time initialization */ |
| 460 | int shortJump = 0; /* Instruction address */ |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 461 | int iTabCur = pParse->nTab++; /* Table cursor */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 462 | #endif |
| 463 | int regCol = iMem++; /* Content of a column in analyzed table */ |
dan | e275dc3 | 2009-08-18 16:24:58 +0000 | [diff] [blame] | 464 | int regRec = iMem++; /* Register holding completed record */ |
| 465 | int regTemp = iMem++; /* Temporary use register */ |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 466 | int regNewRowid = iMem++; /* Rowid for the inserted record */ |
dan | 68c4dbb | 2009-08-20 09:11:06 +0000 | [diff] [blame] | 467 | |
dan | e275dc3 | 2009-08-18 16:24:58 +0000 | [diff] [blame] | 468 | |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 469 | v = sqlite3GetVdbe(pParse); |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 470 | if( v==0 || NEVER(pTab==0) ){ |
| 471 | return; |
| 472 | } |
drh | f39d29c | 2010-09-28 17:34:46 +0000 | [diff] [blame] | 473 | if( pTab->tnum==0 ){ |
| 474 | /* Do not gather statistics on views or virtual tables */ |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 475 | return; |
| 476 | } |
| 477 | if( memcmp(pTab->zName, "sqlite_", 7)==0 ){ |
| 478 | /* Do not gather statistics on system tables */ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 479 | return; |
| 480 | } |
dan | 0f9a34e | 2009-08-19 16:34:31 +0000 | [diff] [blame] | 481 | assert( sqlite3BtreeHoldsAllMutexes(db) ); |
| 482 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
danielk1977 | da18423 | 2006-01-05 11:34:32 +0000 | [diff] [blame] | 483 | assert( iDb>=0 ); |
drh | 2120608 | 2011-04-04 18:22:02 +0000 | [diff] [blame] | 484 | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
drh | e6e0496 | 2005-07-23 02:17:03 +0000 | [diff] [blame] | 485 | #ifndef SQLITE_OMIT_AUTHORIZATION |
| 486 | if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, |
dan | 0f9a34e | 2009-08-19 16:34:31 +0000 | [diff] [blame] | 487 | db->aDb[iDb].zName ) ){ |
drh | e6e0496 | 2005-07-23 02:17:03 +0000 | [diff] [blame] | 488 | return; |
| 489 | } |
| 490 | #endif |
| 491 | |
danielk1977 | c00da10 | 2006-01-07 13:21:04 +0000 | [diff] [blame] | 492 | /* Establish a read-lock on the table at the shared-cache level. */ |
| 493 | sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); |
| 494 | |
danielk1977 | 6ab3a2e | 2009-02-19 14:39:25 +0000 | [diff] [blame] | 495 | iIdxCur = pParse->nTab++; |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 496 | sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 497 | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 498 | int nCol; |
| 499 | KeyInfo *pKey; |
drh | 6825719 | 2011-08-16 17:06:21 +0000 | [diff] [blame] | 500 | int addrIfNot = 0; /* address of OP_IfNot */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 501 | int *aChngAddr; /* Array of jump instruction addresses */ |
danielk1977 | b3bf556 | 2006-01-10 17:58:23 +0000 | [diff] [blame] | 502 | |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 503 | if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 504 | VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName)); |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 505 | nCol = pIdx->nColumn; |
drh | 88ab5b0 | 2011-08-18 01:10:35 +0000 | [diff] [blame] | 506 | aChngAddr = sqlite3DbMallocRaw(db, sizeof(int)*nCol); |
| 507 | if( aChngAddr==0 ) continue; |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 508 | pKey = sqlite3IndexKeyinfo(pParse, pIdx); |
dan | e275dc3 | 2009-08-18 16:24:58 +0000 | [diff] [blame] | 509 | if( iMem+1+(nCol*2)>pParse->nMem ){ |
| 510 | pParse->nMem = iMem+1+(nCol*2); |
| 511 | } |
| 512 | |
| 513 | /* Open a cursor to the index to be analyzed. */ |
dan | 0f9a34e | 2009-08-19 16:34:31 +0000 | [diff] [blame] | 514 | assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); |
danielk1977 | 207872a | 2008-01-03 07:54:23 +0000 | [diff] [blame] | 515 | sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb, |
drh | 66a5167 | 2008-01-03 00:01:23 +0000 | [diff] [blame] | 516 | (char *)pKey, P4_KEYINFO_HANDOFF); |
danielk1977 | 207872a | 2008-01-03 07:54:23 +0000 | [diff] [blame] | 517 | VdbeComment((v, "%s", pIdx->zName)); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 518 | |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 519 | /* Populate the register containing the index name. */ |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 520 | sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0); |
| 521 | |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 522 | #ifdef SQLITE_ENABLE_STAT3 |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 523 | if( once ){ |
| 524 | once = 0; |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 525 | sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 526 | } |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 527 | sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regCount); |
| 528 | sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_STAT3_SAMPLES, regTemp1); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 529 | sqlite3VdbeAddOp2(v, OP_Integer, 0, regNumEq); |
| 530 | sqlite3VdbeAddOp2(v, OP_Integer, 0, regNumLt); |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 531 | sqlite3VdbeAddOp2(v, OP_Integer, -1, regNumDLt); |
drh | e752cda | 2011-12-11 02:30:35 +0000 | [diff] [blame] | 532 | sqlite3VdbeAddOp3(v, OP_Null, 0, regSample, regAccum); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 533 | sqlite3VdbeAddOp4(v, OP_Function, 1, regCount, regAccum, |
| 534 | (char*)&stat3InitFuncdef, P4_FUNCDEF); |
| 535 | sqlite3VdbeChangeP5(v, 2); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 536 | #endif /* SQLITE_ENABLE_STAT3 */ |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 537 | |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 538 | /* The block of memory cells initialized here is used as follows. |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 539 | ** |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 540 | ** iMem: |
| 541 | ** The total number of rows in the table. |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 542 | ** |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 543 | ** iMem+1 .. iMem+nCol: |
| 544 | ** Number of distinct entries in index considering the |
| 545 | ** left-most N columns only, where N is between 1 and nCol, |
| 546 | ** inclusive. |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 547 | ** |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 548 | ** iMem+nCol+1 .. Mem+2*nCol: |
| 549 | ** Previous value of indexed columns, from left to right. |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 550 | ** |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 551 | ** Cells iMem through iMem+nCol are initialized to 0. The others are |
| 552 | ** initialized to contain an SQL NULL. |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 553 | */ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 554 | for(i=0; i<=nCol; i++){ |
drh | 4c58312 | 2008-01-04 22:01:03 +0000 | [diff] [blame] | 555 | sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem+i); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 556 | } |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 557 | for(i=0; i<nCol; i++){ |
drh | 4c58312 | 2008-01-04 22:01:03 +0000 | [diff] [blame] | 558 | sqlite3VdbeAddOp2(v, OP_Null, 0, iMem+nCol+i+1); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 559 | } |
| 560 | |
dan | e275dc3 | 2009-08-18 16:24:58 +0000 | [diff] [blame] | 561 | /* Start the analysis loop. This loop runs through all the entries in |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 562 | ** the index b-tree. */ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 563 | endOfLoop = sqlite3VdbeMakeLabel(v); |
drh | 66a5167 | 2008-01-03 00:01:23 +0000 | [diff] [blame] | 564 | sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop); |
drh | e6e0496 | 2005-07-23 02:17:03 +0000 | [diff] [blame] | 565 | topOfLoop = sqlite3VdbeCurrentAddr(v); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 566 | sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1); /* Increment row counter */ |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 567 | |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 568 | for(i=0; i<nCol; i++){ |
drh | 4856698 | 2011-01-04 19:01:26 +0000 | [diff] [blame] | 569 | CollSeq *pColl; |
drh | 2d401ab | 2008-01-10 23:50:11 +0000 | [diff] [blame] | 570 | sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol); |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 571 | if( i==0 ){ |
drh | 8e93b10 | 2011-01-04 17:57:53 +0000 | [diff] [blame] | 572 | /* Always record the very first row */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 573 | addrIfNot = sqlite3VdbeAddOp1(v, OP_IfNot, iMem+1); |
drh | 8e93b10 | 2011-01-04 17:57:53 +0000 | [diff] [blame] | 574 | } |
drh | 4856698 | 2011-01-04 19:01:26 +0000 | [diff] [blame] | 575 | assert( pIdx->azColl!=0 ); |
| 576 | assert( pIdx->azColl[i]!=0 ); |
| 577 | pColl = sqlite3LocateCollSeq(pParse, pIdx->azColl[i]); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 578 | aChngAddr[i] = sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem+nCol+i+1, |
| 579 | (char*)pColl, P4_COLLSEQ); |
drh | 8e93b10 | 2011-01-04 17:57:53 +0000 | [diff] [blame] | 580 | sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 581 | VdbeComment((v, "jump if column %d changed", i)); |
| 582 | #ifdef SQLITE_ENABLE_STAT3 |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 583 | if( i==0 ){ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 584 | sqlite3VdbeAddOp2(v, OP_AddImm, regNumEq, 1); |
| 585 | VdbeComment((v, "incr repeat count")); |
| 586 | } |
| 587 | #endif |
dan | 0f9a34e | 2009-08-19 16:34:31 +0000 | [diff] [blame] | 588 | } |
drh | 66a5167 | 2008-01-03 00:01:23 +0000 | [diff] [blame] | 589 | sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 590 | for(i=0; i<nCol; i++){ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 591 | sqlite3VdbeJumpHere(v, aChngAddr[i]); /* Set jump dest for the OP_Ne */ |
drh | 8e93b10 | 2011-01-04 17:57:53 +0000 | [diff] [blame] | 592 | if( i==0 ){ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 593 | sqlite3VdbeJumpHere(v, addrIfNot); /* Jump dest for OP_IfNot */ |
| 594 | #ifdef SQLITE_ENABLE_STAT3 |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 595 | sqlite3VdbeAddOp4(v, OP_Function, 1, regNumEq, regTemp2, |
| 596 | (char*)&stat3PushFuncdef, P4_FUNCDEF); |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 597 | sqlite3VdbeChangeP5(v, 5); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 598 | sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, pIdx->nColumn, regRowid); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 599 | sqlite3VdbeAddOp3(v, OP_Add, regNumEq, regNumLt, regNumLt); |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 600 | sqlite3VdbeAddOp2(v, OP_AddImm, regNumDLt, 1); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 601 | sqlite3VdbeAddOp2(v, OP_Integer, 1, regNumEq); |
| 602 | #endif |
drh | 8e93b10 | 2011-01-04 17:57:53 +0000 | [diff] [blame] | 603 | } |
drh | 2d401ab | 2008-01-10 23:50:11 +0000 | [diff] [blame] | 604 | sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1); |
drh | b1fdb2a | 2008-01-05 04:06:03 +0000 | [diff] [blame] | 605 | sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 606 | } |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 607 | sqlite3DbFree(db, aChngAddr); |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 608 | |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 609 | /* Always jump here after updating the iMem+1...iMem+1+nCol counters */ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 610 | sqlite3VdbeResolveLabel(v, endOfLoop); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 611 | |
drh | 66a5167 | 2008-01-03 00:01:23 +0000 | [diff] [blame] | 612 | sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, topOfLoop); |
| 613 | sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 614 | #ifdef SQLITE_ENABLE_STAT3 |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 615 | sqlite3VdbeAddOp4(v, OP_Function, 1, regNumEq, regTemp2, |
| 616 | (char*)&stat3PushFuncdef, P4_FUNCDEF); |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 617 | sqlite3VdbeChangeP5(v, 5); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 618 | sqlite3VdbeAddOp2(v, OP_Integer, -1, regLoop); |
| 619 | shortJump = |
| 620 | sqlite3VdbeAddOp2(v, OP_AddImm, regLoop, 1); |
| 621 | sqlite3VdbeAddOp4(v, OP_Function, 1, regAccum, regTemp1, |
| 622 | (char*)&stat3GetFuncdef, P4_FUNCDEF); |
| 623 | sqlite3VdbeChangeP5(v, 2); |
| 624 | sqlite3VdbeAddOp1(v, OP_IsNull, regTemp1); |
| 625 | sqlite3VdbeAddOp3(v, OP_NotExists, iTabCur, shortJump, regTemp1); |
| 626 | sqlite3VdbeAddOp3(v, OP_Column, iTabCur, pIdx->aiColumn[0], regSample); |
| 627 | sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[0], regSample); |
| 628 | sqlite3VdbeAddOp4(v, OP_Function, 1, regAccum, regNumEq, |
| 629 | (char*)&stat3GetFuncdef, P4_FUNCDEF); |
| 630 | sqlite3VdbeChangeP5(v, 3); |
| 631 | sqlite3VdbeAddOp4(v, OP_Function, 1, regAccum, regNumLt, |
| 632 | (char*)&stat3GetFuncdef, P4_FUNCDEF); |
| 633 | sqlite3VdbeChangeP5(v, 4); |
drh | f404c86 | 2011-08-13 15:25:10 +0000 | [diff] [blame] | 634 | sqlite3VdbeAddOp4(v, OP_Function, 1, regAccum, regNumDLt, |
| 635 | (char*)&stat3GetFuncdef, P4_FUNCDEF); |
| 636 | sqlite3VdbeChangeP5(v, 5); |
| 637 | sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 6, regRec, "bbbbbb", 0); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 638 | sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid); |
| 639 | sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regRec, regNewRowid); |
| 640 | sqlite3VdbeAddOp2(v, OP_Goto, 0, shortJump); |
| 641 | sqlite3VdbeJumpHere(v, shortJump+2); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 642 | #endif |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 643 | |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 644 | /* Store the results in sqlite_stat1. |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 645 | ** |
drh | 4c10383 | 2007-06-20 13:37:31 +0000 | [diff] [blame] | 646 | ** The result is a single row of the sqlite_stat1 table. The first |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 647 | ** two columns are the names of the table and index. The third column |
| 648 | ** is a string composed of a list of integer statistics about the |
danielk1977 | 2f886d1 | 2009-02-28 10:47:41 +0000 | [diff] [blame] | 649 | ** index. The first integer in the list is the total number of entries |
drh | 17a18f2 | 2005-07-23 14:52:12 +0000 | [diff] [blame] | 650 | ** in the index. There is one additional integer in the list for each |
| 651 | ** column of the table. This additional integer is a guess of how many |
| 652 | ** rows of the table the index will select. If D is the count of distinct |
| 653 | ** values and K is the total number of rows, then the integer is computed |
| 654 | ** as: |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 655 | ** |
| 656 | ** I = (K+D-1)/D |
| 657 | ** |
| 658 | ** If K==0 then no entry is made into the sqlite_stat1 table. |
| 659 | ** If K>0 then it is always the case the D>0 so division by zero |
| 660 | ** is never possible. |
| 661 | */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 662 | sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regStat1); |
drh | f6cf1ff | 2011-03-30 14:54:05 +0000 | [diff] [blame] | 663 | if( jZeroRows<0 ){ |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 664 | jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); |
| 665 | } |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 666 | for(i=0; i<nCol; i++){ |
drh | 2d401ab | 2008-01-10 23:50:11 +0000 | [diff] [blame] | 667 | sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 668 | sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regStat1, regStat1); |
drh | 2d401ab | 2008-01-10 23:50:11 +0000 | [diff] [blame] | 669 | sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp); |
| 670 | sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1); |
| 671 | sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp); |
| 672 | sqlite3VdbeAddOp1(v, OP_ToInt, regTemp); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 673 | sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regStat1, regStat1); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 674 | } |
dan | e275dc3 | 2009-08-18 16:24:58 +0000 | [diff] [blame] | 675 | sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 676 | sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); |
| 677 | sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid); |
drh | 2d401ab | 2008-01-10 23:50:11 +0000 | [diff] [blame] | 678 | sqlite3VdbeChangeP5(v, OPFLAG_APPEND); |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 679 | } |
| 680 | |
| 681 | /* If the table has no indices, create a single sqlite_stat1 entry |
| 682 | ** containing NULL as the index name and the row count as the content. |
| 683 | */ |
| 684 | if( pTab->pIndex==0 ){ |
| 685 | sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb); |
| 686 | VdbeComment((v, "%s", pTab->zName)); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 687 | sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat1); |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 688 | sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 689 | jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 690 | }else{ |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 691 | sqlite3VdbeJumpHere(v, jZeroRows); |
drh | f6cf1ff | 2011-03-30 14:54:05 +0000 | [diff] [blame] | 692 | jZeroRows = sqlite3VdbeAddOp0(v, OP_Goto); |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 693 | } |
| 694 | sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); |
| 695 | sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 696 | sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); |
| 697 | sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid); |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 698 | sqlite3VdbeChangeP5(v, OPFLAG_APPEND); |
| 699 | if( pParse->nMem<regRec ) pParse->nMem = regRec; |
drh | f6cf1ff | 2011-03-30 14:54:05 +0000 | [diff] [blame] | 700 | sqlite3VdbeJumpHere(v, jZeroRows); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 701 | } |
| 702 | |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 703 | |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 704 | /* |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 705 | ** Generate code that will cause the most recent index analysis to |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 706 | ** be loaded into internal hash tables where is can be used. |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 707 | */ |
| 708 | static void loadAnalysis(Parse *pParse, int iDb){ |
| 709 | Vdbe *v = sqlite3GetVdbe(pParse); |
drh | cf1be45 | 2007-05-12 12:08:51 +0000 | [diff] [blame] | 710 | if( v ){ |
drh | 66a5167 | 2008-01-03 00:01:23 +0000 | [diff] [blame] | 711 | sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb); |
drh | cf1be45 | 2007-05-12 12:08:51 +0000 | [diff] [blame] | 712 | } |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 713 | } |
| 714 | |
| 715 | /* |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 716 | ** Generate code that will do an analysis of an entire database |
| 717 | */ |
| 718 | static void analyzeDatabase(Parse *pParse, int iDb){ |
| 719 | sqlite3 *db = pParse->db; |
danielk1977 | e501b89 | 2006-01-09 06:29:47 +0000 | [diff] [blame] | 720 | Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 721 | HashElem *k; |
| 722 | int iStatCur; |
| 723 | int iMem; |
| 724 | |
| 725 | sqlite3BeginWriteOperation(pParse, 0, iDb); |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 726 | iStatCur = pParse->nTab; |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 727 | pParse->nTab += 3; |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 728 | openStatTable(pParse, iDb, iStatCur, 0, 0); |
drh | 0a07c10 | 2008-01-03 18:03:08 +0000 | [diff] [blame] | 729 | iMem = pParse->nMem+1; |
drh | 2120608 | 2011-04-04 18:22:02 +0000 | [diff] [blame] | 730 | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
danielk1977 | da18423 | 2006-01-05 11:34:32 +0000 | [diff] [blame] | 731 | for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 732 | Table *pTab = (Table*)sqliteHashData(k); |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 733 | analyzeOneTable(pParse, pTab, 0, iStatCur, iMem); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 734 | } |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 735 | loadAnalysis(pParse, iDb); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 736 | } |
| 737 | |
| 738 | /* |
| 739 | ** Generate code that will do an analysis of a single table in |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 740 | ** a database. If pOnlyIdx is not NULL then it is a single index |
| 741 | ** in pTab that should be analyzed. |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 742 | */ |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 743 | static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 744 | int iDb; |
| 745 | int iStatCur; |
| 746 | |
| 747 | assert( pTab!=0 ); |
drh | 1fee73e | 2007-08-29 04:00:57 +0000 | [diff] [blame] | 748 | assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); |
danielk1977 | da18423 | 2006-01-05 11:34:32 +0000 | [diff] [blame] | 749 | iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 750 | sqlite3BeginWriteOperation(pParse, 0, iDb); |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 751 | iStatCur = pParse->nTab; |
drh | ade3add | 2011-08-13 00:58:05 +0000 | [diff] [blame] | 752 | pParse->nTab += 3; |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 753 | if( pOnlyIdx ){ |
| 754 | openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx"); |
| 755 | }else{ |
| 756 | openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl"); |
| 757 | } |
| 758 | analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem+1); |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 759 | loadAnalysis(pParse, iDb); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 760 | } |
| 761 | |
| 762 | /* |
| 763 | ** Generate code for the ANALYZE command. The parser calls this routine |
| 764 | ** when it recognizes an ANALYZE command. |
drh | 9f18e8a | 2005-07-08 12:13:04 +0000 | [diff] [blame] | 765 | ** |
| 766 | ** ANALYZE -- 1 |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 767 | ** ANALYZE <database> -- 2 |
drh | 9f18e8a | 2005-07-08 12:13:04 +0000 | [diff] [blame] | 768 | ** ANALYZE ?<database>.?<tablename> -- 3 |
| 769 | ** |
| 770 | ** Form 1 causes all indices in all attached databases to be analyzed. |
| 771 | ** Form 2 analyzes all indices the single database named. |
| 772 | ** Form 3 analyzes all indices associated with the named table. |
| 773 | */ |
| 774 | void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 775 | sqlite3 *db = pParse->db; |
| 776 | int iDb; |
| 777 | int i; |
| 778 | char *z, *zDb; |
| 779 | Table *pTab; |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 780 | Index *pIdx; |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 781 | Token *pTableName; |
| 782 | |
| 783 | /* Read the database schema. If an error occurs, leave an error message |
| 784 | ** and code in pParse and return NULL. */ |
drh | 1fee73e | 2007-08-29 04:00:57 +0000 | [diff] [blame] | 785 | assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 786 | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
| 787 | return; |
| 788 | } |
| 789 | |
drh | 05800a1 | 2009-04-16 17:45:47 +0000 | [diff] [blame] | 790 | assert( pName2!=0 || pName1==0 ); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 791 | if( pName1==0 ){ |
| 792 | /* Form 1: Analyze everything */ |
| 793 | for(i=0; i<db->nDb; i++){ |
| 794 | if( i==1 ) continue; /* Do not analyze the TEMP database */ |
| 795 | analyzeDatabase(pParse, i); |
| 796 | } |
drh | 05800a1 | 2009-04-16 17:45:47 +0000 | [diff] [blame] | 797 | }else if( pName2->n==0 ){ |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 798 | /* Form 2: Analyze the database or table named */ |
| 799 | iDb = sqlite3FindDb(db, pName1); |
| 800 | if( iDb>=0 ){ |
| 801 | analyzeDatabase(pParse, iDb); |
drh | e6e0496 | 2005-07-23 02:17:03 +0000 | [diff] [blame] | 802 | }else{ |
drh | 1743575 | 2007-08-16 04:30:38 +0000 | [diff] [blame] | 803 | z = sqlite3NameFromToken(db, pName1); |
danielk1977 | b8b4bfa | 2007-11-15 13:10:22 +0000 | [diff] [blame] | 804 | if( z ){ |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 805 | if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){ |
| 806 | analyzeTable(pParse, pIdx->pTable, pIdx); |
| 807 | }else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){ |
| 808 | analyzeTable(pParse, pTab, 0); |
danielk1977 | b8b4bfa | 2007-11-15 13:10:22 +0000 | [diff] [blame] | 809 | } |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 810 | sqlite3DbFree(db, z); |
drh | e6e0496 | 2005-07-23 02:17:03 +0000 | [diff] [blame] | 811 | } |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 812 | } |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 813 | }else{ |
| 814 | /* Form 3: Analyze the fully qualified table name */ |
| 815 | iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); |
| 816 | if( iDb>=0 ){ |
| 817 | zDb = db->aDb[iDb].zName; |
drh | 1743575 | 2007-08-16 04:30:38 +0000 | [diff] [blame] | 818 | z = sqlite3NameFromToken(db, pTableName); |
drh | cf1be45 | 2007-05-12 12:08:51 +0000 | [diff] [blame] | 819 | if( z ){ |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 820 | if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){ |
| 821 | analyzeTable(pParse, pIdx->pTable, pIdx); |
| 822 | }else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){ |
| 823 | analyzeTable(pParse, pTab, 0); |
drh | cf1be45 | 2007-05-12 12:08:51 +0000 | [diff] [blame] | 824 | } |
drh | a071bc5 | 2011-03-31 02:03:28 +0000 | [diff] [blame] | 825 | sqlite3DbFree(db, z); |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 826 | } |
| 827 | } |
| 828 | } |
drh | 9f18e8a | 2005-07-08 12:13:04 +0000 | [diff] [blame] | 829 | } |
| 830 | |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 831 | /* |
| 832 | ** Used to pass information from the analyzer reader through to the |
| 833 | ** callback routine. |
| 834 | */ |
| 835 | typedef struct analysisInfo analysisInfo; |
| 836 | struct analysisInfo { |
| 837 | sqlite3 *db; |
| 838 | const char *zDatabase; |
| 839 | }; |
| 840 | |
| 841 | /* |
| 842 | ** This callback is invoked once for each index when reading the |
| 843 | ** sqlite_stat1 table. |
| 844 | ** |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 845 | ** argv[0] = name of the table |
| 846 | ** argv[1] = name of the index (might be NULL) |
| 847 | ** argv[2] = results of analysis - on integer for each column |
| 848 | ** |
| 849 | ** Entries for which argv[1]==NULL simply record the number of rows in |
| 850 | ** the table. |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 851 | */ |
danielk1977 | 62c14b3 | 2008-11-19 09:05:26 +0000 | [diff] [blame] | 852 | static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 853 | analysisInfo *pInfo = (analysisInfo*)pData; |
| 854 | Index *pIndex; |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 855 | Table *pTable; |
| 856 | int i, c, n; |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 857 | tRowcnt v; |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 858 | const char *z; |
| 859 | |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 860 | assert( argc==3 ); |
danielk1977 | f3d3c27 | 2008-11-19 16:52:44 +0000 | [diff] [blame] | 861 | UNUSED_PARAMETER2(NotUsed, argc); |
| 862 | |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 863 | if( argv==0 || argv[0]==0 || argv[2]==0 ){ |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 864 | return 0; |
| 865 | } |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 866 | pTable = sqlite3FindTable(pInfo->db, argv[0], pInfo->zDatabase); |
| 867 | if( pTable==0 ){ |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 868 | return 0; |
| 869 | } |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 870 | if( argv[1] ){ |
| 871 | pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); |
| 872 | }else{ |
| 873 | pIndex = 0; |
| 874 | } |
| 875 | n = pIndex ? pIndex->nColumn : 0; |
| 876 | z = argv[2]; |
| 877 | for(i=0; *z && i<=n; i++){ |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 878 | v = 0; |
| 879 | while( (c=z[0])>='0' && c<='9' ){ |
| 880 | v = v*10 + c - '0'; |
| 881 | z++; |
| 882 | } |
drh | 1556405 | 2010-09-25 22:32:56 +0000 | [diff] [blame] | 883 | if( i==0 ) pTable->nRowEst = v; |
| 884 | if( pIndex==0 ) break; |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 885 | pIndex->aiRowEst[i] = v; |
| 886 | if( *z==' ' ) z++; |
drh | d6ee353 | 2011-03-29 15:00:17 +0000 | [diff] [blame] | 887 | if( memcmp(z, "unordered", 10)==0 ){ |
| 888 | pIndex->bUnordered = 1; |
| 889 | break; |
| 890 | } |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 891 | } |
| 892 | return 0; |
| 893 | } |
| 894 | |
| 895 | /* |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 896 | ** If the Index.aSample variable is not NULL, delete the aSample[] array |
| 897 | ** and its contents. |
| 898 | */ |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 899 | void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 900 | #ifdef SQLITE_ENABLE_STAT3 |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 901 | if( pIdx->aSample ){ |
| 902 | int j; |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 903 | for(j=0; j<pIdx->nSample; j++){ |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 904 | IndexSample *p = &pIdx->aSample[j]; |
| 905 | if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){ |
drh | 8e3937f | 2011-08-18 13:45:23 +0000 | [diff] [blame] | 906 | sqlite3DbFree(db, p->u.z); |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 907 | } |
| 908 | } |
drh | 8e3937f | 2011-08-18 13:45:23 +0000 | [diff] [blame] | 909 | sqlite3DbFree(db, pIdx->aSample); |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 910 | } |
drh | 8e3937f | 2011-08-18 13:45:23 +0000 | [diff] [blame] | 911 | if( db && db->pnBytesFreed==0 ){ |
| 912 | pIdx->nSample = 0; |
| 913 | pIdx->aSample = 0; |
| 914 | } |
shane | cea72b2 | 2009-09-07 04:38:36 +0000 | [diff] [blame] | 915 | #else |
drh | 43b18e1 | 2010-08-17 19:40:08 +0000 | [diff] [blame] | 916 | UNUSED_PARAMETER(db); |
shane | cea72b2 | 2009-09-07 04:38:36 +0000 | [diff] [blame] | 917 | UNUSED_PARAMETER(pIdx); |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 918 | #endif |
| 919 | } |
| 920 | |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 921 | #ifdef SQLITE_ENABLE_STAT3 |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 922 | /* |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 923 | ** Load content from the sqlite_stat3 table into the Index.aSample[] |
| 924 | ** arrays of all indices. |
| 925 | */ |
| 926 | static int loadStat3(sqlite3 *db, const char *zDb){ |
| 927 | int rc; /* Result codes from subroutines */ |
| 928 | sqlite3_stmt *pStmt = 0; /* An SQL statement being run */ |
| 929 | char *zSql; /* Text of the SQL statement */ |
| 930 | Index *pPrevIdx = 0; /* Previous index in the loop */ |
drh | 6825719 | 2011-08-16 17:06:21 +0000 | [diff] [blame] | 931 | int idx = 0; /* slot in pIdx->aSample[] for next sample */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 932 | int eType; /* Datatype of a sample */ |
| 933 | IndexSample *pSample; /* A slot in pIdx->aSample[] */ |
| 934 | |
dan | 0d1614c | 2012-03-19 10:21:37 +0000 | [diff] [blame] | 935 | assert( db->lookaside.bEnabled==0 ); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 936 | if( !sqlite3FindTable(db, "sqlite_stat3", zDb) ){ |
| 937 | return SQLITE_OK; |
| 938 | } |
| 939 | |
| 940 | zSql = sqlite3MPrintf(db, |
| 941 | "SELECT idx,count(*) FROM %Q.sqlite_stat3" |
| 942 | " GROUP BY idx", zDb); |
| 943 | if( !zSql ){ |
| 944 | return SQLITE_NOMEM; |
| 945 | } |
| 946 | rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); |
| 947 | sqlite3DbFree(db, zSql); |
| 948 | if( rc ) return rc; |
| 949 | |
| 950 | while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 951 | char *zIndex; /* Index name */ |
| 952 | Index *pIdx; /* Pointer to the index object */ |
| 953 | int nSample; /* Number of samples */ |
| 954 | |
| 955 | zIndex = (char *)sqlite3_column_text(pStmt, 0); |
| 956 | if( zIndex==0 ) continue; |
| 957 | nSample = sqlite3_column_int(pStmt, 1); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 958 | pIdx = sqlite3FindIndex(db, zIndex, zDb); |
| 959 | if( pIdx==0 ) continue; |
| 960 | assert( pIdx->nSample==0 ); |
drh | 2b9cf66 | 2011-09-22 20:52:56 +0000 | [diff] [blame] | 961 | pIdx->nSample = nSample; |
dan | 0d1614c | 2012-03-19 10:21:37 +0000 | [diff] [blame] | 962 | pIdx->aSample = sqlite3DbMallocZero(db, nSample*sizeof(IndexSample)); |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 963 | pIdx->avgEq = pIdx->aiRowEst[1]; |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 964 | if( pIdx->aSample==0 ){ |
| 965 | db->mallocFailed = 1; |
| 966 | sqlite3_finalize(pStmt); |
| 967 | return SQLITE_NOMEM; |
| 968 | } |
| 969 | } |
drh | 8e3937f | 2011-08-18 13:45:23 +0000 | [diff] [blame] | 970 | rc = sqlite3_finalize(pStmt); |
| 971 | if( rc ) return rc; |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 972 | |
| 973 | zSql = sqlite3MPrintf(db, |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 974 | "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat3", zDb); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 975 | if( !zSql ){ |
| 976 | return SQLITE_NOMEM; |
| 977 | } |
| 978 | rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); |
| 979 | sqlite3DbFree(db, zSql); |
| 980 | if( rc ) return rc; |
| 981 | |
| 982 | while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 983 | char *zIndex; /* Index name */ |
| 984 | Index *pIdx; /* Pointer to the index object */ |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 985 | int i; /* Loop counter */ |
| 986 | tRowcnt sumEq; /* Sum of the nEq values */ |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 987 | |
| 988 | zIndex = (char *)sqlite3_column_text(pStmt, 0); |
| 989 | if( zIndex==0 ) continue; |
| 990 | pIdx = sqlite3FindIndex(db, zIndex, zDb); |
| 991 | if( pIdx==0 ) continue; |
| 992 | if( pIdx==pPrevIdx ){ |
| 993 | idx++; |
| 994 | }else{ |
| 995 | pPrevIdx = pIdx; |
| 996 | idx = 0; |
| 997 | } |
| 998 | assert( idx<pIdx->nSample ); |
| 999 | pSample = &pIdx->aSample[idx]; |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 1000 | pSample->nEq = (tRowcnt)sqlite3_column_int64(pStmt, 1); |
| 1001 | pSample->nLt = (tRowcnt)sqlite3_column_int64(pStmt, 2); |
| 1002 | pSample->nDLt = (tRowcnt)sqlite3_column_int64(pStmt, 3); |
| 1003 | if( idx==pIdx->nSample-1 ){ |
| 1004 | if( pSample->nDLt>0 ){ |
| 1005 | for(i=0, sumEq=0; i<=idx-1; i++) sumEq += pIdx->aSample[i].nEq; |
| 1006 | pIdx->avgEq = (pSample->nLt - sumEq)/pSample->nDLt; |
| 1007 | } |
| 1008 | if( pIdx->avgEq<=0 ) pIdx->avgEq = 1; |
| 1009 | } |
| 1010 | eType = sqlite3_column_type(pStmt, 4); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1011 | pSample->eType = (u8)eType; |
| 1012 | switch( eType ){ |
| 1013 | case SQLITE_INTEGER: { |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 1014 | pSample->u.i = sqlite3_column_int64(pStmt, 4); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1015 | break; |
| 1016 | } |
| 1017 | case SQLITE_FLOAT: { |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 1018 | pSample->u.r = sqlite3_column_double(pStmt, 4); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1019 | break; |
| 1020 | } |
| 1021 | case SQLITE_NULL: { |
| 1022 | break; |
| 1023 | } |
| 1024 | default: assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); { |
| 1025 | const char *z = (const char *)( |
| 1026 | (eType==SQLITE_BLOB) ? |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 1027 | sqlite3_column_blob(pStmt, 4): |
| 1028 | sqlite3_column_text(pStmt, 4) |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1029 | ); |
drh | 8e3937f | 2011-08-18 13:45:23 +0000 | [diff] [blame] | 1030 | int n = z ? sqlite3_column_bytes(pStmt, 4) : 0; |
drh | 5c62486 | 2011-09-22 18:46:34 +0000 | [diff] [blame] | 1031 | pSample->nByte = n; |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1032 | if( n < 1){ |
| 1033 | pSample->u.z = 0; |
| 1034 | }else{ |
dan | 0d1614c | 2012-03-19 10:21:37 +0000 | [diff] [blame] | 1035 | pSample->u.z = sqlite3DbMallocRaw(db, n); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1036 | if( pSample->u.z==0 ){ |
| 1037 | db->mallocFailed = 1; |
| 1038 | sqlite3_finalize(pStmt); |
| 1039 | return SQLITE_NOMEM; |
| 1040 | } |
| 1041 | memcpy(pSample->u.z, z, n); |
| 1042 | } |
| 1043 | } |
| 1044 | } |
| 1045 | } |
| 1046 | return sqlite3_finalize(pStmt); |
| 1047 | } |
| 1048 | #endif /* SQLITE_ENABLE_STAT3 */ |
| 1049 | |
| 1050 | /* |
| 1051 | ** Load the content of the sqlite_stat1 and sqlite_stat3 tables. The |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 1052 | ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1053 | ** arrays. The contents of sqlite_stat3 are used to populate the |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 1054 | ** Index.aSample[] arrays. |
| 1055 | ** |
| 1056 | ** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1057 | ** is returned. In this case, even if SQLITE_ENABLE_STAT3 was defined |
| 1058 | ** during compilation and the sqlite_stat3 table is present, no data is |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 1059 | ** read from it. |
| 1060 | ** |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1061 | ** If SQLITE_ENABLE_STAT3 was defined during compilation and the |
| 1062 | ** sqlite_stat3 table is not present in the database, SQLITE_ERROR is |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 1063 | ** returned. However, in this case, data is read from the sqlite_stat1 |
| 1064 | ** table (if it is present) before returning. |
| 1065 | ** |
| 1066 | ** If an OOM error occurs, this function always sets db->mallocFailed. |
| 1067 | ** This means if the caller does not care about other errors, the return |
| 1068 | ** code may be ignored. |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1069 | */ |
drh | cf1be45 | 2007-05-12 12:08:51 +0000 | [diff] [blame] | 1070 | int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1071 | analysisInfo sInfo; |
| 1072 | HashElem *i; |
| 1073 | char *zSql; |
drh | cf1be45 | 2007-05-12 12:08:51 +0000 | [diff] [blame] | 1074 | int rc; |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1075 | |
drh | ff0587c | 2007-08-29 17:43:19 +0000 | [diff] [blame] | 1076 | assert( iDb>=0 && iDb<db->nDb ); |
| 1077 | assert( db->aDb[iDb].pBt!=0 ); |
drh | 1fee73e | 2007-08-29 04:00:57 +0000 | [diff] [blame] | 1078 | |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1079 | /* Clear any prior statistics */ |
drh | 2120608 | 2011-04-04 18:22:02 +0000 | [diff] [blame] | 1080 | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
danielk1977 | da18423 | 2006-01-05 11:34:32 +0000 | [diff] [blame] | 1081 | for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1082 | Index *pIdx = sqliteHashData(i); |
drh | 51147ba | 2005-07-23 22:59:55 +0000 | [diff] [blame] | 1083 | sqlite3DefaultRowEst(pIdx); |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1084 | #ifdef SQLITE_ENABLE_STAT3 |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 1085 | sqlite3DeleteIndexSamples(db, pIdx); |
| 1086 | pIdx->aSample = 0; |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1087 | #endif |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1088 | } |
| 1089 | |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 1090 | /* Check to make sure the sqlite_stat1 table exists */ |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1091 | sInfo.db = db; |
| 1092 | sInfo.zDatabase = db->aDb[iDb].zName; |
| 1093 | if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){ |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 1094 | return SQLITE_ERROR; |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1095 | } |
| 1096 | |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1097 | /* Load new statistics out of the sqlite_stat1 table */ |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 1098 | zSql = sqlite3MPrintf(db, |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1099 | "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); |
drh | f16ce3b | 2009-02-13 16:59:53 +0000 | [diff] [blame] | 1100 | if( zSql==0 ){ |
| 1101 | rc = SQLITE_NOMEM; |
| 1102 | }else{ |
drh | f16ce3b | 2009-02-13 16:59:53 +0000 | [diff] [blame] | 1103 | rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); |
drh | f16ce3b | 2009-02-13 16:59:53 +0000 | [diff] [blame] | 1104 | sqlite3DbFree(db, zSql); |
drh | f16ce3b | 2009-02-13 16:59:53 +0000 | [diff] [blame] | 1105 | } |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 1106 | |
dan | 85c165c | 2009-08-19 14:34:54 +0000 | [diff] [blame] | 1107 | |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1108 | /* Load the statistics from the sqlite_stat3 table. */ |
| 1109 | #ifdef SQLITE_ENABLE_STAT3 |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 1110 | if( rc==SQLITE_OK ){ |
dan | 0d1614c | 2012-03-19 10:21:37 +0000 | [diff] [blame] | 1111 | int lookasideEnabled = db->lookaside.bEnabled; |
| 1112 | db->lookaside.bEnabled = 0; |
drh | faacf17 | 2011-08-12 01:51:45 +0000 | [diff] [blame] | 1113 | rc = loadStat3(db, sInfo.zDatabase); |
dan | 0d1614c | 2012-03-19 10:21:37 +0000 | [diff] [blame] | 1114 | db->lookaside.bEnabled = lookasideEnabled; |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 1115 | } |
dan | 69188d9 | 2009-08-19 08:18:32 +0000 | [diff] [blame] | 1116 | #endif |
dan | 02fa469 | 2009-08-17 17:06:58 +0000 | [diff] [blame] | 1117 | |
dan | e275dc3 | 2009-08-18 16:24:58 +0000 | [diff] [blame] | 1118 | if( rc==SQLITE_NOMEM ){ |
| 1119 | db->mallocFailed = 1; |
| 1120 | } |
drh | cf1be45 | 2007-05-12 12:08:51 +0000 | [diff] [blame] | 1121 | return rc; |
drh | 497e446 | 2005-07-23 03:18:40 +0000 | [diff] [blame] | 1122 | } |
drh | 9f18e8a | 2005-07-08 12:13:04 +0000 | [diff] [blame] | 1123 | |
drh | ff2d5ea | 2005-07-23 00:41:48 +0000 | [diff] [blame] | 1124 | |
drh | 9f18e8a | 2005-07-08 12:13:04 +0000 | [diff] [blame] | 1125 | #endif /* SQLITE_OMIT_ANALYZE */ |