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"
23 ** Interpret an SQLite error number
25 static char *errorName(int 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;
53 ** Page size and reserved size used for testing.
55 static int test_pagesize
= 1024;
58 ** Dummy page reinitializer
60 static void pager_test_reiniter(DbPage
*pNotUsed
){
65 ** Usage: pager_open FILENAME N-PAGE
69 static int pager_open(
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 */
81 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
82 " FILENAME N-PAGE\"", 0);
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
,
90 Tcl_AppendResult(interp
, errorName(rc
), 0);
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);
102 ** Usage: pager_close ID
104 ** Close the given pager.
106 static int pager_close(
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 */
115 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
119 pPager
= sqlite3TestTextToPtr(argv
[1]);
120 rc
= sqlite3PagerClose(pPager
);
122 Tcl_AppendResult(interp
, errorName(rc
), 0);
129 ** Usage: pager_rollback ID
133 static int pager_rollback(
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 */
142 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
146 pPager
= sqlite3TestTextToPtr(argv
[1]);
147 rc
= sqlite3PagerRollback(pPager
);
149 Tcl_AppendResult(interp
, errorName(rc
), 0);
156 ** Usage: pager_commit ID
158 ** Commit all changes
160 static int pager_commit(
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 */
169 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
173 pPager
= sqlite3TestTextToPtr(argv
[1]);
174 rc
= sqlite3PagerCommitPhaseOne(pPager
, 0, 0);
176 Tcl_AppendResult(interp
, errorName(rc
), 0);
179 rc
= sqlite3PagerCommitPhaseTwo(pPager
);
181 Tcl_AppendResult(interp
, errorName(rc
), 0);
188 ** Usage: pager_stmt_begin ID
190 ** Start a new checkpoint.
192 static int pager_stmt_begin(
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 */
201 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
205 pPager
= sqlite3TestTextToPtr(argv
[1]);
206 rc
= sqlite3PagerOpenSavepoint(pPager
, 1);
208 Tcl_AppendResult(interp
, errorName(rc
), 0);
215 ** Usage: pager_stmt_rollback ID
217 ** Rollback changes to a checkpoint
219 static int pager_stmt_rollback(
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_ROLLBACK
, 0);
234 sqlite3PagerSavepoint(pPager
, SAVEPOINT_RELEASE
, 0);
236 Tcl_AppendResult(interp
, errorName(rc
), 0);
243 ** Usage: pager_stmt_commit ID
245 ** Commit changes to a checkpoint
247 static int pager_stmt_commit(
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 */
256 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
260 pPager
= sqlite3TestTextToPtr(argv
[1]);
261 rc
= sqlite3PagerSavepoint(pPager
, SAVEPOINT_RELEASE
, 0);
263 Tcl_AppendResult(interp
, errorName(rc
), 0);
270 ** Usage: pager_stats ID
272 ** Return pager statistics.
274 static int pager_stats(
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 */
283 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
287 pPager
= sqlite3TestTextToPtr(argv
[1]);
288 a
= sqlite3PagerStats(pPager
);
290 static char *zName
[] = {
291 "ref", "page", "max", "size", "state", "err",
292 "hit", "miss", "ovfl",
295 Tcl_AppendElement(interp
, zName
[i
]);
296 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%d",a
[i
]);
297 Tcl_AppendElement(interp
, zBuf
);
303 ** Usage: pager_pagecount ID
305 ** Return the size of the database file.
307 static int pager_pagecount(
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 */
317 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
321 pPager
= sqlite3TestTextToPtr(argv
[1]);
322 sqlite3PagerPagecount(pPager
, &nPage
);
323 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%d", nPage
);
324 Tcl_AppendResult(interp
, zBuf
, 0);
329 ** Usage: page_get ID PGNO
331 ** Return a pointer to a page from the database.
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 */
345 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
349 pPager
= sqlite3TestTextToPtr(argv
[1]);
350 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
351 rc
= sqlite3PagerSharedLock(pPager
);
353 rc
= sqlite3PagerGet(pPager
, pgno
, &pPage
);
356 Tcl_AppendResult(interp
, errorName(rc
), 0);
359 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%p",pPage
);
360 Tcl_AppendResult(interp
, zBuf
, 0);
365 ** Usage: page_lookup ID PGNO
367 ** Return a pointer to a page if the page is already in cache.
368 ** If not in cache, return an empty string.
370 static int page_lookup(
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 */
381 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
385 pPager
= sqlite3TestTextToPtr(argv
[1]);
386 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
387 pPage
= sqlite3PagerLookup(pPager
, pgno
);
389 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%p",pPage
);
390 Tcl_AppendResult(interp
, zBuf
, 0);
396 ** Usage: pager_truncate ID PGNO
398 static int pager_truncate(
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 */
407 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
411 pPager
= sqlite3TestTextToPtr(argv
[1]);
412 if( Tcl_GetInt(interp
, argv
[2], &pgno
) ) return TCL_ERROR
;
413 sqlite3PagerTruncateImage(pPager
, pgno
);
419 ** Usage: page_unref PAGE
421 ** Drop a pointer to a page.
423 static int page_unref(
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 */
431 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
435 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
436 sqlite3PagerUnref(pPage
);
441 ** Usage: page_read PAGE
443 ** Return the content of a page
445 static int page_read(
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
= sqlite3TestTextToPtr(argv
[1]);
459 memcpy(zBuf
, sqlite3PagerGetData(pPage
), sizeof(zBuf
));
460 Tcl_AppendResult(interp
, zBuf
, 0);
465 ** Usage: page_number PAGE
467 ** Return the page number for a page.
469 static int page_number(
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 */
478 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
482 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
483 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%d", sqlite3PagerPagenumber(pPage
));
484 Tcl_AppendResult(interp
, zBuf
, 0);
489 ** Usage: page_write PAGE DATA
491 ** Write something into a page.
493 static int page_write(
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 */
503 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
507 pPage
= (DbPage
*)sqlite3TestTextToPtr(argv
[1]);
508 rc
= sqlite3PagerWrite(pPage
);
510 Tcl_AppendResult(interp
, errorName(rc
), 0);
513 pData
= sqlite3PagerGetData(pPage
);
514 strncpy(pData
, argv
[2], test_pagesize
-1);
515 pData
[test_pagesize
-1] = 0;
519 #ifndef SQLITE_OMIT_DISKIO
521 ** Usage: fake_big_file N FILENAME
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.
529 static int fake_big_file(
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 */
536 sqlite3_file
*fd
= 0;
543 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
544 " N-MEGABYTES FILE\"", 0);
547 if( Tcl_GetInt(interp
, argv
[1], &n
) ) return TCL_ERROR
;
549 pVfs
= sqlite3_vfs_find(0);
550 nFile
= (int)strlen(argv
[2]);
551 zFile
= sqlite3_malloc( nFile
+2 );
552 if( zFile
==0 ) return TCL_ERROR
;
553 memcpy(zFile
, argv
[2], nFile
+1);
555 rc
= sqlite3OsOpenMalloc(pVfs
, zFile
, &fd
,
556 (SQLITE_OPEN_CREATE
|SQLITE_OPEN_READWRITE
|SQLITE_OPEN_MAIN_DB
), 0
559 Tcl_AppendResult(interp
, "open failed: ", errorName(rc
), 0);
565 rc
= sqlite3OsWrite(fd
, "Hello, World!", 14, offset
);
566 sqlite3OsCloseFree(fd
);
569 Tcl_AppendResult(interp
, "write failed: ", errorName(rc
), 0);
578 ** test_control_pending_byte PENDING_BYTE
580 ** Set the PENDING_BYTE using the sqlite3_test_control() interface.
582 static int testPendingByte(
584 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
585 int argc
, /* Number of arguments */
586 const char **argv
/* Text of each argument */
591 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
592 " PENDING-BYTE\"", (void*)0);
595 if( Tcl_GetInt(interp
, argv
[1], &pbyte
) ) return TCL_ERROR
;
596 rc
= sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE
, pbyte
);
597 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
602 ** sqlite3BitvecBuiltinTest SIZE PROGRAM
604 ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
605 ** See comments on sqlite3BitvecBuiltinTest() for additional information.
607 static int testBitvecBuiltinTest(
609 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
610 int argc
, /* Number of arguments */
611 const char **argv
/* Text of each argument */
618 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
619 " SIZE PROGRAM\"", (void*)0);
621 if( Tcl_GetInt(interp
, argv
[1], &sz
) ) return TCL_ERROR
;
623 while( nProg
<99 && *z
){
624 while( *z
&& !sqlite3Isdigit(*z
) ){ z
++; }
626 aProg
[nProg
++] = atoi(z
);
627 while( sqlite3Isdigit(*z
) ){ z
++; }
630 rc
= sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST
, sz
, aProg
);
631 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
636 ** Register commands with the TCL interpreter.
638 int Sqlitetest2_Init(Tcl_Interp
*interp
){
639 extern int sqlite3_io_error_persist
;
640 extern int sqlite3_io_error_pending
;
641 extern int sqlite3_io_error_hit
;
642 extern int sqlite3_io_error_hardhit
;
643 extern int sqlite3_diskfull_pending
;
644 extern int sqlite3_diskfull
;
649 { "pager_open", (Tcl_CmdProc
*)pager_open
},
650 { "pager_close", (Tcl_CmdProc
*)pager_close
},
651 { "pager_commit", (Tcl_CmdProc
*)pager_commit
},
652 { "pager_rollback", (Tcl_CmdProc
*)pager_rollback
},
653 { "pager_stmt_begin", (Tcl_CmdProc
*)pager_stmt_begin
},
654 { "pager_stmt_commit", (Tcl_CmdProc
*)pager_stmt_commit
},
655 { "pager_stmt_rollback", (Tcl_CmdProc
*)pager_stmt_rollback
},
656 { "pager_stats", (Tcl_CmdProc
*)pager_stats
},
657 { "pager_pagecount", (Tcl_CmdProc
*)pager_pagecount
},
658 { "page_get", (Tcl_CmdProc
*)page_get
},
659 { "page_lookup", (Tcl_CmdProc
*)page_lookup
},
660 { "page_unref", (Tcl_CmdProc
*)page_unref
},
661 { "page_read", (Tcl_CmdProc
*)page_read
},
662 { "page_write", (Tcl_CmdProc
*)page_write
},
663 { "page_number", (Tcl_CmdProc
*)page_number
},
664 { "pager_truncate", (Tcl_CmdProc
*)pager_truncate
},
665 #ifndef SQLITE_OMIT_DISKIO
666 { "fake_big_file", (Tcl_CmdProc
*)fake_big_file
},
668 { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc
*)testBitvecBuiltinTest
},
669 { "sqlite3_test_control_pending_byte", (Tcl_CmdProc
*)testPendingByte
},
672 for(i
=0; i
<sizeof(aCmd
)/sizeof(aCmd
[0]); i
++){
673 Tcl_CreateCommand(interp
, aCmd
[i
].zName
, aCmd
[i
].xProc
, 0, 0);
675 Tcl_LinkVar(interp
, "sqlite_io_error_pending",
676 (char*)&sqlite3_io_error_pending
, TCL_LINK_INT
);
677 Tcl_LinkVar(interp
, "sqlite_io_error_persist",
678 (char*)&sqlite3_io_error_persist
, TCL_LINK_INT
);
679 Tcl_LinkVar(interp
, "sqlite_io_error_hit",
680 (char*)&sqlite3_io_error_hit
, TCL_LINK_INT
);
681 Tcl_LinkVar(interp
, "sqlite_io_error_hardhit",
682 (char*)&sqlite3_io_error_hardhit
, TCL_LINK_INT
);
683 Tcl_LinkVar(interp
, "sqlite_diskfull_pending",
684 (char*)&sqlite3_diskfull_pending
, TCL_LINK_INT
);
685 Tcl_LinkVar(interp
, "sqlite_diskfull",
686 (char*)&sqlite3_diskfull
, TCL_LINK_INT
);
687 #ifndef SQLITE_OMIT_WSD
688 Tcl_LinkVar(interp
, "sqlite_pending_byte",
689 (char*)&sqlite3PendingByte
, TCL_LINK_INT
| TCL_LINK_READ_ONLY
);