4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
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.
16 #include "sqliteInt.h"
22 extern const char *sqlite3ErrName(int);
25 ** Page size and reserved size used for testing.
27 static int test_pagesize
= 1024;
30 ** Dummy page reinitializer
32 static void pager_test_reiniter(DbPage
*pNotUsed
){
37 ** Usage: pager_open FILENAME N-PAGE
41 static int pager_open(
43 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
44 int argc
, /* Number of arguments */
45 const char **argv
/* Text of each argument */
53 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
54 " FILENAME N-PAGE\"", 0);
57 if( Tcl_GetInt(interp
, argv
[2], &nPage
) ) return TCL_ERROR
;
58 rc
= sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager
, argv
[1], 0, 0,
59 SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
| SQLITE_OPEN_MAIN_DB
,
62 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
65 sqlite3PagerSetCachesize(pPager
, nPage
);
66 pageSize
= test_pagesize
;
67 sqlite3PagerSetPagesize(pPager
, &pageSize
, -1);
68 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%p",pPager
);
69 Tcl_AppendResult(interp
, zBuf
, 0);
74 ** Usage: pager_close ID
76 ** Close the given pager.
78 static int pager_close(
80 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
81 int argc
, /* Number of arguments */
82 const char **argv
/* Text of each argument */
87 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
91 pPager
= sqlite3TestTextToPtr(argv
[1]);
92 rc
= sqlite3PagerClose(pPager
);
94 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
101 ** Usage: pager_rollback ID
105 static int pager_rollback(
107 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
108 int argc
, /* Number of arguments */
109 const char **argv
/* Text of each argument */
114 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
118 pPager
= sqlite3TestTextToPtr(argv
[1]);
119 rc
= sqlite3PagerRollback(pPager
);
121 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
128 ** Usage: pager_commit ID
130 ** Commit all changes
132 static int pager_commit(
134 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
135 int argc
, /* Number of arguments */
136 const char **argv
/* Text of each argument */
141 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
145 pPager
= sqlite3TestTextToPtr(argv
[1]);
146 rc
= sqlite3PagerCommitPhaseOne(pPager
, 0, 0);
148 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
151 rc
= sqlite3PagerCommitPhaseTwo(pPager
);
153 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
160 ** Usage: pager_stmt_begin ID
162 ** Start a new checkpoint.
164 static int pager_stmt_begin(
166 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
167 int argc
, /* Number of arguments */
168 const char **argv
/* Text of each argument */
173 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
177 pPager
= sqlite3TestTextToPtr(argv
[1]);
178 rc
= sqlite3PagerOpenSavepoint(pPager
, 1);
180 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
187 ** Usage: pager_stmt_rollback ID
189 ** Rollback changes to a checkpoint
191 static int pager_stmt_rollback(
193 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
194 int argc
, /* Number of arguments */
195 const char **argv
/* Text of each argument */
200 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
204 pPager
= sqlite3TestTextToPtr(argv
[1]);
205 rc
= sqlite3PagerSavepoint(pPager
, SAVEPOINT_ROLLBACK
, 0);
206 sqlite3PagerSavepoint(pPager
, SAVEPOINT_RELEASE
, 0);
208 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
215 ** Usage: pager_stmt_commit ID
217 ** Commit changes to a checkpoint
219 static int pager_stmt_commit(
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 */
228 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
232 pPager
= sqlite3TestTextToPtr(argv
[1]);
233 rc
= sqlite3PagerSavepoint(pPager
, SAVEPOINT_RELEASE
, 0);
235 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
242 ** Usage: pager_stats ID
244 ** Return pager statistics.
246 static int pager_stats(
248 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
249 int argc
, /* Number of arguments */
250 const char **argv
/* Text of each argument */
255 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
259 pPager
= sqlite3TestTextToPtr(argv
[1]);
260 a
= sqlite3PagerStats(pPager
);
262 static char *zName
[] = {
263 "ref", "page", "max", "size", "state", "err",
264 "hit", "miss", "ovfl",
267 Tcl_AppendElement(interp
, zName
[i
]);
268 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%d",a
[i
]);
269 Tcl_AppendElement(interp
, zBuf
);
275 ** Usage: pager_pagecount ID
277 ** Return the size of the database file.
279 static int pager_pagecount(
281 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
282 int argc
, /* Number of arguments */
283 const char **argv
/* Text of each argument */
289 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
293 pPager
= sqlite3TestTextToPtr(argv
[1]);
294 sqlite3PagerPagecount(pPager
, &nPage
);
295 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%d", nPage
);
296 Tcl_AppendResult(interp
, zBuf
, 0);
301 ** Usage: page_get ID PGNO
303 ** Return a pointer to a page from the database.
307 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
308 int argc
, /* Number of arguments */
309 const char **argv
/* Text of each argument */
317 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
321 pPager
= sqlite3TestTextToPtr(argv
[1]);
322 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
323 rc
= sqlite3PagerSharedLock(pPager
);
325 rc
= sqlite3PagerGet(pPager
, pgno
, &pPage
);
328 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
331 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%p",pPage
);
332 Tcl_AppendResult(interp
, zBuf
, 0);
337 ** Usage: page_lookup ID PGNO
339 ** Return a pointer to a page if the page is already in cache.
340 ** If not in cache, return an empty string.
342 static int page_lookup(
344 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
345 int argc
, /* Number of arguments */
346 const char **argv
/* Text of each argument */
353 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
357 pPager
= sqlite3TestTextToPtr(argv
[1]);
358 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
359 pPage
= sqlite3PagerLookup(pPager
, pgno
);
361 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%p",pPage
);
362 Tcl_AppendResult(interp
, zBuf
, 0);
368 ** Usage: pager_truncate ID PGNO
370 static int pager_truncate(
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 */
379 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
383 pPager
= sqlite3TestTextToPtr(argv
[1]);
384 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
385 sqlite3PagerTruncateImage(pPager
, pgno
);
391 ** Usage: page_unref PAGE
393 ** Drop a pointer to a page.
395 static int page_unref(
397 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
398 int argc
, /* Number of arguments */
399 const char **argv
/* Text of each argument */
403 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
407 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
408 sqlite3PagerUnref(pPage
);
413 ** Usage: page_read PAGE
415 ** Return the content of a page
417 static int page_read(
419 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
420 int argc
, /* Number of arguments */
421 const char **argv
/* Text of each argument */
426 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
430 pPage
= sqlite3TestTextToPtr(argv
[1]);
431 memcpy(zBuf
, sqlite3PagerGetData(pPage
), sizeof(zBuf
));
432 Tcl_AppendResult(interp
, zBuf
, 0);
437 ** Usage: page_number PAGE
439 ** Return the page number for a page.
441 static int page_number(
443 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
444 int argc
, /* Number of arguments */
445 const char **argv
/* Text of each argument */
450 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
454 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
455 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%d", sqlite3PagerPagenumber(pPage
));
456 Tcl_AppendResult(interp
, zBuf
, 0);
461 ** Usage: page_write PAGE DATA
463 ** Write something into a page.
465 static int page_write(
467 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
468 int argc
, /* Number of arguments */
469 const char **argv
/* Text of each argument */
475 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
479 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
480 rc
= sqlite3PagerWrite(pPage
);
482 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
485 pData
= sqlite3PagerGetData(pPage
);
486 strncpy(pData
, argv
[2], test_pagesize
-1);
487 pData
[test_pagesize
-1] = 0;
491 #ifndef SQLITE_OMIT_DISKIO
493 ** Usage: fake_big_file N FILENAME
495 ** Write a few bytes at the N megabyte point of FILENAME. This will
496 ** create a large file. If the file was a valid SQLite database, then
497 ** the next time the database is opened, SQLite will begin allocating
498 ** new pages after N. If N is 2096 or bigger, this will test the
499 ** ability of SQLite to write to large files.
501 static int fake_big_file(
503 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
504 int argc
, /* Number of arguments */
505 const char **argv
/* Text of each argument */
508 sqlite3_file
*fd
= 0;
515 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
516 " N-MEGABYTES FILE\"", 0);
519 if( Tcl_GetInt(interp
, argv
[1], &n
) ) return TCL_ERROR
;
521 pVfs
= sqlite3_vfs_find(0);
522 nFile
= (int)strlen(argv
[2]);
523 zFile
= sqlite3_malloc( nFile
+2 );
524 if( zFile
==0 ) return TCL_ERROR
;
525 memcpy(zFile
, argv
[2], nFile
+1);
527 rc
= sqlite3OsOpenMalloc(pVfs
, zFile
, &fd
,
528 (SQLITE_OPEN_CREATE
|SQLITE_OPEN_READWRITE
|SQLITE_OPEN_MAIN_DB
), 0
531 Tcl_AppendResult(interp
, "open failed: ", sqlite3ErrName(rc
), 0);
537 rc
= sqlite3OsWrite(fd
, "Hello, World!", 14, offset
);
538 sqlite3OsCloseFree(fd
);
541 Tcl_AppendResult(interp
, "write failed: ", sqlite3ErrName(rc
), 0);
550 ** test_control_pending_byte PENDING_BYTE
552 ** Set the PENDING_BYTE using the sqlite3_test_control() interface.
554 static int testPendingByte(
556 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
557 int argc
, /* Number of arguments */
558 const char **argv
/* Text of each argument */
563 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
564 " PENDING-BYTE\"", (void*)0);
567 if( Tcl_GetInt(interp
, argv
[1], &pbyte
) ) return TCL_ERROR
;
568 rc
= sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE
, pbyte
);
569 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
574 ** The sqlite3FaultSim() callback:
576 static Tcl_Interp
*faultSimInterp
= 0;
577 static int faultSimScriptSize
= 0;
578 static char *faultSimScript
;
579 static int faultSimCallback(int x
){
585 memcpy(faultSimScript
+faultSimScriptSize
, "0", 2);
587 /* Convert x to text without using any sqlite3 routines */
594 zInt
[sizeof(zInt
)-1] = 0;
595 for(i
=sizeof(zInt
)-2; i
>0 && x
>0; i
--, x
/= 10){
596 zInt
[i
] = (x
%10) + '0';
598 if( isNeg
) zInt
[i
--] = '-';
599 memcpy(faultSimScript
+faultSimScriptSize
, zInt
+i
+1, sizeof(zInt
)-i
);
601 rc
= Tcl_Eval(faultSimInterp
, faultSimScript
);
603 fprintf(stderr
, "fault simulator script failed: [%s]", faultSimScript
);
606 rc
= atoi(Tcl_GetStringResult(faultSimInterp
));
608 Tcl_ResetResult(faultSimInterp
);
613 ** sqlite3_test_control_fault_install SCRIPT
615 ** Arrange to invoke SCRIPT with the integer argument to sqlite3FaultSim()
616 ** appended, whenever sqlite3FaultSim() is called. Or, if SCRIPT is the
617 ** empty string, cancel the sqlite3FaultSim() callback.
619 static int faultInstallCmd(
621 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
622 int argc
, /* Number of arguments */
623 const char **argv
/* Text of each argument */
628 if( argc
!=1 && argc
!=2 ){
629 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
630 " SCRIPT\"", (void*)0);
632 zScript
= argc
==2 ? argv
[1] : "";
633 nScript
= (int)strlen(zScript
);
634 if( faultSimScript
){
635 free(faultSimScript
);
639 rc
= sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL
, 0);
641 faultSimScript
= malloc( nScript
+100 );
642 if( faultSimScript
==0 ){
643 Tcl_AppendResult(interp
, "out of memory", (void*)0);
646 memcpy(faultSimScript
, zScript
, nScript
);
647 faultSimScript
[nScript
] = ' ';
648 faultSimScriptSize
= nScript
+1;
649 faultSimInterp
= interp
;
650 rc
= sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL
, faultSimCallback
);
652 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
657 ** sqlite3BitvecBuiltinTest SIZE PROGRAM
659 ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
660 ** See comments on sqlite3BitvecBuiltinTest() for additional information.
662 static int testBitvecBuiltinTest(
664 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
665 int argc
, /* Number of arguments */
666 const char **argv
/* Text of each argument */
673 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
674 " SIZE PROGRAM\"", (void*)0);
676 if( Tcl_GetInt(interp
, argv
[1], &sz
) ) return TCL_ERROR
;
678 while( nProg
<99 && *z
){
679 while( *z
&& !sqlite3Isdigit(*z
) ){ z
++; }
681 aProg
[nProg
++] = atoi(z
);
682 while( sqlite3Isdigit(*z
) ){ z
++; }
685 rc
= sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST
, sz
, aProg
);
686 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
691 ** Register commands with the TCL interpreter.
693 int Sqlitetest2_Init(Tcl_Interp
*interp
){
694 extern int sqlite3_io_error_persist
;
695 extern int sqlite3_io_error_pending
;
696 extern int sqlite3_io_error_hit
;
697 extern int sqlite3_io_error_hardhit
;
698 extern int sqlite3_diskfull_pending
;
699 extern int sqlite3_diskfull
;
704 { "pager_open", (Tcl_CmdProc
*)pager_open
},
705 { "pager_close", (Tcl_CmdProc
*)pager_close
},
706 { "pager_commit", (Tcl_CmdProc
*)pager_commit
},
707 { "pager_rollback", (Tcl_CmdProc
*)pager_rollback
},
708 { "pager_stmt_begin", (Tcl_CmdProc
*)pager_stmt_begin
},
709 { "pager_stmt_commit", (Tcl_CmdProc
*)pager_stmt_commit
},
710 { "pager_stmt_rollback", (Tcl_CmdProc
*)pager_stmt_rollback
},
711 { "pager_stats", (Tcl_CmdProc
*)pager_stats
},
712 { "pager_pagecount", (Tcl_CmdProc
*)pager_pagecount
},
713 { "page_get", (Tcl_CmdProc
*)page_get
},
714 { "page_lookup", (Tcl_CmdProc
*)page_lookup
},
715 { "page_unref", (Tcl_CmdProc
*)page_unref
},
716 { "page_read", (Tcl_CmdProc
*)page_read
},
717 { "page_write", (Tcl_CmdProc
*)page_write
},
718 { "page_number", (Tcl_CmdProc
*)page_number
},
719 { "pager_truncate", (Tcl_CmdProc
*)pager_truncate
},
720 #ifndef SQLITE_OMIT_DISKIO
721 { "fake_big_file", (Tcl_CmdProc
*)fake_big_file
},
723 { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc
*)testBitvecBuiltinTest
},
724 { "sqlite3_test_control_pending_byte", (Tcl_CmdProc
*)testPendingByte
},
725 { "sqlite3_test_control_fault_install", (Tcl_CmdProc
*)faultInstallCmd
},
728 for(i
=0; i
<sizeof(aCmd
)/sizeof(aCmd
[0]); i
++){
729 Tcl_CreateCommand(interp
, aCmd
[i
].zName
, aCmd
[i
].xProc
, 0, 0);
731 Tcl_LinkVar(interp
, "sqlite_io_error_pending",
732 (char*)&sqlite3_io_error_pending
, TCL_LINK_INT
);
733 Tcl_LinkVar(interp
, "sqlite_io_error_persist",
734 (char*)&sqlite3_io_error_persist
, TCL_LINK_INT
);
735 Tcl_LinkVar(interp
, "sqlite_io_error_hit",
736 (char*)&sqlite3_io_error_hit
, TCL_LINK_INT
);
737 Tcl_LinkVar(interp
, "sqlite_io_error_hardhit",
738 (char*)&sqlite3_io_error_hardhit
, TCL_LINK_INT
);
739 Tcl_LinkVar(interp
, "sqlite_diskfull_pending",
740 (char*)&sqlite3_diskfull_pending
, TCL_LINK_INT
);
741 Tcl_LinkVar(interp
, "sqlite_diskfull",
742 (char*)&sqlite3_diskfull
, TCL_LINK_INT
);
743 #ifndef SQLITE_OMIT_WSD
744 Tcl_LinkVar(interp
, "sqlite_pending_byte",
745 (char*)&sqlite3PendingByte
, TCL_LINK_INT
| TCL_LINK_READ_ONLY
);