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"
17 #if defined(INCLUDE_SQLITE_TCL_H)
18 # include "sqlite_tcl.h"
26 extern const char *sqlite3ErrName(int);
29 ** Page size and reserved size used for testing.
31 static int test_pagesize
= 1024;
34 ** Dummy page reinitializer
36 static void pager_test_reiniter(DbPage
*pNotUsed
){
41 ** Usage: pager_open FILENAME N-PAGE
45 static int SQLITE_TCLAPI
pager_open(
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 */
57 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
58 " FILENAME N-PAGE\"", 0);
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
,
66 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
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);
78 ** Usage: pager_close ID
80 ** Close the given pager.
82 static int SQLITE_TCLAPI
pager_close(
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 */
91 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
95 pPager
= sqlite3TestTextToPtr(argv
[1]);
96 rc
= sqlite3PagerClose(pPager
, 0);
98 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
105 ** Usage: pager_rollback ID
109 static int SQLITE_TCLAPI
pager_rollback(
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 */
118 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
122 pPager
= sqlite3TestTextToPtr(argv
[1]);
123 rc
= sqlite3PagerRollback(pPager
);
125 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
132 ** Usage: pager_commit ID
134 ** Commit all changes
136 static int SQLITE_TCLAPI
pager_commit(
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 */
145 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
149 pPager
= sqlite3TestTextToPtr(argv
[1]);
150 rc
= sqlite3PagerCommitPhaseOne(pPager
, 0, 0);
152 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
155 rc
= sqlite3PagerCommitPhaseTwo(pPager
);
157 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
164 ** Usage: pager_stmt_begin ID
166 ** Start a new checkpoint.
168 static int SQLITE_TCLAPI
pager_stmt_begin(
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 */
177 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
181 pPager
= sqlite3TestTextToPtr(argv
[1]);
182 rc
= sqlite3PagerOpenSavepoint(pPager
, 1);
184 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
191 ** Usage: pager_stmt_rollback ID
193 ** Rollback changes to a checkpoint
195 static int SQLITE_TCLAPI
pager_stmt_rollback(
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 */
204 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
208 pPager
= sqlite3TestTextToPtr(argv
[1]);
209 rc
= sqlite3PagerSavepoint(pPager
, SAVEPOINT_ROLLBACK
, 0);
210 sqlite3PagerSavepoint(pPager
, SAVEPOINT_RELEASE
, 0);
212 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
219 ** Usage: pager_stmt_commit ID
221 ** Commit changes to a checkpoint
223 static int SQLITE_TCLAPI
pager_stmt_commit(
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 */
232 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
236 pPager
= sqlite3TestTextToPtr(argv
[1]);
237 rc
= sqlite3PagerSavepoint(pPager
, SAVEPOINT_RELEASE
, 0);
239 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
246 ** Usage: pager_stats ID
248 ** Return pager statistics.
250 static int SQLITE_TCLAPI
pager_stats(
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 */
259 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
263 pPager
= sqlite3TestTextToPtr(argv
[1]);
264 a
= sqlite3PagerStats(pPager
);
266 static char *zName
[] = {
267 "ref", "page", "max", "size", "state", "err",
268 "hit", "miss", "ovfl",
271 Tcl_AppendElement(interp
, zName
[i
]);
272 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%d",a
[i
]);
273 Tcl_AppendElement(interp
, zBuf
);
279 ** Usage: pager_pagecount ID
281 ** Return the size of the database file.
283 static int SQLITE_TCLAPI
pager_pagecount(
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 */
293 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
297 pPager
= sqlite3TestTextToPtr(argv
[1]);
298 sqlite3PagerPagecount(pPager
, &nPage
);
299 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%d", nPage
);
300 Tcl_AppendResult(interp
, zBuf
, 0);
305 ** Usage: page_get ID PGNO
307 ** Return a pointer to a page from the database.
309 static int SQLITE_TCLAPI
page_get(
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 */
321 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
325 pPager
= sqlite3TestTextToPtr(argv
[1]);
326 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
327 rc
= sqlite3PagerSharedLock(pPager
);
329 rc
= sqlite3PagerGet(pPager
, pgno
, &pPage
, 0);
332 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
335 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%p",pPage
);
336 Tcl_AppendResult(interp
, zBuf
, 0);
341 ** Usage: page_lookup ID PGNO
343 ** Return a pointer to a page if the page is already in cache.
344 ** If not in cache, return an empty string.
346 static int SQLITE_TCLAPI
page_lookup(
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 */
357 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
361 pPager
= sqlite3TestTextToPtr(argv
[1]);
362 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
363 pPage
= sqlite3PagerLookup(pPager
, pgno
);
365 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%p",pPage
);
366 Tcl_AppendResult(interp
, zBuf
, 0);
372 ** Usage: pager_truncate ID PGNO
374 static int SQLITE_TCLAPI
pager_truncate(
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 */
383 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
387 pPager
= sqlite3TestTextToPtr(argv
[1]);
388 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
389 sqlite3PagerTruncateImage(pPager
, pgno
);
395 ** Usage: page_unref PAGE
397 ** Drop a pointer to a page.
399 static int SQLITE_TCLAPI
page_unref(
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 */
407 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
411 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
412 sqlite3PagerUnref(pPage
);
417 ** Usage: page_read PAGE
419 ** Return the content of a page
421 static int SQLITE_TCLAPI
page_read(
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 */
430 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
434 pPage
= sqlite3TestTextToPtr(argv
[1]);
435 memcpy(zBuf
, sqlite3PagerGetData(pPage
), sizeof(zBuf
));
436 Tcl_AppendResult(interp
, zBuf
, 0);
441 ** Usage: page_number PAGE
443 ** Return the page number for a page.
445 static int SQLITE_TCLAPI
page_number(
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 */
454 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
458 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
459 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%d", sqlite3PagerPagenumber(pPage
));
460 Tcl_AppendResult(interp
, zBuf
, 0);
465 ** Usage: page_write PAGE DATA
467 ** Write something into a page.
469 static int SQLITE_TCLAPI
page_write(
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 */
479 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
483 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
484 rc
= sqlite3PagerWrite(pPage
);
486 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
489 pData
= sqlite3PagerGetData(pPage
);
490 strncpy(pData
, argv
[2], test_pagesize
-1);
491 pData
[test_pagesize
-1] = 0;
495 #ifndef SQLITE_OMIT_DISKIO
497 ** Usage: fake_big_file N FILENAME
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.
505 static int SQLITE_TCLAPI
fake_big_file(
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 */
512 sqlite3_file
*fd
= 0;
519 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
520 " N-MEGABYTES FILE\"", 0);
523 if( Tcl_GetInt(interp
, argv
[1], &n
) ) return TCL_ERROR
;
526 Tcl_AppendResult(interp
, "cannot create ", argv
[1],
527 "MB file because Windows "
528 "does not support sparse files", (void*)0);
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);
539 rc
= sqlite3OsOpenMalloc(pVfs
, zFile
, &fd
,
540 (SQLITE_OPEN_CREATE
|SQLITE_OPEN_READWRITE
|SQLITE_OPEN_MAIN_DB
), 0
543 Tcl_AppendResult(interp
, "open failed: ", sqlite3ErrName(rc
), 0);
549 rc
= sqlite3OsWrite(fd
, "Hello, World!", 14, offset
);
550 sqlite3OsCloseFree(fd
);
553 Tcl_AppendResult(interp
, "write failed: ", sqlite3ErrName(rc
), 0);
562 ** test_control_pending_byte PENDING_BYTE
564 ** Set the PENDING_BYTE using the sqlite3_test_control() interface.
566 static int SQLITE_TCLAPI
testPendingByte(
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 */
575 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
576 " PENDING-BYTE\"", (void*)0);
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
));
586 ** The sqlite3FaultSim() callback:
588 static Tcl_Interp
*faultSimInterp
= 0;
589 static int faultSimScriptSize
= 0;
590 static char *faultSimScript
;
591 static int faultSimCallback(int x
){
597 memcpy(faultSimScript
+faultSimScriptSize
, "0", 2);
599 /* Convert x to text without using any sqlite3 routines */
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';
610 if( isNeg
) zInt
[i
--] = '-';
611 memcpy(faultSimScript
+faultSimScriptSize
, zInt
+i
+1, sizeof(zInt
)-i
-1);
613 rc
= Tcl_Eval(faultSimInterp
, faultSimScript
);
615 fprintf(stderr
, "fault simulator script failed: [%s]", faultSimScript
);
618 rc
= atoi(Tcl_GetStringResult(faultSimInterp
));
620 Tcl_ResetResult(faultSimInterp
);
625 ** sqlite3_test_control_fault_install SCRIPT
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.
631 static int SQLITE_TCLAPI
faultInstallCmd(
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 */
640 if( argc
!=1 && argc
!=2 ){
641 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
642 " SCRIPT\"", (void*)0);
644 zScript
= argc
==2 ? argv
[1] : "";
645 nScript
= (int)strlen(zScript
);
646 if( faultSimScript
){
647 free(faultSimScript
);
651 rc
= sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL
, 0);
653 faultSimScript
= malloc( nScript
+100 );
654 if( faultSimScript
==0 ){
655 Tcl_AppendResult(interp
, "out of memory", (void*)0);
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
);
664 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
669 ** sqlite3BitvecBuiltinTest SIZE PROGRAM
671 ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
672 ** See comments on sqlite3BitvecBuiltinTest() for additional information.
674 static int SQLITE_TCLAPI
testBitvecBuiltinTest(
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 */
685 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
686 " SIZE PROGRAM\"", (void*)0);
688 if( Tcl_GetInt(interp
, argv
[1], &sz
) ) return TCL_ERROR
;
690 while( nProg
<99 && *z
){
691 while( *z
&& !sqlite3Isdigit(*z
) ){ z
++; }
693 aProg
[nProg
++] = atoi(z
);
694 while( sqlite3Isdigit(*z
) ){ z
++; }
697 rc
= sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST
, sz
, aProg
);
698 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
703 ** Register commands with the TCL interpreter.
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
;
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
},
735 { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc
*)testBitvecBuiltinTest
},
736 { "sqlite3_test_control_pending_byte", (Tcl_CmdProc
*)testPendingByte
},
737 { "sqlite3_test_control_fault_install", (Tcl_CmdProc
*)faultInstallCmd
},
740 for(i
=0; i
<sizeof(aCmd
)/sizeof(aCmd
[0]); i
++){
741 Tcl_CreateCommand(interp
, aCmd
[i
].zName
, aCmd
[i
].xProc
, 0, 0);
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
);