wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Diagnostics;
3 using System.Text;
4  
5 using u8 = System.Byte;
6  
7 namespace Community.CsharpSqlite
8 {
9 using sqlite3_int64 = System.Int64;
10 using sqlite3_stmt = Sqlite3.Vdbe;
11  
12 public partial class Sqlite3
13 {
14 /*
15 ** 2005 July 8
16 **
17 ** The author disclaims copyright to this source code. In place of
18 ** a legal notice, here is a blessing:
19 **
20 ** May you do good and not evil.
21 ** May you find forgiveness for yourself and forgive others.
22 ** May you share freely, never taking more than you give.
23 **
24 *************************************************************************
25 ** This file contains code associated with the ANALYZE command.
26 *************************************************************************
27 ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
28 ** C#-SQLite is an independent reimplementation of the SQLite software library
29 **
30 ** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
31 **
32 *************************************************************************
33 */
34 #if !SQLITE_OMIT_ANALYZE
35 //#include "sqliteInt.h"
36  
37 /*
38 ** This routine generates code that opens the sqlite_stat1 table for
39 ** writing with cursor iStatCur. If the library was built with the
40 ** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is
41 ** opened for writing using cursor (iStatCur+1)
42 **
43 ** If the sqlite_stat1 tables does not previously exist, it is created.
44 ** Similarly, if the sqlite_stat2 table does not exist and the library
45 ** is compiled with SQLITE_ENABLE_STAT2 defined, it is created.
46 **
47 ** Argument zWhere may be a pointer to a buffer containing a table name,
48 ** or it may be a NULL pointer. If it is not NULL, then all entries in
49 ** the sqlite_stat1 and (if applicable) sqlite_stat2 tables associated
50 ** with the named table are deleted. If zWhere==0, then code is generated
51 ** to delete all stat table entries.
52 */
53 public struct _aTable
54 {
55 public string zName;
56 public string zCols;
57 public _aTable( string zName, string zCols )
58 {
59 this.zName = zName;
60 this.zCols = zCols;
61 }
62 };
63 static _aTable[] aTable = new _aTable[]{
64 new _aTable( "sqlite_stat1", "tbl,idx,stat" ),
65 #if SQLITE_ENABLE_STAT2
66 new _aTable( "sqlite_stat2", "tbl,idx,sampleno,sample" ),
67 #endif
68 };
69  
70 static void openStatTable(
71 Parse pParse, /* Parsing context */
72 int iDb, /* The database we are looking in */
73 int iStatCur, /* Open the sqlite_stat1 table on this cursor */
74 string zWhere, /* Delete entries for this table or index */
75 string zWhereType /* Either "tbl" or "idx" */
76 )
77 {
78 int[] aRoot = new int[] { 0, 0 };
79 u8[] aCreateTbl = new u8[] { 0, 0 };
80  
81 int i;
82 sqlite3 db = pParse.db;
83 Db pDb;
84 Vdbe v = sqlite3GetVdbe( pParse );
85  
86 if ( v == null )
87 return;
88 Debug.Assert( sqlite3BtreeHoldsAllMutexes( db ) );
89 Debug.Assert( sqlite3VdbeDb( v ) == db );
90 pDb = db.aDb[iDb];
91  
92 for ( i = 0; i < ArraySize( aTable ); i++ )
93 {
94 string zTab = aTable[i].zName;
95 Table pStat;
96 if ( ( pStat = sqlite3FindTable( db, zTab, pDb.zName ) ) == null )
97 {
98 /* The sqlite_stat[12] table does not exist. Create it. Note that a
99 ** side-effect of the CREATE TABLE statement is to leave the rootpage
100 ** of the new table in register pParse.regRoot. This is important
101 ** because the OpenWrite opcode below will be needing it. */
102 sqlite3NestedParse( pParse,
103 "CREATE TABLE %Q.%s(%s)", pDb.zName, zTab, aTable[i].zCols
104 );
105 aRoot[i] = pParse.regRoot;
106 aCreateTbl[i] = 1;
107 }
108 else
109 {
110 /* The table already exists. If zWhere is not NULL, delete all entries
111 ** associated with the table zWhere. If zWhere is NULL, delete the
112 ** entire contents of the table. */
113 aRoot[i] = pStat.tnum;
114 sqlite3TableLock( pParse, iDb, aRoot[i], 1, zTab );
115 if ( !string.IsNullOrEmpty( zWhere ) )
116 {
117 sqlite3NestedParse( pParse,
118 "DELETE FROM %Q.%s WHERE %s=%Q", pDb.zName, zTab, zWhereType, zWhere
119 );
120 }
121 else
122 {
123 /* The sqlite_stat[12] table already exists. Delete all rows. */
124 sqlite3VdbeAddOp2( v, OP_Clear, aRoot[i], iDb );
125 }
126 }
127 }
128  
129 /* Open the sqlite_stat[12] tables for writing. */
130 for ( i = 0; i < ArraySize( aTable ); i++ )
131 {
132 sqlite3VdbeAddOp3( v, OP_OpenWrite, iStatCur + i, aRoot[i], iDb );
133 sqlite3VdbeChangeP4( v, -1, 3, P4_INT32 );
134 sqlite3VdbeChangeP5( v, aCreateTbl[i] );
135 }
136 }
137  
138 /*
139 ** Generate code to do an analysis of all indices associated with
140 ** a single table.
141 */
142 static void analyzeOneTable(
143 Parse pParse, /* Parser context */
144 Table pTab, /* Table whose indices are to be analyzed */
145 Index pOnlyIdx, /* If not NULL, only analyze this one index */
146 int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */
147 int iMem /* Available memory locations begin here */
148 )
149 {
150 sqlite3 db = pParse.db; /* Database handle */
151 Index pIdx; /* An index to being analyzed */
152 int iIdxCur; /* Cursor open on index being analyzed */
153 Vdbe v; /* The virtual machine being built up */
154 int i; /* Loop counter */
155 int topOfLoop; /* The top of the loop */
156 int endOfLoop; /* The end of the loop */
157 int jZeroRows = -1; /* Jump from here if number of rows is zero */
158 int iDb; /* Index of database containing pTab */
159 int regTabname = iMem++; /* Register containing table name */
160 int regIdxname = iMem++; /* Register containing index name */
161 int regSampleno = iMem++; /* Register containing next sample number */
162 int regCol = iMem++; /* Content of a column analyzed table */
163 int regRec = iMem++; /* Register holding completed record */
164 int regTemp = iMem++; /* Temporary use register */
165 int regRowid = iMem++; /* Rowid for the inserted record */
166  
167 #if SQLITE_ENABLE_STAT2
168 int addr = 0; /* Instruction address */
169 int regTemp2 = iMem++; /* Temporary use register */
170 int regSamplerecno = iMem++; /* Index of next sample to record */
171 int regRecno = iMem++; /* Current sample index */
172 int regLast = iMem++; /* Index of last sample to record */
173 int regFirst = iMem++; /* Index of first sample to record */
174 #endif
175  
176 v = sqlite3GetVdbe( pParse );
177 if ( v == null || NEVER( pTab == null ) )
178 {
179 return;
180 }
181 if ( pTab.tnum == 0 )
182 {
183 /* Do not gather statistics on views or virtual tables */
184 return;
185 }
186 if ( pTab.zName.StartsWith( "sqlite_", StringComparison.OrdinalIgnoreCase ) )
187 {
188 /* Do not gather statistics on system tables */
189 return;
190 }
191 Debug.Assert( sqlite3BtreeHoldsAllMutexes( db ) );
192 iDb = sqlite3SchemaToIndex( db, pTab.pSchema );
193 Debug.Assert( iDb >= 0 );
194 Debug.Assert( sqlite3SchemaMutexHeld(db, iDb, null) );
195 #if !SQLITE_OMIT_AUTHORIZATION
196 if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab.zName, 0,
197 db.aDb[iDb].zName ) ){
198 return;
199 }
200 #endif
201  
202 /* Establish a read-lock on the table at the shared-cache level. */
203 sqlite3TableLock( pParse, iDb, pTab.tnum, 0, pTab.zName );
204  
205 iIdxCur = pParse.nTab++;
206 sqlite3VdbeAddOp4( v, OP_String8, 0, regTabname, 0, pTab.zName, 0 );
207 for ( pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext )
208 {
209 int nCol;
210 KeyInfo pKey;
211 if ( pOnlyIdx != null && pOnlyIdx != pIdx )
212 continue;
213 nCol = pIdx.nColumn;
214 pKey = sqlite3IndexKeyinfo( pParse, pIdx );
215  
216 if ( iMem + 1 + ( nCol * 2 ) > pParse.nMem )
217 {
218 pParse.nMem = iMem + 1 + ( nCol * 2 );
219 }
220  
221 /* Open a cursor to the index to be analyzed. */
222 Debug.Assert( iDb == sqlite3SchemaToIndex( db, pIdx.pSchema ) );
223 sqlite3VdbeAddOp4( v, OP_OpenRead, iIdxCur, pIdx.tnum, iDb,
224 pKey, P4_KEYINFO_HANDOFF );
225 VdbeComment( v, "%s", pIdx.zName );
226  
227 /* Populate the registers containing the index names. */
228 sqlite3VdbeAddOp4( v, OP_String8, 0, regIdxname, 0, pIdx.zName, 0 );
229  
230 #if SQLITE_ENABLE_STAT2
231  
232 /* If this iteration of the loop is generating code to analyze the
233 ** first index in the pTab.pIndex list, then register regLast has
234 ** not been populated. In this case populate it now. */
235 if ( pTab.pIndex == pIdx )
236 {
237 sqlite3VdbeAddOp2( v, OP_Integer, SQLITE_INDEX_SAMPLES, regSamplerecno );
238 sqlite3VdbeAddOp2( v, OP_Integer, SQLITE_INDEX_SAMPLES * 2 - 1, regTemp );
239 sqlite3VdbeAddOp2( v, OP_Integer, SQLITE_INDEX_SAMPLES * 2, regTemp2 );
240  
241 sqlite3VdbeAddOp2( v, OP_Count, iIdxCur, regLast );
242 sqlite3VdbeAddOp2( v, OP_Null, 0, regFirst );
243 addr = sqlite3VdbeAddOp3( v, OP_Lt, regSamplerecno, 0, regLast );
244 sqlite3VdbeAddOp3( v, OP_Divide, regTemp2, regLast, regFirst );
245 sqlite3VdbeAddOp3( v, OP_Multiply, regLast, regTemp, regLast );
246 sqlite3VdbeAddOp2( v, OP_AddImm, regLast, SQLITE_INDEX_SAMPLES * 2 - 2 );
247 sqlite3VdbeAddOp3( v, OP_Divide, regTemp2, regLast, regLast );
248 sqlite3VdbeJumpHere( v, addr );
249 }
250  
251 /* Zero the regSampleno and regRecno registers. */
252 sqlite3VdbeAddOp2( v, OP_Integer, 0, regSampleno );
253 sqlite3VdbeAddOp2( v, OP_Integer, 0, regRecno );
254 sqlite3VdbeAddOp2( v, OP_Copy, regFirst, regSamplerecno );
255 #endif
256  
257 /* The block of memory cells initialized here is used as follows.
258 **
259 ** iMem:
260 ** The total number of rows in the table.
261 **
262 ** iMem+1 .. iMem+nCol:
263 ** Number of distinct entries in index considering the
264 ** left-most N columns only, where N is between 1 and nCol,
265 ** inclusive.
266 **
267 ** iMem+nCol+1 .. Mem+2*nCol:
268 ** Previous value of indexed columns, from left to right.
269 **
270 ** Cells iMem through iMem+nCol are initialized to 0. The others are
271 ** initialized to contain an SQL NULL.
272 */
273 for ( i = 0; i <= nCol; i++ )
274 {
275 sqlite3VdbeAddOp2( v, OP_Integer, 0, iMem + i );
276 }
277 for ( i = 0; i < nCol; i++ )
278 {
279 sqlite3VdbeAddOp2( v, OP_Null, 0, iMem + nCol + i + 1 );
280 }
281  
282 /* Start the analysis loop. This loop runs through all the entries in
283 ** the index b-tree. */
284 endOfLoop = sqlite3VdbeMakeLabel( v );
285 sqlite3VdbeAddOp2( v, OP_Rewind, iIdxCur, endOfLoop );
286 topOfLoop = sqlite3VdbeCurrentAddr( v );
287 sqlite3VdbeAddOp2( v, OP_AddImm, iMem, 1 );
288  
289 for ( i = 0; i < nCol; i++ )
290 {
291 sqlite3VdbeAddOp3( v, OP_Column, iIdxCur, i, regCol );
292 CollSeq pColl;
293 if ( i == 0 )
294 {
295 #if SQLITE_ENABLE_STAT2
296 /* Check if the record that cursor iIdxCur points to contains a
297 ** value that should be stored in the sqlite_stat2 table. If so,
298 ** store it. */
299 int ne = sqlite3VdbeAddOp3( v, OP_Ne, regRecno, 0, regSamplerecno );
300 Debug.Assert( regTabname + 1 == regIdxname
301 && regTabname + 2 == regSampleno
302 && regTabname + 3 == regCol
303 );
304 sqlite3VdbeChangeP5( v, SQLITE_JUMPIFNULL );
305 sqlite3VdbeAddOp4( v, OP_MakeRecord, regTabname, 4, regRec, "aaab", 0 );
306 sqlite3VdbeAddOp2( v, OP_NewRowid, iStatCur + 1, regRowid );
307 sqlite3VdbeAddOp3( v, OP_Insert, iStatCur + 1, regRec, regRowid );
308  
309 /* Calculate new values for regSamplerecno and regSampleno.
310 **
311 ** sampleno = sampleno + 1
312 ** samplerecno = samplerecno+(remaining records)/(remaining samples)
313 */
314 sqlite3VdbeAddOp2( v, OP_AddImm, regSampleno, 1 );
315 sqlite3VdbeAddOp3( v, OP_Subtract, regRecno, regLast, regTemp );
316 sqlite3VdbeAddOp2( v, OP_AddImm, regTemp, -1 );
317 sqlite3VdbeAddOp2( v, OP_Integer, SQLITE_INDEX_SAMPLES, regTemp2 );
318 sqlite3VdbeAddOp3( v, OP_Subtract, regSampleno, regTemp2, regTemp2 );
319 sqlite3VdbeAddOp3( v, OP_Divide, regTemp2, regTemp, regTemp );
320 sqlite3VdbeAddOp3( v, OP_Add, regSamplerecno, regTemp, regSamplerecno );
321  
322 sqlite3VdbeJumpHere( v, ne );
323 sqlite3VdbeAddOp2( v, OP_AddImm, regRecno, 1 );
324 #endif
325  
326 /* Always record the very first row */
327 sqlite3VdbeAddOp1( v, OP_IfNot, iMem + 1 );
328 }
329 Debug.Assert( pIdx.azColl != null );
330 Debug.Assert( pIdx.azColl[i] != null );
331 pColl = sqlite3LocateCollSeq( pParse, pIdx.azColl[i] );
332 sqlite3VdbeAddOp4( v, OP_Ne, regCol, 0, iMem + nCol + i + 1,
333 pColl, P4_COLLSEQ );
334 sqlite3VdbeChangeP5( v, SQLITE_NULLEQ );
335 }
336 //if( db.mallocFailed ){
337 // /* If a malloc failure has occurred, then the result of the expression
338 // ** passed as the second argument to the call to sqlite3VdbeJumpHere()
339 // ** below may be negative. Which causes an Debug.Assert() to fail (or an
340 // ** out-of-bounds write if SQLITE_DEBUG is not defined). */
341 // return;
342 //}
343 sqlite3VdbeAddOp2( v, OP_Goto, 0, endOfLoop );
344 for ( i = 0; i < nCol; i++ )
345 {
346 int addr2 = sqlite3VdbeCurrentAddr( v ) - ( nCol * 2 );
347 if ( i == 0 )
348 {
349 sqlite3VdbeJumpHere( v, addr2 - 1 ); /* Set jump dest for the OP_IfNot */
350 }
351 sqlite3VdbeJumpHere( v, addr2 ); /* Set jump dest for the OP_Ne */
352 sqlite3VdbeAddOp2( v, OP_AddImm, iMem + i + 1, 1 );
353 sqlite3VdbeAddOp3( v, OP_Column, iIdxCur, i, iMem + nCol + i + 1 );
354 }
355  
356 /* End of the analysis loop. */
357 sqlite3VdbeResolveLabel( v, endOfLoop );
358 sqlite3VdbeAddOp2( v, OP_Next, iIdxCur, topOfLoop );
359 sqlite3VdbeAddOp1( v, OP_Close, iIdxCur );
360  
361 /* Store the results in sqlite_stat1.
362 **
363 ** The result is a single row of the sqlite_stat1 table. The first
364 ** two columns are the names of the table and index. The third column
365 ** is a string composed of a list of integer statistics about the
366 ** index. The first integer in the list is the total number of entries
367 ** in the index. There is one additional integer in the list for each
368 ** column of the table. This additional integer is a guess of how many
369 ** rows of the table the index will select. If D is the count of distinct
370 ** values and K is the total number of rows, then the integer is computed
371 ** as:
372 **
373 ** I = (K+D-1)/D
374 **
375 ** If K==0 then no entry is made into the sqlite_stat1 table.
376 ** If K>0 then it is always the case the D>0 so division by zero
377 ** is never possible.
378 */
379 sqlite3VdbeAddOp2( v, OP_SCopy, iMem, regSampleno );
380 if ( jZeroRows < 0 )
381 {
382 jZeroRows = sqlite3VdbeAddOp1( v, OP_IfNot, iMem );
383 }
384 for ( i = 0; i < nCol; i++ )
385 {
386 sqlite3VdbeAddOp4( v, OP_String8, 0, regTemp, 0, " ", 0 );
387 sqlite3VdbeAddOp3( v, OP_Concat, regTemp, regSampleno, regSampleno );
388 sqlite3VdbeAddOp3( v, OP_Add, iMem, iMem + i + 1, regTemp );
389 sqlite3VdbeAddOp2( v, OP_AddImm, regTemp, -1 );
390 sqlite3VdbeAddOp3( v, OP_Divide, iMem + i + 1, regTemp, regTemp );
391 sqlite3VdbeAddOp1( v, OP_ToInt, regTemp );
392 sqlite3VdbeAddOp3( v, OP_Concat, regTemp, regSampleno, regSampleno );
393 }
394 sqlite3VdbeAddOp4( v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0 );
395 sqlite3VdbeAddOp2( v, OP_NewRowid, iStatCur, regRowid );
396 sqlite3VdbeAddOp3( v, OP_Insert, iStatCur, regRec, regRowid );
397 sqlite3VdbeChangeP5( v, OPFLAG_APPEND );
398 }
399  
400 /* If the table has no indices, create a single sqlite_stat1 entry
401 ** containing NULL as the index name and the row count as the content.
402 */
403 if ( pTab.pIndex == null )
404 {
405 sqlite3VdbeAddOp3( v, OP_OpenRead, iIdxCur, pTab.tnum, iDb );
406 VdbeComment( v, "%s", pTab.zName );
407 sqlite3VdbeAddOp2( v, OP_Count, iIdxCur, regSampleno );
408 sqlite3VdbeAddOp1( v, OP_Close, iIdxCur );
409 jZeroRows = sqlite3VdbeAddOp1( v, OP_IfNot, regSampleno );
410 }
411 else
412 {
413 sqlite3VdbeJumpHere( v, jZeroRows );
414 jZeroRows = sqlite3VdbeAddOp0( v, OP_Goto );
415 }
416 sqlite3VdbeAddOp2( v, OP_Null, 0, regIdxname );
417 sqlite3VdbeAddOp4( v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0 );
418 sqlite3VdbeAddOp2( v, OP_NewRowid, iStatCur, regRowid );
419 sqlite3VdbeAddOp3( v, OP_Insert, iStatCur, regRec, regRowid );
420 sqlite3VdbeChangeP5( v, OPFLAG_APPEND );
421 if ( pParse.nMem < regRec )
422 pParse.nMem = regRec;
423 sqlite3VdbeJumpHere( v, jZeroRows );
424 }
425  
426 /*
427 ** Generate code that will cause the most recent index analysis to
428 ** be loaded into internal hash tables where is can be used.
429 */
430 static void loadAnalysis( Parse pParse, int iDb )
431 {
432 Vdbe v = sqlite3GetVdbe( pParse );
433 if ( v != null )
434 {
435 sqlite3VdbeAddOp1( v, OP_LoadAnalysis, iDb );
436 }
437 }
438  
439 /*
440 ** Generate code that will do an analysis of an entire database
441 */
442 static void analyzeDatabase( Parse pParse, int iDb )
443 {
444 sqlite3 db = pParse.db;
445 Schema pSchema = db.aDb[iDb].pSchema; /* Schema of database iDb */
446 HashElem k;
447 int iStatCur;
448 int iMem;
449  
450 sqlite3BeginWriteOperation( pParse, 0, iDb );
451 iStatCur = pParse.nTab;
452 pParse.nTab += 2;
453 openStatTable( pParse, iDb, iStatCur, null, null );
454 iMem = pParse.nMem + 1;
455 Debug.Assert( sqlite3SchemaMutexHeld( db, iDb, null ) );
456 //for(k=sqliteHashFirst(pSchema.tblHash); k; k=sqliteHashNext(k)){
457 for ( k = pSchema.tblHash.first; k != null; k = k.next )
458 {
459 Table pTab = (Table)k.data;// sqliteHashData( k );
460 analyzeOneTable( pParse, pTab, null, iStatCur, iMem );
461 }
462 loadAnalysis( pParse, iDb );
463 }
464  
465 /*
466 ** Generate code that will do an analysis of a single table in
467 ** a database. If pOnlyIdx is not NULL then it is a single index
468 ** in pTab that should be analyzed.
469 */
470 static void analyzeTable( Parse pParse, Table pTab, Index pOnlyIdx)
471 {
472 int iDb;
473 int iStatCur;
474  
475 Debug.Assert( pTab != null );
476 Debug.Assert( sqlite3BtreeHoldsAllMutexes( pParse.db ) );
477 iDb = sqlite3SchemaToIndex( pParse.db, pTab.pSchema );
478 sqlite3BeginWriteOperation( pParse, 0, iDb );
479 iStatCur = pParse.nTab;
480 pParse.nTab += 2;
481 if ( pOnlyIdx != null )
482 {
483 openStatTable( pParse, iDb, iStatCur, pOnlyIdx.zName, "idx" );
484 }
485 else
486 {
487 openStatTable( pParse, iDb, iStatCur, pTab.zName, "tbl" );
488 }
489 analyzeOneTable( pParse, pTab, pOnlyIdx, iStatCur, pParse.nMem + 1 );
490 loadAnalysis( pParse, iDb );
491 }
492  
493 /*
494 ** Generate code for the ANALYZE command. The parser calls this routine
495 ** when it recognizes an ANALYZE command.
496 **
497 ** ANALYZE -- 1
498 ** ANALYZE <database> -- 2
499 ** ANALYZE ?<database>.?<tablename> -- 3
500 **
501 ** Form 1 causes all indices in all attached databases to be analyzed.
502 ** Form 2 analyzes all indices the single database named.
503 ** Form 3 analyzes all indices associated with the named table.
504 */
505 // OVERLOADS, so I don't need to rewrite parse.c
506 static void sqlite3Analyze( Parse pParse, int null_2, int null_3 )
507 {
508 sqlite3Analyze( pParse, null, null );
509 }
510 static void sqlite3Analyze( Parse pParse, Token pName1, Token pName2 )
511 {
512 sqlite3 db = pParse.db;
513 int iDb;
514 int i;
515 string z, zDb;
516 Table pTab;
517 Index pIdx;
518 Token pTableName = null;
519  
520 /* Read the database schema. If an error occurs, leave an error message
521 ** and code in pParse and return NULL. */
522 Debug.Assert( sqlite3BtreeHoldsAllMutexes( pParse.db ) );
523 if ( SQLITE_OK != sqlite3ReadSchema( pParse ) )
524 {
525 return;
526 }
527  
528 Debug.Assert( pName2 != null || pName1 == null );
529 if ( pName1 == null )
530 {
531 /* Form 1: Analyze everything */
532 for ( i = 0; i < db.nDb; i++ )
533 {
534 if ( i == 1 )
535 continue; /* Do not analyze the TEMP database */
536 analyzeDatabase( pParse, i );
537 }
538 }
539 else if ( pName2.n == 0 )
540 {
541 /* Form 2: Analyze the database or table named */
542 iDb = sqlite3FindDb( db, pName1 );
543 if ( iDb >= 0 )
544 {
545 analyzeDatabase( pParse, iDb );
546 }
547 else
548 {
549 z = sqlite3NameFromToken( db, pName1 );
550 if ( z != null )
551 {
552 if ( ( pIdx = sqlite3FindIndex( db, z, null ) ) != null )
553 {
554 analyzeTable( pParse, pIdx.pTable, pIdx );
555 }
556 else if ( ( pTab = sqlite3LocateTable( pParse, 0, z, null ) ) != null )
557 {
558 analyzeTable( pParse, pTab, null );
559 }
560 z = null;//sqlite3DbFree( db, z );
561 }
562 }
563 }
564 else
565 {
566 /* Form 3: Analyze the fully qualified table name */
567 iDb = sqlite3TwoPartName( pParse, pName1, pName2, ref pTableName );
568 if ( iDb >= 0 )
569 {
570 zDb = db.aDb[iDb].zName;
571 z = sqlite3NameFromToken( db, pTableName );
572 if ( z != null )
573 {
574 if ( ( pIdx = sqlite3FindIndex( db, z, zDb ) ) != null )
575 {
576 analyzeTable( pParse, pIdx.pTable, pIdx );
577 }
578 else if ( ( pTab = sqlite3LocateTable( pParse, 0, z, zDb ) ) != null )
579 {
580 analyzeTable( pParse, pTab, null );
581 }
582 z = null; //sqlite3DbFree( db, z );
583 }
584 }
585 }
586 }
587  
588 /*
589 ** Used to pass information from the analyzer reader through to the
590 ** callback routine.
591 */
592 //typedef struct analysisInfo analysisInfo;
593 public struct analysisInfo
594 {
595 public sqlite3 db;
596 public string zDatabase;
597 };
598  
599 /*
600 ** This callback is invoked once for each index when reading the
601 ** sqlite_stat1 table.
602 **
603 ** argv[0] = name of the table
604 ** argv[1] = name of the index (might be NULL)
605 ** argv[2] = results of analysis - on integer for each column
606 **
607 ** Entries for which argv[1]==NULL simply record the number of rows in
608 ** the table.
609 */
610 static int analysisLoader( object pData, sqlite3_int64 argc, object Oargv, object NotUsed )
611 {
612 string[] argv = (string[])Oargv;
613 analysisInfo pInfo = (analysisInfo)pData;
614 Index pIndex;
615 Table pTable;
616 int i, c, n;
617 int v;
618 string z;
619  
620 Debug.Assert( argc == 3 );
621 UNUSED_PARAMETER2( NotUsed, argc );
622 if ( argv == null || argv[0] == null || argv[2] == null )
623 {
624 return 0;
625 }
626 pTable = sqlite3FindTable( pInfo.db, argv[0], pInfo.zDatabase );
627 if ( pTable == null )
628 {
629 return 0;
630 }
631 if ( !string.IsNullOrEmpty( argv[1] ) )
632 {
633 pIndex = sqlite3FindIndex( pInfo.db, argv[1], pInfo.zDatabase );
634 }
635 else
636 {
637 pIndex = null;
638 }
639  
640 n = pIndex != null ? pIndex.nColumn : 0;
641 z = argv[2];
642 int zIndex = 0;
643 for ( i = 0; z != null && i <= n; i++ )
644 {
645 v = 0;
646 while ( zIndex < z.Length && ( c = z[zIndex] ) >= '0' && c <= '9' )
647 {
648 v = v * 10 + c - '0';
649 zIndex++;
650 }
651 if ( i == 0 )
652 pTable.nRowEst = (uint)v;
653 if ( pIndex == null )
654 break;
655 pIndex.aiRowEst[i] = v;
656 if ( zIndex < z.Length && z[zIndex] == ' ' )
657 zIndex++;
658 if ( z.Substring(zIndex).CompareTo("unordered")==0)//memcmp( z, "unordered", 10 ) == 0 )
659 {
660 pIndex.bUnordered = 1;
661 break;
662 }
663 }
664 return 0;
665 }
666  
667 /*
668 ** If the Index.aSample variable is not NULL, delete the aSample[] array
669 ** and its contents.
670 */
671 static void sqlite3DeleteIndexSamples( sqlite3 db, Index pIdx )
672 {
673 #if SQLITE_ENABLE_STAT2
674 if ( pIdx.aSample != null )
675 {
676 int j;
677 for ( j = 0; j < SQLITE_INDEX_SAMPLES; j++ )
678 {
679 IndexSample p = pIdx.aSample[j];
680 if ( p.eType == SQLITE_TEXT || p.eType == SQLITE_BLOB )
681 {
682 p.u.z = null;//sqlite3DbFree(db, p.u.z);
683 p.u.zBLOB = null;
684 }
685 }
686 sqlite3DbFree( db, ref pIdx.aSample );
687 }
688 #else
689 UNUSED_PARAMETER(db);
690 UNUSED_PARAMETER( pIdx );
691 #endif
692 }
693  
694 /*
695 ** Load the content of the sqlite_stat1 and sqlite_stat2 tables. The
696 ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[]
697 ** arrays. The contents of sqlite_stat2 are used to populate the
698 ** Index.aSample[] arrays.
699 **
700 ** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR
701 ** is returned. In this case, even if SQLITE_ENABLE_STAT2 was defined
702 ** during compilation and the sqlite_stat2 table is present, no data is
703 ** read from it.
704 **
705 ** If SQLITE_ENABLE_STAT2 was defined during compilation and the
706 ** sqlite_stat2 table is not present in the database, SQLITE_ERROR is
707 ** returned. However, in this case, data is read from the sqlite_stat1
708 ** table (if it is present) before returning.
709 **
710 ** If an OOM error occurs, this function always sets db.mallocFailed.
711 ** This means if the caller does not care about other errors, the return
712 ** code may be ignored.
713 */
714 static int sqlite3AnalysisLoad( sqlite3 db, int iDb )
715 {
716 analysisInfo sInfo;
717 HashElem i;
718 string zSql;
719 int rc;
720  
721 Debug.Assert( iDb >= 0 && iDb < db.nDb );
722 Debug.Assert( db.aDb[iDb].pBt != null );
723 /* Clear any prior statistics */
724 Debug.Assert( sqlite3SchemaMutexHeld( db, iDb, null ) );
725 //for(i=sqliteHashFirst(&db.aDb[iDb].pSchema.idxHash);i;i=sqliteHashNext(i)){
726 for ( i = db.aDb[iDb].pSchema.idxHash.first; i != null; i = i.next )
727 {
728 Index pIdx = (Index)i.data;// sqliteHashData( i );
729 sqlite3DefaultRowEst( pIdx );
730 sqlite3DeleteIndexSamples( db, pIdx );
731 pIdx.aSample = null;
732 }
733  
734 /* Check to make sure the sqlite_stat1 table exists */
735 sInfo.db = db;
736 sInfo.zDatabase = db.aDb[iDb].zName;
737 if ( sqlite3FindTable( db, "sqlite_stat1", sInfo.zDatabase ) == null )
738 {
739 return SQLITE_ERROR;
740 }
741  
742  
743 /* Load new statistics out of the sqlite_stat1 table */
744 zSql = sqlite3MPrintf( db,
745 "SELECT tbl, idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase );
746 //if ( zSql == null )
747 //{
748 // rc = SQLITE_NOMEM;
749 //}
750 //else
751 {
752 rc = sqlite3_exec( db, zSql, (dxCallback)analysisLoader, sInfo, 0 );
753 sqlite3DbFree( db, ref zSql );
754 }
755  
756  
757 /* Load the statistics from the sqlite_stat2 table. */
758 #if SQLITE_ENABLE_STAT2
759 if ( rc == SQLITE_OK && null == sqlite3FindTable( db, "sqlite_stat2", sInfo.zDatabase ) )
760 {
761 rc = SQLITE_ERROR;
762 }
763 if ( rc == SQLITE_OK )
764 {
765 sqlite3_stmt pStmt = null;
766  
767 zSql = sqlite3MPrintf( db,
768 "SELECT idx,sampleno,sample FROM %Q.sqlite_stat2", sInfo.zDatabase );
769 //if( null==zSql ){
770 //rc = SQLITE_NOMEM;
771 //}else{
772 rc = sqlite3_prepare( db, zSql, -1, ref pStmt, 0 );
773 sqlite3DbFree( db, ref zSql );
774 //}
775  
776 if ( rc == SQLITE_OK )
777 {
778 while ( sqlite3_step( pStmt ) == SQLITE_ROW )
779 {
780 string zIndex; /* Index name */
781 Index pIdx; /* Pointer to the index object */
782 zIndex = sqlite3_column_text( pStmt, 0 );
783 pIdx = !string.IsNullOrEmpty( zIndex ) ? sqlite3FindIndex( db, zIndex, sInfo.zDatabase ) : null;
784 if ( pIdx != null )
785 {
786 int iSample = sqlite3_column_int( pStmt, 1 );
787 if ( iSample < SQLITE_INDEX_SAMPLES && iSample >= 0 )
788 {
789 int eType = sqlite3_column_type( pStmt, 2 );
790  
791 if ( pIdx.aSample == null )
792 {
793 //static const int sz = sizeof(IndexSample)*SQLITE_INDEX_SAMPLES;
794 //pIdx->aSample = (IndexSample )sqlite3DbMallocRaw(0, sz);
795 //if( pIdx.aSample==0 ){
796 //db.mallocFailed = 1;
797 //break;
798 //}
799 pIdx.aSample = new IndexSample[SQLITE_INDEX_SAMPLES];//memset(pIdx->aSample, 0, sz);
800 }
801  
802 //Debug.Assert( pIdx.aSample != null );
803 if ( pIdx.aSample[iSample] == null )
804 pIdx.aSample[iSample] = new IndexSample();
805 IndexSample pSample = pIdx.aSample[iSample];
806 {
807 pSample.eType = (u8)eType;
808 if ( eType == SQLITE_INTEGER || eType == SQLITE_FLOAT )
809 {
810 pSample.u.r = sqlite3_column_double( pStmt, 2 );
811 }
812 else if ( eType == SQLITE_TEXT || eType == SQLITE_BLOB )
813 {
814 string z = null;
815 byte[] zBLOB = null;
816 //string z = (string )(
817 //(eType==SQLITE_BLOB) ?
818 //sqlite3_column_blob(pStmt, 2):
819 //sqlite3_column_text(pStmt, 2)
820 //);
821 if ( eType == SQLITE_BLOB )
822 zBLOB = sqlite3_column_blob( pStmt, 2 );
823 else
824 z = sqlite3_column_text( pStmt, 2 );
825 int n = sqlite3_column_bytes( pStmt, 2 );
826 if ( n > 24 )
827 {
828 n = 24;
829 }
830 pSample.nByte = (u8)n;
831 if ( n < 1 )
832 {
833 pSample.u.z = null;
834 pSample.u.zBLOB = null;
835 }
836 else
837 {
838 pSample.u.z = z;
839 pSample.u.zBLOB = zBLOB;
840 //pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
841 //if( pSample->u.z ){
842 // memcpy(pSample->u.z, z, n);
843 //}else{
844 // db->mallocFailed = 1;
845 // break;
846 //}
847 }
848 }
849 }
850 }
851 }
852 }
853 rc = sqlite3_finalize( pStmt );
854 }
855 }
856 #endif
857  
858 //if( rc==SQLITE_NOMEM ){
859 // db.mallocFailed = 1;
860 //}
861 return rc;
862 }
863  
864 #endif // * SQLITE_OMIT_ANALYZE */
865 }
866 }