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
525 pVfs = sqlite3_vfs_find(0);
526 nFile = (int)strlen(argv[2]);
527 zFile = sqlite3_malloc( nFile+2 );
528 if( zFile==0 ) return TCL_ERROR;
529 memcpy(zFile, argv[2], nFile+1);
530 zFile[nFile+1] = 0;
531 rc = sqlite3OsOpenMalloc(pVfs, zFile, &fd,
532 (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0
533 );
534 if( rc ){
535 Tcl_AppendResult(interp, "open failed: ", sqlite3ErrName(rc), 0);
536 sqlite3_free(zFile);
537 return TCL_ERROR;
538 }
539 offset = n;
540 offset *= 1024*1024;
541 rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
542 sqlite3OsCloseFree(fd);
543 sqlite3_free(zFile);
544 if( rc ){
545 Tcl_AppendResult(interp, "write failed: ", sqlite3ErrName(rc), 0);
546 return TCL_ERROR;
547 }
548 return TCL_OK;
549 }
550 #endif
551
552
553 /*
554 ** test_control_pending_byte PENDING_BYTE
555 **
556 ** Set the PENDING_BYTE using the sqlite3_test_control() interface.
557 */
testPendingByte(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)558 static int SQLITE_TCLAPI testPendingByte(
559 void *NotUsed,
560 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
561 int argc, /* Number of arguments */
562 const char **argv /* Text of each argument */
563 ){
564 int pbyte;
565 int rc;
566 if( argc!=2 ){
567 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
568 " PENDING-BYTE\"", (void*)0);
569 return TCL_ERROR;
570 }
571 if( Tcl_GetInt(interp, argv[1], &pbyte) ) return TCL_ERROR;
572 rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
573 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
574 return TCL_OK;
575 }
576
577 /*
578 ** The sqlite3FaultSim() callback:
579 */
580 static Tcl_Interp *faultSimInterp = 0;
581 static int faultSimScriptSize = 0;
582 static char *faultSimScript;
faultSimCallback(int x)583 static int faultSimCallback(int x){
584 char zInt[30];
585 int i;
586 int isNeg;
587 int rc;
588 if( x==0 ){
589 memcpy(faultSimScript+faultSimScriptSize, "0", 2);
590 }else{
591 /* Convert x to text without using any sqlite3 routines */
592 if( x<0 ){
593 isNeg = 1;
594 x = -x;
595 }else{
596 isNeg = 0;
597 }
598 zInt[sizeof(zInt)-1] = 0;
599 for(i=sizeof(zInt)-2; i>0 && x>0; i--, x /= 10){
600 zInt[i] = (x%10) + '0';
601 }
602 if( isNeg ) zInt[i--] = '-';
603 memcpy(faultSimScript+faultSimScriptSize, zInt+i+1, sizeof(zInt)-i);
604 }
605 rc = Tcl_Eval(faultSimInterp, faultSimScript);
606 if( rc ){
607 fprintf(stderr, "fault simulator script failed: [%s]", faultSimScript);
608 rc = SQLITE_ERROR;
609 }else{
610 rc = atoi(Tcl_GetStringResult(faultSimInterp));
611 }
612 Tcl_ResetResult(faultSimInterp);
613 return rc;
614 }
615
616 /*
617 ** sqlite3_test_control_fault_install SCRIPT
618 **
619 ** Arrange to invoke SCRIPT with the integer argument to sqlite3FaultSim()
620 ** appended, whenever sqlite3FaultSim() is called. Or, if SCRIPT is the
621 ** empty string, cancel the sqlite3FaultSim() callback.
622 */
faultInstallCmd(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)623 static int SQLITE_TCLAPI faultInstallCmd(
624 void *NotUsed,
625 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
626 int argc, /* Number of arguments */
627 const char **argv /* Text of each argument */
628 ){
629 const char *zScript;
630 int nScript;
631 int rc;
632 if( argc!=1 && argc!=2 ){
633 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
634 " SCRIPT\"", (void*)0);
635 }
636 zScript = argc==2 ? argv[1] : "";
637 nScript = (int)strlen(zScript);
638 if( faultSimScript ){
639 free(faultSimScript);
640 faultSimScript = 0;
641 }
642 if( nScript==0 ){
643 rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, 0);
644 }else{
645 faultSimScript = malloc( nScript+100 );
646 if( faultSimScript==0 ){
647 Tcl_AppendResult(interp, "out of memory", (void*)0);
648 return SQLITE_ERROR;
649 }
650 memcpy(faultSimScript, zScript, nScript);
651 faultSimScript[nScript] = ' ';
652 faultSimScriptSize = nScript+1;
653 faultSimInterp = interp;
654 rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, faultSimCallback);
655 }
656 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
657 return SQLITE_OK;
658 }
659
660 /*
661 ** sqlite3BitvecBuiltinTest SIZE PROGRAM
662 **
663 ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
664 ** See comments on sqlite3BitvecBuiltinTest() for additional information.
665 */
testBitvecBuiltinTest(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)666 static int SQLITE_TCLAPI testBitvecBuiltinTest(
667 void *NotUsed,
668 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
669 int argc, /* Number of arguments */
670 const char **argv /* Text of each argument */
671 ){
672 int sz, rc;
673 int nProg = 0;
674 int aProg[100];
675 const char *z;
676 if( argc!=3 ){
677 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
678 " SIZE PROGRAM\"", (void*)0);
679 }
680 if( Tcl_GetInt(interp, argv[1], &sz) ) return TCL_ERROR;
681 z = argv[2];
682 while( nProg<99 && *z ){
683 while( *z && !sqlite3Isdigit(*z) ){ z++; }
684 if( *z==0 ) break;
685 aProg[nProg++] = atoi(z);
686 while( sqlite3Isdigit(*z) ){ z++; }
687 }
688 aProg[nProg] = 0;
689 rc = sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST, sz, aProg);
690 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
691 return TCL_OK;
692 }
693
694 /*
695 ** Register commands with the TCL interpreter.
696 */
Sqlitetest2_Init(Tcl_Interp * interp)697 int Sqlitetest2_Init(Tcl_Interp *interp){
698 extern int sqlite3_io_error_persist;
699 extern int sqlite3_io_error_pending;
700 extern int sqlite3_io_error_hit;
701 extern int sqlite3_io_error_hardhit;
702 extern int sqlite3_diskfull_pending;
703 extern int sqlite3_diskfull;
704 static struct {
705 char *zName;
706 Tcl_CmdProc *xProc;
707 } aCmd[] = {
708 { "pager_open", (Tcl_CmdProc*)pager_open },
709 { "pager_close", (Tcl_CmdProc*)pager_close },
710 { "pager_commit", (Tcl_CmdProc*)pager_commit },
711 { "pager_rollback", (Tcl_CmdProc*)pager_rollback },
712 { "pager_stmt_begin", (Tcl_CmdProc*)pager_stmt_begin },
713 { "pager_stmt_commit", (Tcl_CmdProc*)pager_stmt_commit },
714 { "pager_stmt_rollback", (Tcl_CmdProc*)pager_stmt_rollback },
715 { "pager_stats", (Tcl_CmdProc*)pager_stats },
716 { "pager_pagecount", (Tcl_CmdProc*)pager_pagecount },
717 { "page_get", (Tcl_CmdProc*)page_get },
718 { "page_lookup", (Tcl_CmdProc*)page_lookup },
719 { "page_unref", (Tcl_CmdProc*)page_unref },
720 { "page_read", (Tcl_CmdProc*)page_read },
721 { "page_write", (Tcl_CmdProc*)page_write },
722 { "page_number", (Tcl_CmdProc*)page_number },
723 { "pager_truncate", (Tcl_CmdProc*)pager_truncate },
724 #ifndef SQLITE_OMIT_DISKIO
725 { "fake_big_file", (Tcl_CmdProc*)fake_big_file },
726 #endif
727 { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest },
728 { "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte },
729 { "sqlite3_test_control_fault_install", (Tcl_CmdProc*)faultInstallCmd },
730 };
731 int i;
732 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
733 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
734 }
735 Tcl_LinkVar(interp, "sqlite_io_error_pending",
736 (char*)&sqlite3_io_error_pending, TCL_LINK_INT);
737 Tcl_LinkVar(interp, "sqlite_io_error_persist",
738 (char*)&sqlite3_io_error_persist, TCL_LINK_INT);
739 Tcl_LinkVar(interp, "sqlite_io_error_hit",
740 (char*)&sqlite3_io_error_hit, TCL_LINK_INT);
741 Tcl_LinkVar(interp, "sqlite_io_error_hardhit",
742 (char*)&sqlite3_io_error_hardhit, TCL_LINK_INT);
743 Tcl_LinkVar(interp, "sqlite_diskfull_pending",
744 (char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
745 Tcl_LinkVar(interp, "sqlite_diskfull",
746 (char*)&sqlite3_diskfull, TCL_LINK_INT);
747 #ifndef SQLITE_OMIT_WSD
748 Tcl_LinkVar(interp, "sqlite_pending_byte",
749 (char*)&sqlite3PendingByte, TCL_LINK_INT | TCL_LINK_READ_ONLY);
750 #endif
751 return TCL_OK;
752 }
753