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