Annotation of embedaddon/php/ext/sqlite/libsqlite/src/pragma.c, revision 1.1.1.1
1.1 misho 1: /*
2: ** 2003 April 6
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 used to implement the PRAGMA command.
13: **
14: ** $Id: pragma.c 195361 2005-09-07 15:11:33Z iliaa $
15: */
16: #include "sqliteInt.h"
17: #include <ctype.h>
18:
19: /*
20: ** Interpret the given string as a boolean value.
21: */
22: static int getBoolean(const char *z){
23: static char *azTrue[] = { "yes", "on", "true" };
24: int i;
25: if( z[0]==0 ) return 0;
26: if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
27: return atoi(z);
28: }
29: for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
30: if( sqliteStrICmp(z,azTrue[i])==0 ) return 1;
31: }
32: return 0;
33: }
34:
35: /*
36: ** Interpret the given string as a safety level. Return 0 for OFF,
37: ** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
38: ** unrecognized string argument.
39: **
40: ** Note that the values returned are one less that the values that
41: ** should be passed into sqliteBtreeSetSafetyLevel(). The is done
42: ** to support legacy SQL code. The safety level used to be boolean
43: ** and older scripts may have used numbers 0 for OFF and 1 for ON.
44: */
45: static int getSafetyLevel(char *z){
46: static const struct {
47: const char *zWord;
48: int val;
49: } aKey[] = {
50: { "no", 0 },
51: { "off", 0 },
52: { "false", 0 },
53: { "yes", 1 },
54: { "on", 1 },
55: { "true", 1 },
56: { "full", 2 },
57: };
58: int i;
59: if( z[0]==0 ) return 1;
60: if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
61: return atoi(z);
62: }
63: for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
64: if( sqliteStrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
65: }
66: return 1;
67: }
68:
69: /*
70: ** Interpret the given string as a temp db location. Return 1 for file
71: ** backed temporary databases, 2 for the Red-Black tree in memory database
72: ** and 0 to use the compile-time default.
73: */
74: static int getTempStore(const char *z){
75: if( z[0]>='0' && z[0]<='2' ){
76: return z[0] - '0';
77: }else if( sqliteStrICmp(z, "file")==0 ){
78: return 1;
79: }else if( sqliteStrICmp(z, "memory")==0 ){
80: return 2;
81: }else{
82: return 0;
83: }
84: }
85:
86: /*
87: ** If the TEMP database is open, close it and mark the database schema
88: ** as needing reloading. This must be done when using the TEMP_STORE
89: ** or DEFAULT_TEMP_STORE pragmas.
90: */
91: static int changeTempStorage(Parse *pParse, const char *zStorageType){
92: int ts = getTempStore(zStorageType);
93: sqlite *db = pParse->db;
94: if( db->temp_store==ts ) return SQLITE_OK;
95: if( db->aDb[1].pBt!=0 ){
96: if( db->flags & SQLITE_InTrans ){
97: sqliteErrorMsg(pParse, "temporary storage cannot be changed "
98: "from within a transaction");
99: return SQLITE_ERROR;
100: }
101: sqliteBtreeClose(db->aDb[1].pBt);
102: db->aDb[1].pBt = 0;
103: sqliteResetInternalSchema(db, 0);
104: }
105: db->temp_store = ts;
106: return SQLITE_OK;
107: }
108:
109: /*
110: ** Check to see if zRight and zLeft refer to a pragma that queries
111: ** or changes one of the flags in db->flags. Return 1 if so and 0 if not.
112: ** Also, implement the pragma.
113: */
114: static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
115: static const struct {
116: const char *zName; /* Name of the pragma */
117: int mask; /* Mask for the db->flags value */
118: } aPragma[] = {
119: { "vdbe_trace", SQLITE_VdbeTrace },
120: { "full_column_names", SQLITE_FullColNames },
121: { "short_column_names", SQLITE_ShortColNames },
122: { "show_datatypes", SQLITE_ReportTypes },
123: { "count_changes", SQLITE_CountRows },
124: { "empty_result_callbacks", SQLITE_NullCallback },
125: };
126: int i;
127: for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
128: if( sqliteStrICmp(zLeft, aPragma[i].zName)==0 ){
129: sqlite *db = pParse->db;
130: Vdbe *v;
131: if( strcmp(zLeft,zRight)==0 && (v = sqliteGetVdbe(pParse))!=0 ){
132: sqliteVdbeOp3(v, OP_ColumnName, 0, 1, aPragma[i].zName, P3_STATIC);
133: sqliteVdbeOp3(v, OP_ColumnName, 1, 0, "boolean", P3_STATIC);
134: sqliteVdbeCode(v, OP_Integer, (db->flags & aPragma[i].mask)!=0, 0,
135: OP_Callback, 1, 0,
136: 0);
137: }else if( getBoolean(zRight) ){
138: db->flags |= aPragma[i].mask;
139: }else{
140: db->flags &= ~aPragma[i].mask;
141: }
142: return 1;
143: }
144: }
145: return 0;
146: }
147:
148: /*
149: ** Process a pragma statement.
150: **
151: ** Pragmas are of this form:
152: **
153: ** PRAGMA id = value
154: **
155: ** The identifier might also be a string. The value is a string, and
156: ** identifier, or a number. If minusFlag is true, then the value is
157: ** a number that was preceded by a minus sign.
158: */
159: void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
160: char *zLeft = 0;
161: char *zRight = 0;
162: sqlite *db = pParse->db;
163: Vdbe *v = sqliteGetVdbe(pParse);
164: if( v==0 ) return;
165:
166: zLeft = sqliteStrNDup(pLeft->z, pLeft->n);
167: sqliteDequote(zLeft);
168: if( minusFlag ){
169: zRight = 0;
170: sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0);
171: }else{
172: zRight = sqliteStrNDup(pRight->z, pRight->n);
173: sqliteDequote(zRight);
174: }
175: if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, 0) ){
176: sqliteFree(zLeft);
177: sqliteFree(zRight);
178: return;
179: }
180:
181: /*
182: ** PRAGMA default_cache_size
183: ** PRAGMA default_cache_size=N
184: **
185: ** The first form reports the current persistent setting for the
186: ** page cache size. The value returned is the maximum number of
187: ** pages in the page cache. The second form sets both the current
188: ** page cache size value and the persistent page cache size value
189: ** stored in the database file.
190: **
191: ** The default cache size is stored in meta-value 2 of page 1 of the
192: ** database file. The cache size is actually the absolute value of
193: ** this memory location. The sign of meta-value 2 determines the
194: ** synchronous setting. A negative value means synchronous is off
195: ** and a positive value means synchronous is on.
196: */
197: if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
198: static VdbeOpList getCacheSize[] = {
199: { OP_ReadCookie, 0, 2, 0},
200: { OP_AbsValue, 0, 0, 0},
201: { OP_Dup, 0, 0, 0},
202: { OP_Integer, 0, 0, 0},
203: { OP_Ne, 0, 6, 0},
204: { OP_Integer, 0, 0, 0}, /* 5 */
205: { OP_ColumnName, 0, 1, "cache_size"},
206: { OP_Callback, 1, 0, 0},
207: };
208: int addr;
209: if( pRight->z==pLeft->z ){
210: addr = sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
211: sqliteVdbeChangeP1(v, addr+5, MAX_PAGES);
212: }else{
213: int size = atoi(zRight);
214: if( size<0 ) size = -size;
215: sqliteBeginWriteOperation(pParse, 0, 0);
216: sqliteVdbeAddOp(v, OP_Integer, size, 0);
217: sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
218: addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
219: sqliteVdbeAddOp(v, OP_Ge, 0, addr+3);
220: sqliteVdbeAddOp(v, OP_Negative, 0, 0);
221: sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
222: sqliteEndWriteOperation(pParse);
223: db->cache_size = db->cache_size<0 ? -size : size;
224: sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
225: }
226: }else
227:
228: /*
229: ** PRAGMA cache_size
230: ** PRAGMA cache_size=N
231: **
232: ** The first form reports the current local setting for the
233: ** page cache size. The local setting can be different from
234: ** the persistent cache size value that is stored in the database
235: ** file itself. The value returned is the maximum number of
236: ** pages in the page cache. The second form sets the local
237: ** page cache size value. It does not change the persistent
238: ** cache size stored on the disk so the cache size will revert
239: ** to its default value when the database is closed and reopened.
240: ** N should be a positive integer.
241: */
242: if( sqliteStrICmp(zLeft,"cache_size")==0 ){
243: static VdbeOpList getCacheSize[] = {
244: { OP_ColumnName, 0, 1, "cache_size"},
245: { OP_Callback, 1, 0, 0},
246: };
247: if( pRight->z==pLeft->z ){
248: int size = db->cache_size;;
249: if( size<0 ) size = -size;
250: sqliteVdbeAddOp(v, OP_Integer, size, 0);
251: sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
252: }else{
253: int size = atoi(zRight);
254: if( size<0 ) size = -size;
255: if( db->cache_size<0 ) size = -size;
256: db->cache_size = size;
257: sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
258: }
259: }else
260:
261: /*
262: ** PRAGMA default_synchronous
263: ** PRAGMA default_synchronous=ON|OFF|NORMAL|FULL
264: **
265: ** The first form returns the persistent value of the "synchronous" setting
266: ** that is stored in the database. This is the synchronous setting that
267: ** is used whenever the database is opened unless overridden by a separate
268: ** "synchronous" pragma. The second form changes the persistent and the
269: ** local synchronous setting to the value given.
270: **
271: ** If synchronous is OFF, SQLite does not attempt any fsync() systems calls
272: ** to make sure data is committed to disk. Write operations are very fast,
273: ** but a power failure can leave the database in an inconsistent state.
274: ** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to
275: ** make sure data is being written to disk. The risk of corruption due to
276: ** a power loss in this mode is negligible but non-zero. If synchronous
277: ** is FULL, extra fsync()s occur to reduce the risk of corruption to near
278: ** zero, but with a write performance penalty. The default mode is NORMAL.
279: */
280: if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
281: static VdbeOpList getSync[] = {
282: { OP_ColumnName, 0, 1, "synchronous"},
283: { OP_ReadCookie, 0, 3, 0},
284: { OP_Dup, 0, 0, 0},
285: { OP_If, 0, 0, 0}, /* 3 */
286: { OP_ReadCookie, 0, 2, 0},
287: { OP_Integer, 0, 0, 0},
288: { OP_Lt, 0, 5, 0},
289: { OP_AddImm, 1, 0, 0},
290: { OP_Callback, 1, 0, 0},
291: { OP_Halt, 0, 0, 0},
292: { OP_AddImm, -1, 0, 0}, /* 10 */
293: { OP_Callback, 1, 0, 0}
294: };
295: if( pRight->z==pLeft->z ){
296: int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
297: sqliteVdbeChangeP2(v, addr+3, addr+10);
298: }else{
299: int addr;
300: int size = db->cache_size;
301: if( size<0 ) size = -size;
302: sqliteBeginWriteOperation(pParse, 0, 0);
303: sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
304: sqliteVdbeAddOp(v, OP_Dup, 0, 0);
305: addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
306: sqliteVdbeAddOp(v, OP_Ne, 0, addr+3);
307: sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0);
308: sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
309: db->safety_level = getSafetyLevel(zRight)+1;
310: if( db->safety_level==1 ){
311: sqliteVdbeAddOp(v, OP_Negative, 0, 0);
312: size = -size;
313: }
314: sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
315: sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0);
316: sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
317: sqliteEndWriteOperation(pParse);
318: db->cache_size = size;
319: sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
320: sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
321: }
322: }else
323:
324: /*
325: ** PRAGMA synchronous
326: ** PRAGMA synchronous=OFF|ON|NORMAL|FULL
327: **
328: ** Return or set the local value of the synchronous flag. Changing
329: ** the local value does not make changes to the disk file and the
330: ** default value will be restored the next time the database is
331: ** opened.
332: */
333: if( sqliteStrICmp(zLeft,"synchronous")==0 ){
334: static VdbeOpList getSync[] = {
335: { OP_ColumnName, 0, 1, "synchronous"},
336: { OP_Callback, 1, 0, 0},
337: };
338: if( pRight->z==pLeft->z ){
339: sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0);
340: sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
341: }else{
342: int size = db->cache_size;
343: if( size<0 ) size = -size;
344: db->safety_level = getSafetyLevel(zRight)+1;
345: if( db->safety_level==1 ) size = -size;
346: db->cache_size = size;
347: sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
348: sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
349: }
350: }else
351:
352: #ifndef NDEBUG
353: if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){
354: if( getBoolean(zRight) ){
355: always_code_trigger_setup = 1;
356: }else{
357: always_code_trigger_setup = 0;
358: }
359: }else
360: #endif
361:
362: if( flagPragma(pParse, zLeft, zRight) ){
363: /* The flagPragma() call also generates any necessary code */
364: }else
365:
366: if( sqliteStrICmp(zLeft, "table_info")==0 ){
367: Table *pTab;
368: pTab = sqliteFindTable(db, zRight, 0);
369: if( pTab ){
370: static VdbeOpList tableInfoPreface[] = {
371: { OP_ColumnName, 0, 0, "cid"},
372: { OP_ColumnName, 1, 0, "name"},
373: { OP_ColumnName, 2, 0, "type"},
374: { OP_ColumnName, 3, 0, "notnull"},
375: { OP_ColumnName, 4, 0, "dflt_value"},
376: { OP_ColumnName, 5, 1, "pk"},
377: };
378: int i;
379: sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
380: sqliteViewGetColumnNames(pParse, pTab);
381: for(i=0; i<pTab->nCol; i++){
382: sqliteVdbeAddOp(v, OP_Integer, i, 0);
383: sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zName, 0);
384: sqliteVdbeOp3(v, OP_String, 0, 0,
385: pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
386: sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
387: sqliteVdbeOp3(v, OP_String, 0, 0,
388: pTab->aCol[i].zDflt, P3_STATIC);
389: sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
390: sqliteVdbeAddOp(v, OP_Callback, 6, 0);
391: }
392: }
393: }else
394:
395: if( sqliteStrICmp(zLeft, "index_info")==0 ){
396: Index *pIdx;
397: Table *pTab;
398: pIdx = sqliteFindIndex(db, zRight, 0);
399: if( pIdx ){
400: static VdbeOpList tableInfoPreface[] = {
401: { OP_ColumnName, 0, 0, "seqno"},
402: { OP_ColumnName, 1, 0, "cid"},
403: { OP_ColumnName, 2, 1, "name"},
404: };
405: int i;
406: pTab = pIdx->pTable;
407: sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
408: for(i=0; i<pIdx->nColumn; i++){
409: int cnum = pIdx->aiColumn[i];
410: sqliteVdbeAddOp(v, OP_Integer, i, 0);
411: sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
412: assert( pTab->nCol>cnum );
413: sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[cnum].zName, 0);
414: sqliteVdbeAddOp(v, OP_Callback, 3, 0);
415: }
416: }
417: }else
418:
419: if( sqliteStrICmp(zLeft, "index_list")==0 ){
420: Index *pIdx;
421: Table *pTab;
422: pTab = sqliteFindTable(db, zRight, 0);
423: if( pTab ){
424: v = sqliteGetVdbe(pParse);
425: pIdx = pTab->pIndex;
426: }
427: if( pTab && pIdx ){
428: int i = 0;
429: static VdbeOpList indexListPreface[] = {
430: { OP_ColumnName, 0, 0, "seq"},
431: { OP_ColumnName, 1, 0, "name"},
432: { OP_ColumnName, 2, 1, "unique"},
433: };
434:
435: sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
436: while(pIdx){
437: sqliteVdbeAddOp(v, OP_Integer, i, 0);
438: sqliteVdbeOp3(v, OP_String, 0, 0, pIdx->zName, 0);
439: sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
440: sqliteVdbeAddOp(v, OP_Callback, 3, 0);
441: ++i;
442: pIdx = pIdx->pNext;
443: }
444: }
445: }else
446:
447: if( sqliteStrICmp(zLeft, "foreign_key_list")==0 ){
448: FKey *pFK;
449: Table *pTab;
450: pTab = sqliteFindTable(db, zRight, 0);
451: if( pTab ){
452: v = sqliteGetVdbe(pParse);
453: pFK = pTab->pFKey;
454: }
455: if( pTab && pFK ){
456: int i = 0;
457: static VdbeOpList indexListPreface[] = {
458: { OP_ColumnName, 0, 0, "id"},
459: { OP_ColumnName, 1, 0, "seq"},
460: { OP_ColumnName, 2, 0, "table"},
461: { OP_ColumnName, 3, 0, "from"},
462: { OP_ColumnName, 4, 1, "to"},
463: };
464:
465: sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
466: while(pFK){
467: int j;
468: for(j=0; j<pFK->nCol; j++){
469: sqliteVdbeAddOp(v, OP_Integer, i, 0);
470: sqliteVdbeAddOp(v, OP_Integer, j, 0);
471: sqliteVdbeOp3(v, OP_String, 0, 0, pFK->zTo, 0);
472: sqliteVdbeOp3(v, OP_String, 0, 0,
473: pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
474: sqliteVdbeOp3(v, OP_String, 0, 0, pFK->aCol[j].zCol, 0);
475: sqliteVdbeAddOp(v, OP_Callback, 5, 0);
476: }
477: ++i;
478: pFK = pFK->pNextFrom;
479: }
480: }
481: }else
482:
483: if( sqliteStrICmp(zLeft, "database_list")==0 ){
484: int i;
485: static VdbeOpList indexListPreface[] = {
486: { OP_ColumnName, 0, 0, "seq"},
487: { OP_ColumnName, 1, 0, "name"},
488: { OP_ColumnName, 2, 1, "file"},
489: };
490:
491: sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
492: for(i=0; i<db->nDb; i++){
493: if( db->aDb[i].pBt==0 ) continue;
494: assert( db->aDb[i].zName!=0 );
495: sqliteVdbeAddOp(v, OP_Integer, i, 0);
496: sqliteVdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, 0);
497: sqliteVdbeOp3(v, OP_String, 0, 0,
498: sqliteBtreeGetFilename(db->aDb[i].pBt), 0);
499: sqliteVdbeAddOp(v, OP_Callback, 3, 0);
500: }
501: }else
502:
503:
504: /*
505: ** PRAGMA temp_store
506: ** PRAGMA temp_store = "default"|"memory"|"file"
507: **
508: ** Return or set the local value of the temp_store flag. Changing
509: ** the local value does not make changes to the disk file and the default
510: ** value will be restored the next time the database is opened.
511: **
512: ** Note that it is possible for the library compile-time options to
513: ** override this setting
514: */
515: if( sqliteStrICmp(zLeft, "temp_store")==0 ){
516: static VdbeOpList getTmpDbLoc[] = {
517: { OP_ColumnName, 0, 1, "temp_store"},
518: { OP_Callback, 1, 0, 0},
519: };
520: if( pRight->z==pLeft->z ){
521: sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0);
522: sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
523: }else{
524: changeTempStorage(pParse, zRight);
525: }
526: }else
527:
528: /*
529: ** PRAGMA default_temp_store
530: ** PRAGMA default_temp_store = "default"|"memory"|"file"
531: **
532: ** Return or set the value of the persistent temp_store flag. Any
533: ** change does not take effect until the next time the database is
534: ** opened.
535: **
536: ** Note that it is possible for the library compile-time options to
537: ** override this setting
538: */
539: if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){
540: static VdbeOpList getTmpDbLoc[] = {
541: { OP_ColumnName, 0, 1, "temp_store"},
542: { OP_ReadCookie, 0, 5, 0},
543: { OP_Callback, 1, 0, 0}};
544: if( pRight->z==pLeft->z ){
545: sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
546: }else{
547: sqliteBeginWriteOperation(pParse, 0, 0);
548: sqliteVdbeAddOp(v, OP_Integer, getTempStore(zRight), 0);
549: sqliteVdbeAddOp(v, OP_SetCookie, 0, 5);
550: sqliteEndWriteOperation(pParse);
551: }
552: }else
553:
554: #ifndef NDEBUG
555: if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
556: extern void sqliteParserTrace(FILE*, char *);
557: if( getBoolean(zRight) ){
558: sqliteParserTrace(stdout, "parser: ");
559: }else{
560: sqliteParserTrace(0, 0);
561: }
562: }else
563: #endif
564:
565: if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
566: int i, j, addr;
567:
568: /* Code that initializes the integrity check program. Set the
569: ** error count 0
570: */
571: static VdbeOpList initCode[] = {
572: { OP_Integer, 0, 0, 0},
573: { OP_MemStore, 0, 1, 0},
574: { OP_ColumnName, 0, 1, "integrity_check"},
575: };
576:
577: /* Code to do an BTree integrity check on a single database file.
578: */
579: static VdbeOpList checkDb[] = {
580: { OP_SetInsert, 0, 0, "2"},
581: { OP_Integer, 0, 0, 0}, /* 1 */
582: { OP_OpenRead, 0, 2, 0},
583: { OP_Rewind, 0, 7, 0}, /* 3 */
584: { OP_Column, 0, 3, 0}, /* 4 */
585: { OP_SetInsert, 0, 0, 0},
586: { OP_Next, 0, 4, 0}, /* 6 */
587: { OP_IntegrityCk, 0, 0, 0}, /* 7 */
588: { OP_Dup, 0, 1, 0},
589: { OP_String, 0, 0, "ok"},
590: { OP_StrEq, 0, 12, 0}, /* 10 */
591: { OP_MemIncr, 0, 0, 0},
592: { OP_String, 0, 0, "*** in database "},
593: { OP_String, 0, 0, 0}, /* 13 */
594: { OP_String, 0, 0, " ***\n"},
595: { OP_Pull, 3, 0, 0},
596: { OP_Concat, 4, 1, 0},
597: { OP_Callback, 1, 0, 0},
598: };
599:
600: /* Code that appears at the end of the integrity check. If no error
601: ** messages have been generated, output OK. Otherwise output the
602: ** error message
603: */
604: static VdbeOpList endCode[] = {
605: { OP_MemLoad, 0, 0, 0},
606: { OP_Integer, 0, 0, 0},
607: { OP_Ne, 0, 0, 0}, /* 2 */
608: { OP_String, 0, 0, "ok"},
609: { OP_Callback, 1, 0, 0},
610: };
611:
612: /* Initialize the VDBE program */
613: sqliteVdbeAddOpList(v, ArraySize(initCode), initCode);
614:
615: /* Do an integrity check on each database file */
616: for(i=0; i<db->nDb; i++){
617: HashElem *x;
618:
619: /* Do an integrity check of the B-Tree
620: */
621: addr = sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
622: sqliteVdbeChangeP1(v, addr+1, i);
623: sqliteVdbeChangeP2(v, addr+3, addr+7);
624: sqliteVdbeChangeP2(v, addr+6, addr+4);
625: sqliteVdbeChangeP2(v, addr+7, i);
626: sqliteVdbeChangeP2(v, addr+10, addr+ArraySize(checkDb));
627: sqliteVdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC);
628:
629: /* Make sure all the indices are constructed correctly.
630: */
631: sqliteCodeVerifySchema(pParse, i);
632: for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
633: Table *pTab = sqliteHashData(x);
634: Index *pIdx;
635: int loopTop;
636:
637: if( pTab->pIndex==0 ) continue;
638: sqliteVdbeAddOp(v, OP_Integer, i, 0);
639: sqliteVdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0);
640: for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
641: if( pIdx->tnum==0 ) continue;
642: sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
643: sqliteVdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0);
644: }
645: sqliteVdbeAddOp(v, OP_Integer, 0, 0);
646: sqliteVdbeAddOp(v, OP_MemStore, 1, 1);
647: loopTop = sqliteVdbeAddOp(v, OP_Rewind, 1, 0);
648: sqliteVdbeAddOp(v, OP_MemIncr, 1, 0);
649: for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
650: int k, jmp2;
651: static VdbeOpList idxErr[] = {
652: { OP_MemIncr, 0, 0, 0},
653: { OP_String, 0, 0, "rowid "},
654: { OP_Recno, 1, 0, 0},
655: { OP_String, 0, 0, " missing from index "},
656: { OP_String, 0, 0, 0}, /* 4 */
657: { OP_Concat, 4, 0, 0},
658: { OP_Callback, 1, 0, 0},
659: };
660: sqliteVdbeAddOp(v, OP_Recno, 1, 0);
661: for(k=0; k<pIdx->nColumn; k++){
662: int idx = pIdx->aiColumn[k];
663: if( idx==pTab->iPKey ){
664: sqliteVdbeAddOp(v, OP_Recno, 1, 0);
665: }else{
666: sqliteVdbeAddOp(v, OP_Column, 1, idx);
667: }
668: }
669: sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
670: if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
671: jmp2 = sqliteVdbeAddOp(v, OP_Found, j+2, 0);
672: addr = sqliteVdbeAddOpList(v, ArraySize(idxErr), idxErr);
673: sqliteVdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
674: sqliteVdbeChangeP2(v, jmp2, sqliteVdbeCurrentAddr(v));
675: }
676: sqliteVdbeAddOp(v, OP_Next, 1, loopTop+1);
677: sqliteVdbeChangeP2(v, loopTop, sqliteVdbeCurrentAddr(v));
678: for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
679: static VdbeOpList cntIdx[] = {
680: { OP_Integer, 0, 0, 0},
681: { OP_MemStore, 2, 1, 0},
682: { OP_Rewind, 0, 0, 0}, /* 2 */
683: { OP_MemIncr, 2, 0, 0},
684: { OP_Next, 0, 0, 0}, /* 4 */
685: { OP_MemLoad, 1, 0, 0},
686: { OP_MemLoad, 2, 0, 0},
687: { OP_Eq, 0, 0, 0}, /* 7 */
688: { OP_MemIncr, 0, 0, 0},
689: { OP_String, 0, 0, "wrong # of entries in index "},
690: { OP_String, 0, 0, 0}, /* 10 */
691: { OP_Concat, 2, 0, 0},
692: { OP_Callback, 1, 0, 0},
693: };
694: if( pIdx->tnum==0 ) continue;
695: addr = sqliteVdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
696: sqliteVdbeChangeP1(v, addr+2, j+2);
697: sqliteVdbeChangeP2(v, addr+2, addr+5);
698: sqliteVdbeChangeP1(v, addr+4, j+2);
699: sqliteVdbeChangeP2(v, addr+4, addr+3);
700: sqliteVdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
701: sqliteVdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
702: }
703: }
704: }
705: addr = sqliteVdbeAddOpList(v, ArraySize(endCode), endCode);
706: sqliteVdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
707: }else
708:
709: {}
710: sqliteFree(zLeft);
711: sqliteFree(zRight);
712: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>