xref: /sqlite-3.40.0/src/test2.c (revision 5130c31b)
1 /*
2 ** 2001 September 15
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 ** Code for testing the pager.c module in SQLite.  This code
13 ** is not included in the SQLite library.  It is used for automated
14 ** testing of the SQLite library.
15 */
16 #include "sqliteInt.h"
17 #include "tcl.h"
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 
22 /*
23 ** Interpret an SQLite error number
24 */
25 static char *errorName(int rc){
26   char *zName;
27   switch( rc ){
28     case SQLITE_OK:         zName = "SQLITE_OK";          break;
29     case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
30     case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
31     case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
32     case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
33     case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
34     case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
35     case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
36     case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
37     case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
38     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
39     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
40     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
41     case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
42     case SQLITE_SCHEMA:     zName = "SQLITE_SCHEMA";      break;
43     case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT";  break;
44     case SQLITE_MISMATCH:   zName = "SQLITE_MISMATCH";    break;
45     case SQLITE_MISUSE:     zName = "SQLITE_MISUSE";      break;
46     case SQLITE_NOLFS:      zName = "SQLITE_NOLFS";       break;
47     default:                zName = "SQLITE_Unknown";     break;
48   }
49   return zName;
50 }
51 
52 /*
53 ** Page size and reserved size used for testing.
54 */
55 static int test_pagesize = 1024;
56 
57 /*
58 ** Dummy page reinitializer
59 */
60 static void pager_test_reiniter(DbPage *pNotUsed){
61   return;
62 }
63 
64 /*
65 ** Usage:   pager_open FILENAME N-PAGE
66 **
67 ** Open a new pager
68 */
69 static int pager_open(
70   void *NotUsed,
71   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
72   int argc,              /* Number of arguments */
73   const char **argv      /* Text of each argument */
74 ){
75   u16 pageSize;
76   Pager *pPager;
77   int nPage;
78   int rc;
79   char zBuf[100];
80   if( argc!=3 ){
81     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
82        " FILENAME N-PAGE\"", 0);
83     return TCL_ERROR;
84   }
85   if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
86   rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0,
87       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
88       pager_test_reiniter);
89   if( rc!=SQLITE_OK ){
90     Tcl_AppendResult(interp, errorName(rc), 0);
91     return TCL_ERROR;
92   }
93   sqlite3PagerSetCachesize(pPager, nPage);
94   pageSize = test_pagesize;
95   sqlite3PagerSetPagesize(pPager, &pageSize, -1);
96   sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
97   Tcl_AppendResult(interp, zBuf, 0);
98   return TCL_OK;
99 }
100 
101 /*
102 ** Usage:   pager_close ID
103 **
104 ** Close the given pager.
105 */
106 static int pager_close(
107   void *NotUsed,
108   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
109   int argc,              /* Number of arguments */
110   const char **argv      /* Text of each argument */
111 ){
112   Pager *pPager;
113   int rc;
114   if( argc!=2 ){
115     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
116        " ID\"", 0);
117     return TCL_ERROR;
118   }
119   pPager = sqlite3TestTextToPtr(argv[1]);
120   rc = sqlite3PagerClose(pPager);
121   if( rc!=SQLITE_OK ){
122     Tcl_AppendResult(interp, errorName(rc), 0);
123     return TCL_ERROR;
124   }
125   return TCL_OK;
126 }
127 
128 /*
129 ** Usage:   pager_rollback ID
130 **
131 ** Rollback changes
132 */
133 static int pager_rollback(
134   void *NotUsed,
135   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
136   int argc,              /* Number of arguments */
137   const char **argv      /* Text of each argument */
138 ){
139   Pager *pPager;
140   int rc;
141   if( argc!=2 ){
142     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
143        " ID\"", 0);
144     return TCL_ERROR;
145   }
146   pPager = sqlite3TestTextToPtr(argv[1]);
147   rc = sqlite3PagerRollback(pPager);
148   if( rc!=SQLITE_OK ){
149     Tcl_AppendResult(interp, errorName(rc), 0);
150     return TCL_ERROR;
151   }
152   return TCL_OK;
153 }
154 
155 /*
156 ** Usage:   pager_commit ID
157 **
158 ** Commit all changes
159 */
160 static int pager_commit(
161   void *NotUsed,
162   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
163   int argc,              /* Number of arguments */
164   const char **argv      /* Text of each argument */
165 ){
166   Pager *pPager;
167   int rc;
168   if( argc!=2 ){
169     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
170        " ID\"", 0);
171     return TCL_ERROR;
172   }
173   pPager = sqlite3TestTextToPtr(argv[1]);
174   rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
175   if( rc!=SQLITE_OK ){
176     Tcl_AppendResult(interp, errorName(rc), 0);
177     return TCL_ERROR;
178   }
179   rc = sqlite3PagerCommitPhaseTwo(pPager);
180   if( rc!=SQLITE_OK ){
181     Tcl_AppendResult(interp, errorName(rc), 0);
182     return TCL_ERROR;
183   }
184   return TCL_OK;
185 }
186 
187 /*
188 ** Usage:   pager_stmt_begin ID
189 **
190 ** Start a new checkpoint.
191 */
192 static int pager_stmt_begin(
193   void *NotUsed,
194   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
195   int argc,              /* Number of arguments */
196   const char **argv      /* Text of each argument */
197 ){
198   Pager *pPager;
199   int rc;
200   if( argc!=2 ){
201     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
202        " ID\"", 0);
203     return TCL_ERROR;
204   }
205   pPager = sqlite3TestTextToPtr(argv[1]);
206   rc = sqlite3PagerOpenSavepoint(pPager, 1);
207   if( rc!=SQLITE_OK ){
208     Tcl_AppendResult(interp, errorName(rc), 0);
209     return TCL_ERROR;
210   }
211   return TCL_OK;
212 }
213 
214 /*
215 ** Usage:   pager_stmt_rollback ID
216 **
217 ** Rollback changes to a checkpoint
218 */
219 static int pager_stmt_rollback(
220   void *NotUsed,
221   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
222   int argc,              /* Number of arguments */
223   const char **argv      /* Text of each argument */
224 ){
225   Pager *pPager;
226   int rc;
227   if( argc!=2 ){
228     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
229        " ID\"", 0);
230     return TCL_ERROR;
231   }
232   pPager = sqlite3TestTextToPtr(argv[1]);
233   rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0);
234   sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
235   if( rc!=SQLITE_OK ){
236     Tcl_AppendResult(interp, errorName(rc), 0);
237     return TCL_ERROR;
238   }
239   return TCL_OK;
240 }
241 
242 /*
243 ** Usage:   pager_stmt_commit ID
244 **
245 ** Commit changes to a checkpoint
246 */
247 static int pager_stmt_commit(
248   void *NotUsed,
249   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
250   int argc,              /* Number of arguments */
251   const char **argv      /* Text of each argument */
252 ){
253   Pager *pPager;
254   int rc;
255   if( argc!=2 ){
256     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
257        " ID\"", 0);
258     return TCL_ERROR;
259   }
260   pPager = sqlite3TestTextToPtr(argv[1]);
261   rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
262   if( rc!=SQLITE_OK ){
263     Tcl_AppendResult(interp, errorName(rc), 0);
264     return TCL_ERROR;
265   }
266   return TCL_OK;
267 }
268 
269 /*
270 ** Usage:   pager_stats ID
271 **
272 ** Return pager statistics.
273 */
274 static int pager_stats(
275   void *NotUsed,
276   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
277   int argc,              /* Number of arguments */
278   const char **argv      /* Text of each argument */
279 ){
280   Pager *pPager;
281   int i, *a;
282   if( argc!=2 ){
283     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
284        " ID\"", 0);
285     return TCL_ERROR;
286   }
287   pPager = sqlite3TestTextToPtr(argv[1]);
288   a = sqlite3PagerStats(pPager);
289   for(i=0; i<9; i++){
290     static char *zName[] = {
291       "ref", "page", "max", "size", "state", "err",
292       "hit", "miss", "ovfl",
293     };
294     char zBuf[100];
295     Tcl_AppendElement(interp, zName[i]);
296     sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",a[i]);
297     Tcl_AppendElement(interp, zBuf);
298   }
299   return TCL_OK;
300 }
301 
302 /*
303 ** Usage:   pager_pagecount ID
304 **
305 ** Return the size of the database file.
306 */
307 static int pager_pagecount(
308   void *NotUsed,
309   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
310   int argc,              /* Number of arguments */
311   const char **argv      /* Text of each argument */
312 ){
313   Pager *pPager;
314   char zBuf[100];
315   int nPage;
316   if( argc!=2 ){
317     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
318        " ID\"", 0);
319     return TCL_ERROR;
320   }
321   pPager = sqlite3TestTextToPtr(argv[1]);
322   sqlite3PagerPagecount(pPager, &nPage);
323   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nPage);
324   Tcl_AppendResult(interp, zBuf, 0);
325   return TCL_OK;
326 }
327 
328 /*
329 ** Usage:   page_get ID PGNO
330 **
331 ** Return a pointer to a page from the database.
332 */
333 static int page_get(
334   void *NotUsed,
335   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
336   int argc,              /* Number of arguments */
337   const char **argv      /* Text of each argument */
338 ){
339   Pager *pPager;
340   char zBuf[100];
341   DbPage *pPage;
342   int pgno;
343   int rc;
344   if( argc!=3 ){
345     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
346        " ID PGNO\"", 0);
347     return TCL_ERROR;
348   }
349   pPager = sqlite3TestTextToPtr(argv[1]);
350   if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
351   rc = sqlite3PagerSharedLock(pPager);
352   if( rc==SQLITE_OK ){
353     rc = sqlite3PagerGet(pPager, pgno, &pPage);
354   }
355   if( rc!=SQLITE_OK ){
356     Tcl_AppendResult(interp, errorName(rc), 0);
357     return TCL_ERROR;
358   }
359   sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
360   Tcl_AppendResult(interp, zBuf, 0);
361   return TCL_OK;
362 }
363 
364 /*
365 ** Usage:   page_lookup ID PGNO
366 **
367 ** Return a pointer to a page if the page is already in cache.
368 ** If not in cache, return an empty string.
369 */
370 static int page_lookup(
371   void *NotUsed,
372   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
373   int argc,              /* Number of arguments */
374   const char **argv      /* Text of each argument */
375 ){
376   Pager *pPager;
377   char zBuf[100];
378   DbPage *pPage;
379   int pgno;
380   if( argc!=3 ){
381     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
382        " ID PGNO\"", 0);
383     return TCL_ERROR;
384   }
385   pPager = sqlite3TestTextToPtr(argv[1]);
386   if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
387   pPage = sqlite3PagerLookup(pPager, pgno);
388   if( pPage ){
389     sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
390     Tcl_AppendResult(interp, zBuf, 0);
391   }
392   return TCL_OK;
393 }
394 
395 /*
396 ** Usage:   pager_truncate ID PGNO
397 */
398 static int pager_truncate(
399   void *NotUsed,
400   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
401   int argc,              /* Number of arguments */
402   const char **argv      /* Text of each argument */
403 ){
404   Pager *pPager;
405   int pgno;
406   if( argc!=3 ){
407     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
408        " ID PGNO\"", 0);
409     return TCL_ERROR;
410   }
411   pPager = sqlite3TestTextToPtr(argv[1]);
412   if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
413   sqlite3PagerTruncateImage(pPager, pgno);
414   return TCL_OK;
415 }
416 
417 
418 /*
419 ** Usage:   page_unref PAGE
420 **
421 ** Drop a pointer to a page.
422 */
423 static int page_unref(
424   void *NotUsed,
425   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
426   int argc,              /* Number of arguments */
427   const char **argv      /* Text of each argument */
428 ){
429   DbPage *pPage;
430   if( argc!=2 ){
431     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
432        " PAGE\"", 0);
433     return TCL_ERROR;
434   }
435   pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
436   sqlite3PagerUnref(pPage);
437   return TCL_OK;
438 }
439 
440 /*
441 ** Usage:   page_read PAGE
442 **
443 ** Return the content of a page
444 */
445 static int page_read(
446   void *NotUsed,
447   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
448   int argc,              /* Number of arguments */
449   const char **argv      /* Text of each argument */
450 ){
451   char zBuf[100];
452   DbPage *pPage;
453   if( argc!=2 ){
454     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
455        " PAGE\"", 0);
456     return TCL_ERROR;
457   }
458   pPage = sqlite3TestTextToPtr(argv[1]);
459   memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf));
460   Tcl_AppendResult(interp, zBuf, 0);
461   return TCL_OK;
462 }
463 
464 /*
465 ** Usage:   page_number PAGE
466 **
467 ** Return the page number for a page.
468 */
469 static int page_number(
470   void *NotUsed,
471   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
472   int argc,              /* Number of arguments */
473   const char **argv      /* Text of each argument */
474 ){
475   char zBuf[100];
476   DbPage *pPage;
477   if( argc!=2 ){
478     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
479        " PAGE\"", 0);
480     return TCL_ERROR;
481   }
482   pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
483   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage));
484   Tcl_AppendResult(interp, zBuf, 0);
485   return TCL_OK;
486 }
487 
488 /*
489 ** Usage:   page_write PAGE DATA
490 **
491 ** Write something into a page.
492 */
493 static int page_write(
494   void *NotUsed,
495   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
496   int argc,              /* Number of arguments */
497   const char **argv      /* Text of each argument */
498 ){
499   DbPage *pPage;
500   char *pData;
501   int rc;
502   if( argc!=3 ){
503     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
504        " PAGE DATA\"", 0);
505     return TCL_ERROR;
506   }
507   pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
508   rc = sqlite3PagerWrite(pPage);
509   if( rc!=SQLITE_OK ){
510     Tcl_AppendResult(interp, errorName(rc), 0);
511     return TCL_ERROR;
512   }
513   pData = sqlite3PagerGetData(pPage);
514   strncpy(pData, argv[2], test_pagesize-1);
515   pData[test_pagesize-1] = 0;
516   return TCL_OK;
517 }
518 
519 #ifndef SQLITE_OMIT_DISKIO
520 /*
521 ** Usage:   fake_big_file  N  FILENAME
522 **
523 ** Write a few bytes at the N megabyte point of FILENAME.  This will
524 ** create a large file.  If the file was a valid SQLite database, then
525 ** the next time the database is opened, SQLite will begin allocating
526 ** new pages after N.  If N is 2096 or bigger, this will test the
527 ** ability of SQLite to write to large files.
528 */
529 static int fake_big_file(
530   void *NotUsed,
531   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
532   int argc,              /* Number of arguments */
533   const char **argv      /* Text of each argument */
534 ){
535   sqlite3_vfs *pVfs;
536   sqlite3_file *fd = 0;
537   int rc;
538   int n;
539   i64 offset;
540   if( argc!=3 ){
541     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
542        " N-MEGABYTES FILE\"", 0);
543     return TCL_ERROR;
544   }
545   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
546 
547   pVfs = sqlite3_vfs_find(0);
548   rc = sqlite3OsOpenMalloc(pVfs, argv[2], &fd,
549       (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0
550   );
551   if( rc ){
552     Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
553     return TCL_ERROR;
554   }
555   offset = n;
556   offset *= 1024*1024;
557   rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
558   sqlite3OsCloseFree(fd);
559   if( rc ){
560     Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
561     return TCL_ERROR;
562   }
563   return TCL_OK;
564 }
565 #endif
566 
567 
568 /*
569 ** test_control_pending_byte  PENDING_BYTE
570 **
571 ** Set the PENDING_BYTE using the sqlite3_test_control() interface.
572 */
573 static int testPendingByte(
574   void *NotUsed,
575   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
576   int argc,              /* Number of arguments */
577   const char **argv      /* Text of each argument */
578 ){
579   int pbyte;
580   int rc;
581   if( argc!=2 ){
582     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
583                      " PENDING-BYTE\"", (void*)0);
584     return TCL_ERROR;
585   }
586   if( Tcl_GetInt(interp, argv[1], &pbyte) ) return TCL_ERROR;
587   rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
588   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
589   return TCL_OK;
590 }
591 
592 /*
593 ** sqlite3BitvecBuiltinTest SIZE PROGRAM
594 **
595 ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
596 ** See comments on sqlite3BitvecBuiltinTest() for additional information.
597 */
598 static int testBitvecBuiltinTest(
599   void *NotUsed,
600   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
601   int argc,              /* Number of arguments */
602   const char **argv      /* Text of each argument */
603 ){
604   int sz, rc;
605   int nProg = 0;
606   int aProg[100];
607   const char *z;
608   if( argc!=3 ){
609     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
610                      " SIZE PROGRAM\"", (void*)0);
611   }
612   if( Tcl_GetInt(interp, argv[1], &sz) ) return TCL_ERROR;
613   z = argv[2];
614   while( nProg<99 && *z ){
615     while( *z && !sqlite3Isdigit(*z) ){ z++; }
616     if( *z==0 ) break;
617     aProg[nProg++] = atoi(z);
618     while( sqlite3Isdigit(*z) ){ z++; }
619   }
620   aProg[nProg] = 0;
621   rc = sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST, sz, aProg);
622   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
623   return TCL_OK;
624 }
625 
626 /*
627 ** Register commands with the TCL interpreter.
628 */
629 int Sqlitetest2_Init(Tcl_Interp *interp){
630   extern int sqlite3_io_error_persist;
631   extern int sqlite3_io_error_pending;
632   extern int sqlite3_io_error_hit;
633   extern int sqlite3_io_error_hardhit;
634   extern int sqlite3_diskfull_pending;
635   extern int sqlite3_diskfull;
636   static struct {
637     char *zName;
638     Tcl_CmdProc *xProc;
639   } aCmd[] = {
640     { "pager_open",              (Tcl_CmdProc*)pager_open          },
641     { "pager_close",             (Tcl_CmdProc*)pager_close         },
642     { "pager_commit",            (Tcl_CmdProc*)pager_commit        },
643     { "pager_rollback",          (Tcl_CmdProc*)pager_rollback      },
644     { "pager_stmt_begin",        (Tcl_CmdProc*)pager_stmt_begin    },
645     { "pager_stmt_commit",       (Tcl_CmdProc*)pager_stmt_commit   },
646     { "pager_stmt_rollback",     (Tcl_CmdProc*)pager_stmt_rollback },
647     { "pager_stats",             (Tcl_CmdProc*)pager_stats         },
648     { "pager_pagecount",         (Tcl_CmdProc*)pager_pagecount     },
649     { "page_get",                (Tcl_CmdProc*)page_get            },
650     { "page_lookup",             (Tcl_CmdProc*)page_lookup         },
651     { "page_unref",              (Tcl_CmdProc*)page_unref          },
652     { "page_read",               (Tcl_CmdProc*)page_read           },
653     { "page_write",              (Tcl_CmdProc*)page_write          },
654     { "page_number",             (Tcl_CmdProc*)page_number         },
655     { "pager_truncate",          (Tcl_CmdProc*)pager_truncate      },
656 #ifndef SQLITE_OMIT_DISKIO
657     { "fake_big_file",           (Tcl_CmdProc*)fake_big_file       },
658 #endif
659     { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest     },
660     { "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte },
661   };
662   int i;
663   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
664     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
665   }
666   Tcl_LinkVar(interp, "sqlite_io_error_pending",
667      (char*)&sqlite3_io_error_pending, TCL_LINK_INT);
668   Tcl_LinkVar(interp, "sqlite_io_error_persist",
669      (char*)&sqlite3_io_error_persist, TCL_LINK_INT);
670   Tcl_LinkVar(interp, "sqlite_io_error_hit",
671      (char*)&sqlite3_io_error_hit, TCL_LINK_INT);
672   Tcl_LinkVar(interp, "sqlite_io_error_hardhit",
673      (char*)&sqlite3_io_error_hardhit, TCL_LINK_INT);
674   Tcl_LinkVar(interp, "sqlite_diskfull_pending",
675      (char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
676   Tcl_LinkVar(interp, "sqlite_diskfull",
677      (char*)&sqlite3_diskfull, TCL_LINK_INT);
678 #ifndef SQLITE_OMIT_WSD
679   Tcl_LinkVar(interp, "sqlite_pending_byte",
680      (char*)&sqlite3PendingByte, TCL_LINK_INT | TCL_LINK_READ_ONLY);
681 #endif
682   return TCL_OK;
683 }
684