blob: d5db3867b822761513e120e66fddf0a0897914e6 [file] [log] [blame]
drh5c4d9702001-08-20 00:33:58 +00001/*
drhb19a2bc2001-09-16 00:13:26 +00002** 2001 September 15
drh5c4d9702001-08-20 00:33:58 +00003**
drhb19a2bc2001-09-16 00:13:26 +00004** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
drh5c4d9702001-08-20 00:33:58 +00006**
drhb19a2bc2001-09-16 00:13:26 +00007** 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.
drh5c4d9702001-08-20 00:33:58 +000010**
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.
drh5c4d9702001-08-20 00:33:58 +000015*/
16#include "sqliteInt.h"
mistachkin52b1dbb2016-07-28 14:37:04 +000017#if defined(INCLUDE_SQLITE_TCL_H)
18# include "sqlite_tcl.h"
19#else
20# include "tcl.h"
21#endif
drh5c4d9702001-08-20 00:33:58 +000022#include <stdlib.h>
23#include <string.h>
drh3088d592008-03-21 16:45:47 +000024#include <ctype.h>
drh5c4d9702001-08-20 00:33:58 +000025
mistachkine84d8d32013-04-29 03:09:10 +000026extern const char *sqlite3ErrName(int);
drh5c4d9702001-08-20 00:33:58 +000027
28/*
drh90f5ecb2004-07-22 01:19:35 +000029** Page size and reserved size used for testing.
30*/
31static int test_pagesize = 1024;
32
33/*
drh4775ecd2009-07-24 19:01:19 +000034** Dummy page reinitializer
35*/
36static void pager_test_reiniter(DbPage *pNotUsed){
37 return;
38}
39
40/*
drh5c4d9702001-08-20 00:33:58 +000041** Usage: pager_open FILENAME N-PAGE
42**
43** Open a new pager
44*/
mistachkin7617e4a2016-07-28 17:11:20 +000045static int SQLITE_TCLAPI pager_open(
drh5c4d9702001-08-20 00:33:58 +000046 void *NotUsed,
47 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
48 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +000049 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +000050){
drhb2eced52010-08-12 02:41:12 +000051 u32 pageSize;
drh5c4d9702001-08-20 00:33:58 +000052 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;
danielk197771d5d2c2008-09-29 11:49:47 +000062 rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0,
drh4775ecd2009-07-24 19:01:19 +000063 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
64 pager_test_reiniter);
drh5c4d9702001-08-20 00:33:58 +000065 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +000066 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +000067 return TCL_ERROR;
68 }
danielk19773b8a05f2007-03-19 17:44:26 +000069 sqlite3PagerSetCachesize(pPager, nPage);
danielk1977a1644fd2007-08-29 12:31:25 +000070 pageSize = test_pagesize;
drhfa9601a2009-06-18 17:22:39 +000071 sqlite3PagerSetPagesize(pPager, &pageSize, -1);
drhfe63d1c2004-09-08 20:13:04 +000072 sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
drh5c4d9702001-08-20 00:33:58 +000073 Tcl_AppendResult(interp, zBuf, 0);
74 return TCL_OK;
75}
76
77/*
78** Usage: pager_close ID
79**
80** Close the given pager.
81*/
mistachkin7617e4a2016-07-28 17:11:20 +000082static int SQLITE_TCLAPI pager_close(
drh5c4d9702001-08-20 00:33:58 +000083 void *NotUsed,
84 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
85 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +000086 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +000087){
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 }
drhe8f52c52008-07-12 14:52:20 +000095 pPager = sqlite3TestTextToPtr(argv[1]);
dan7fb89902016-08-12 16:21:15 +000096 rc = sqlite3PagerClose(pPager, 0);
drh5c4d9702001-08-20 00:33:58 +000097 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +000098 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +000099 return TCL_ERROR;
100 }
101 return TCL_OK;
102}
103
104/*
105** Usage: pager_rollback ID
106**
107** Rollback changes
108*/
mistachkin7617e4a2016-07-28 17:11:20 +0000109static int SQLITE_TCLAPI pager_rollback(
drh5c4d9702001-08-20 00:33:58 +0000110 void *NotUsed,
111 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
112 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000113 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000114){
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 }
drhe8f52c52008-07-12 14:52:20 +0000122 pPager = sqlite3TestTextToPtr(argv[1]);
danielk19773b8a05f2007-03-19 17:44:26 +0000123 rc = sqlite3PagerRollback(pPager);
drh5c4d9702001-08-20 00:33:58 +0000124 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000125 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000126 return TCL_ERROR;
127 }
128 return TCL_OK;
129}
130
131/*
132** Usage: pager_commit ID
133**
134** Commit all changes
135*/
mistachkin7617e4a2016-07-28 17:11:20 +0000136static int SQLITE_TCLAPI pager_commit(
drh5c4d9702001-08-20 00:33:58 +0000137 void *NotUsed,
138 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
139 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000140 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000141){
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 }
drhe8f52c52008-07-12 14:52:20 +0000149 pPager = sqlite3TestTextToPtr(argv[1]);
drh49b9d332009-01-02 18:10:42 +0000150 rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
drh80e35f42007-03-30 14:06:34 +0000151 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000152 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh80e35f42007-03-30 14:06:34 +0000153 return TCL_ERROR;
154 }
155 rc = sqlite3PagerCommitPhaseTwo(pPager);
drh5c4d9702001-08-20 00:33:58 +0000156 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000157 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000158 return TCL_ERROR;
159 }
160 return TCL_OK;
161}
162
163/*
drh3aac2dd2004-04-26 14:10:20 +0000164** Usage: pager_stmt_begin ID
drhfa86c412002-02-02 15:01:15 +0000165**
166** Start a new checkpoint.
167*/
mistachkin7617e4a2016-07-28 17:11:20 +0000168static int SQLITE_TCLAPI pager_stmt_begin(
drhfa86c412002-02-02 15:01:15 +0000169 void *NotUsed,
170 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
171 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000172 const char **argv /* Text of each argument */
drhfa86c412002-02-02 15:01:15 +0000173){
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 }
drhe8f52c52008-07-12 14:52:20 +0000181 pPager = sqlite3TestTextToPtr(argv[1]);
danielk1977fd7f0452008-12-17 17:30:26 +0000182 rc = sqlite3PagerOpenSavepoint(pPager, 1);
drhfa86c412002-02-02 15:01:15 +0000183 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000184 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drhfa86c412002-02-02 15:01:15 +0000185 return TCL_ERROR;
186 }
187 return TCL_OK;
188}
189
190/*
drh3aac2dd2004-04-26 14:10:20 +0000191** Usage: pager_stmt_rollback ID
drhfa86c412002-02-02 15:01:15 +0000192**
193** Rollback changes to a checkpoint
194*/
mistachkin7617e4a2016-07-28 17:11:20 +0000195static int SQLITE_TCLAPI pager_stmt_rollback(
drhfa86c412002-02-02 15:01:15 +0000196 void *NotUsed,
197 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
198 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000199 const char **argv /* Text of each argument */
drhfa86c412002-02-02 15:01:15 +0000200){
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 }
drhe8f52c52008-07-12 14:52:20 +0000208 pPager = sqlite3TestTextToPtr(argv[1]);
danielk1977fd7f0452008-12-17 17:30:26 +0000209 rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0);
210 sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
drhfa86c412002-02-02 15:01:15 +0000211 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000212 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drhfa86c412002-02-02 15:01:15 +0000213 return TCL_ERROR;
214 }
215 return TCL_OK;
216}
217
218/*
drh3aac2dd2004-04-26 14:10:20 +0000219** Usage: pager_stmt_commit ID
drhfa86c412002-02-02 15:01:15 +0000220**
221** Commit changes to a checkpoint
222*/
mistachkin7617e4a2016-07-28 17:11:20 +0000223static int SQLITE_TCLAPI pager_stmt_commit(
drhfa86c412002-02-02 15:01:15 +0000224 void *NotUsed,
225 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
226 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000227 const char **argv /* Text of each argument */
drhfa86c412002-02-02 15:01:15 +0000228){
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 }
drhe8f52c52008-07-12 14:52:20 +0000236 pPager = sqlite3TestTextToPtr(argv[1]);
danielk1977fd7f0452008-12-17 17:30:26 +0000237 rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
drhfa86c412002-02-02 15:01:15 +0000238 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000239 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drhfa86c412002-02-02 15:01:15 +0000240 return TCL_ERROR;
241 }
242 return TCL_OK;
243}
244
245/*
drh5c4d9702001-08-20 00:33:58 +0000246** Usage: pager_stats ID
247**
248** Return pager statistics.
249*/
mistachkin7617e4a2016-07-28 17:11:20 +0000250static int SQLITE_TCLAPI pager_stats(
drh5c4d9702001-08-20 00:33:58 +0000251 void *NotUsed,
252 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
253 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000254 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000255){
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 }
drhe8f52c52008-07-12 14:52:20 +0000263 pPager = sqlite3TestTextToPtr(argv[1]);
danielk19773b8a05f2007-03-19 17:44:26 +0000264 a = sqlite3PagerStats(pPager);
drh5c4d9702001-08-20 00:33:58 +0000265 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]);
drhfe63d1c2004-09-08 20:13:04 +0000272 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",a[i]);
drh5c4d9702001-08-20 00:33:58 +0000273 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*/
mistachkin7617e4a2016-07-28 17:11:20 +0000283static int SQLITE_TCLAPI pager_pagecount(
drh5c4d9702001-08-20 00:33:58 +0000284 void *NotUsed,
285 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
286 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000287 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000288){
289 Pager *pPager;
290 char zBuf[100];
danielk1977ad0132d2008-06-07 08:58:22 +0000291 int nPage;
drh5c4d9702001-08-20 00:33:58 +0000292 if( argc!=2 ){
293 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
294 " ID\"", 0);
295 return TCL_ERROR;
296 }
drhe8f52c52008-07-12 14:52:20 +0000297 pPager = sqlite3TestTextToPtr(argv[1]);
danielk1977ad0132d2008-06-07 08:58:22 +0000298 sqlite3PagerPagecount(pPager, &nPage);
299 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nPage);
drh5c4d9702001-08-20 00:33:58 +0000300 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*/
mistachkin7617e4a2016-07-28 17:11:20 +0000309static int SQLITE_TCLAPI page_get(
drh5c4d9702001-08-20 00:33:58 +0000310 void *NotUsed,
311 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
312 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000313 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000314){
315 Pager *pPager;
316 char zBuf[100];
mistachkin27b2f052015-01-12 19:49:46 +0000317 DbPage *pPage = 0;
drh5c4d9702001-08-20 00:33:58 +0000318 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 }
drhe8f52c52008-07-12 14:52:20 +0000325 pPager = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000326 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
danielk197789bc4bc2009-07-21 19:25:24 +0000327 rc = sqlite3PagerSharedLock(pPager);
328 if( rc==SQLITE_OK ){
drh9584f582015-11-04 20:22:37 +0000329 rc = sqlite3PagerGet(pPager, pgno, &pPage, 0);
danielk197789bc4bc2009-07-21 19:25:24 +0000330 }
drh5c4d9702001-08-20 00:33:58 +0000331 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000332 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000333 return TCL_ERROR;
334 }
drhfe63d1c2004-09-08 20:13:04 +0000335 sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
drh5c4d9702001-08-20 00:33:58 +0000336 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*/
mistachkin7617e4a2016-07-28 17:11:20 +0000346static int SQLITE_TCLAPI page_lookup(
drh5c4d9702001-08-20 00:33:58 +0000347 void *NotUsed,
348 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
349 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000350 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000351){
352 Pager *pPager;
353 char zBuf[100];
danielk19773b8a05f2007-03-19 17:44:26 +0000354 DbPage *pPage;
drh5c4d9702001-08-20 00:33:58 +0000355 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 }
drhe8f52c52008-07-12 14:52:20 +0000361 pPager = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000362 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
danielk19773b8a05f2007-03-19 17:44:26 +0000363 pPage = sqlite3PagerLookup(pPager, pgno);
drh5c4d9702001-08-20 00:33:58 +0000364 if( pPage ){
drhfe63d1c2004-09-08 20:13:04 +0000365 sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
drh5c4d9702001-08-20 00:33:58 +0000366 Tcl_AppendResult(interp, zBuf, 0);
367 }
368 return TCL_OK;
369}
370
371/*
danielk1977aca790a2005-01-13 11:07:52 +0000372** Usage: pager_truncate ID PGNO
373*/
mistachkin7617e4a2016-07-28 17:11:20 +0000374static int SQLITE_TCLAPI pager_truncate(
danielk1977aca790a2005-01-13 11:07:52 +0000375 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;
danielk1977aca790a2005-01-13 11:07:52 +0000381 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 }
drhe8f52c52008-07-12 14:52:20 +0000387 pPager = sqlite3TestTextToPtr(argv[1]);
danielk1977aca790a2005-01-13 11:07:52 +0000388 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
danielk1977f90b7262009-01-07 15:18:20 +0000389 sqlite3PagerTruncateImage(pPager, pgno);
danielk1977aca790a2005-01-13 11:07:52 +0000390 return TCL_OK;
391}
392
393
394/*
drh5c4d9702001-08-20 00:33:58 +0000395** Usage: page_unref PAGE
396**
397** Drop a pointer to a page.
398*/
mistachkin7617e4a2016-07-28 17:11:20 +0000399static int SQLITE_TCLAPI page_unref(
drh5c4d9702001-08-20 00:33:58 +0000400 void *NotUsed,
401 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
402 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000403 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000404){
danielk19773b8a05f2007-03-19 17:44:26 +0000405 DbPage *pPage;
drh5c4d9702001-08-20 00:33:58 +0000406 if( argc!=2 ){
407 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
408 " PAGE\"", 0);
409 return TCL_ERROR;
410 }
drhe8f52c52008-07-12 14:52:20 +0000411 pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
danielk1977bea2a942009-01-20 17:06:27 +0000412 sqlite3PagerUnref(pPage);
drh5c4d9702001-08-20 00:33:58 +0000413 return TCL_OK;
414}
415
416/*
417** Usage: page_read PAGE
418**
419** Return the content of a page
420*/
mistachkin7617e4a2016-07-28 17:11:20 +0000421static int SQLITE_TCLAPI page_read(
drh5c4d9702001-08-20 00:33:58 +0000422 void *NotUsed,
423 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
424 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000425 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000426){
427 char zBuf[100];
danielk19773b8a05f2007-03-19 17:44:26 +0000428 DbPage *pPage;
drh5c4d9702001-08-20 00:33:58 +0000429 if( argc!=2 ){
430 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
431 " PAGE\"", 0);
432 return TCL_ERROR;
433 }
drhe8f52c52008-07-12 14:52:20 +0000434 pPage = sqlite3TestTextToPtr(argv[1]);
danielk19773b8a05f2007-03-19 17:44:26 +0000435 memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf));
drh5c4d9702001-08-20 00:33:58 +0000436 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*/
mistachkin7617e4a2016-07-28 17:11:20 +0000445static int SQLITE_TCLAPI page_number(
drh5c4d9702001-08-20 00:33:58 +0000446 void *NotUsed,
447 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
448 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000449 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000450){
451 char zBuf[100];
danielk19773b8a05f2007-03-19 17:44:26 +0000452 DbPage *pPage;
drh5c4d9702001-08-20 00:33:58 +0000453 if( argc!=2 ){
454 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
455 " PAGE\"", 0);
456 return TCL_ERROR;
457 }
drhe8f52c52008-07-12 14:52:20 +0000458 pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
danielk19773b8a05f2007-03-19 17:44:26 +0000459 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage));
drh5c4d9702001-08-20 00:33:58 +0000460 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*/
mistachkin7617e4a2016-07-28 17:11:20 +0000469static int SQLITE_TCLAPI page_write(
drh5c4d9702001-08-20 00:33:58 +0000470 void *NotUsed,
471 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
472 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000473 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000474){
danielk19773b8a05f2007-03-19 17:44:26 +0000475 DbPage *pPage;
476 char *pData;
drh5c4d9702001-08-20 00:33:58 +0000477 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 }
drhe8f52c52008-07-12 14:52:20 +0000483 pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
danielk19773b8a05f2007-03-19 17:44:26 +0000484 rc = sqlite3PagerWrite(pPage);
drh5c4d9702001-08-20 00:33:58 +0000485 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000486 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000487 return TCL_ERROR;
488 }
danielk19773b8a05f2007-03-19 17:44:26 +0000489 pData = sqlite3PagerGetData(pPage);
490 strncpy(pData, argv[2], test_pagesize-1);
491 pData[test_pagesize-1] = 0;
drh5c4d9702001-08-20 00:33:58 +0000492 return TCL_OK;
493}
494
danielk197744ee5bf2005-05-27 09:41:12 +0000495#ifndef SQLITE_OMIT_DISKIO
drh5c4d9702001-08-20 00:33:58 +0000496/*
drhd0d006e2002-12-01 02:00:57 +0000497** 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*/
mistachkin7617e4a2016-07-28 17:11:20 +0000505static int SQLITE_TCLAPI fake_big_file(
drhd0d006e2002-12-01 02:00:57 +0000506 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){
danielk1977b4b47412007-08-17 15:53:36 +0000511 sqlite3_vfs *pVfs;
512 sqlite3_file *fd = 0;
drhd0d006e2002-12-01 02:00:57 +0000513 int rc;
514 int n;
drheb206252004-10-01 02:00:31 +0000515 i64 offset;
drh69578ac2012-01-11 00:38:51 +0000516 char *zFile;
517 int nFile;
drhd0d006e2002-12-01 02:00:57 +0000518 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;
drh1da477d2022-11-14 18:57:21 +0000524#if defined(_WIN32)
525 if( n>2 ){
drha70a01d2022-11-14 19:42:01 +0000526 Tcl_AppendResult(interp, "cannot create ", argv[1],
527 "MB file because Windows "
528 "does not support sparse files", (void*)0);
drh1da477d2022-11-14 18:57:21 +0000529 return TCL_ERROR;
530 }
531#endif
danielk1977b4b47412007-08-17 15:53:36 +0000532
drhd677b3d2007-08-20 22:48:41 +0000533 pVfs = sqlite3_vfs_find(0);
drh83cc1392012-04-19 18:04:28 +0000534 nFile = (int)strlen(argv[2]);
drh69578ac2012-01-11 00:38:51 +0000535 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,
danielk1977967a4a12007-08-20 14:23:44 +0000540 (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0
danielk1977fee2d252007-08-18 10:59:19 +0000541 );
drhd0d006e2002-12-01 02:00:57 +0000542 if( rc ){
mistachkine84d8d32013-04-29 03:09:10 +0000543 Tcl_AppendResult(interp, "open failed: ", sqlite3ErrName(rc), 0);
drh69578ac2012-01-11 00:38:51 +0000544 sqlite3_free(zFile);
drhd0d006e2002-12-01 02:00:57 +0000545 return TCL_ERROR;
546 }
547 offset = n;
548 offset *= 1024*1024;
danielk197762079062007-08-15 17:08:46 +0000549 rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
danielk1977b4b47412007-08-17 15:53:36 +0000550 sqlite3OsCloseFree(fd);
drh69578ac2012-01-11 00:38:51 +0000551 sqlite3_free(zFile);
drhd0d006e2002-12-01 02:00:57 +0000552 if( rc ){
mistachkine84d8d32013-04-29 03:09:10 +0000553 Tcl_AppendResult(interp, "write failed: ", sqlite3ErrName(rc), 0);
drhd0d006e2002-12-01 02:00:57 +0000554 return TCL_ERROR;
555 }
drhd0d006e2002-12-01 02:00:57 +0000556 return TCL_OK;
557}
danielk197744ee5bf2005-05-27 09:41:12 +0000558#endif
drhd0d006e2002-12-01 02:00:57 +0000559
drh3088d592008-03-21 16:45:47 +0000560
drhd0d006e2002-12-01 02:00:57 +0000561/*
drhc7a3bb92009-02-05 16:31:45 +0000562** test_control_pending_byte PENDING_BYTE
563**
564** Set the PENDING_BYTE using the sqlite3_test_control() interface.
565*/
mistachkin7617e4a2016-07-28 17:11:20 +0000566static int SQLITE_TCLAPI testPendingByte(
drhc7a3bb92009-02-05 16:31:45 +0000567 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);
dan8d6ad1c2010-05-04 10:36:20 +0000577 return TCL_ERROR;
drhc7a3bb92009-02-05 16:31:45 +0000578 }
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;
drhc007f612014-05-16 14:17:01 +0000583}
584
585/*
586** The sqlite3FaultSim() callback:
587*/
588static Tcl_Interp *faultSimInterp = 0;
589static int faultSimScriptSize = 0;
590static char *faultSimScript;
591static 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*/
mistachkin7617e4a2016-07-28 17:11:20 +0000631static int SQLITE_TCLAPI faultInstallCmd(
drhc007f612014-05-16 14:17:01 +0000632 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}
drhc7a3bb92009-02-05 16:31:45 +0000667
668/*
drh3088d592008-03-21 16:45:47 +0000669** sqlite3BitvecBuiltinTest SIZE PROGRAM
670**
671** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
672** See comments on sqlite3BitvecBuiltinTest() for additional information.
drhf5e7bb52008-02-18 14:47:33 +0000673*/
mistachkin7617e4a2016-07-28 17:11:20 +0000674static int SQLITE_TCLAPI testBitvecBuiltinTest(
drhf5e7bb52008-02-18 14:47:33 +0000675 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){
drh3088d592008-03-21 16:45:47 +0000680 int sz, rc;
681 int nProg = 0;
682 int aProg[100];
683 const char *z;
drhf5e7bb52008-02-18 14:47:33 +0000684 if( argc!=3 ){
drh3088d592008-03-21 16:45:47 +0000685 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
686 " SIZE PROGRAM\"", (void*)0);
drhf5e7bb52008-02-18 14:47:33 +0000687 }
drh3088d592008-03-21 16:45:47 +0000688 if( Tcl_GetInt(interp, argv[1], &sz) ) return TCL_ERROR;
689 z = argv[2];
690 while( nProg<99 && *z ){
danielk197778ca0e72009-01-20 16:53:39 +0000691 while( *z && !sqlite3Isdigit(*z) ){ z++; }
drh3088d592008-03-21 16:45:47 +0000692 if( *z==0 ) break;
693 aProg[nProg++] = atoi(z);
danielk197778ca0e72009-01-20 16:53:39 +0000694 while( sqlite3Isdigit(*z) ){ z++; }
drh3088d592008-03-21 16:45:47 +0000695 }
696 aProg[nProg] = 0;
697 rc = sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST, sz, aProg);
698 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
drhf5e7bb52008-02-18 14:47:33 +0000699 return TCL_OK;
700}
drhf5e7bb52008-02-18 14:47:33 +0000701
702/*
drh5c4d9702001-08-20 00:33:58 +0000703** Register commands with the TCL interpreter.
704*/
705int Sqlitetest2_Init(Tcl_Interp *interp){
drhd5eb79e2007-03-15 12:17:42 +0000706 extern int sqlite3_io_error_persist;
danielk19776f8a5032004-05-10 10:34:51 +0000707 extern int sqlite3_io_error_pending;
drhc9ac5ca2005-11-04 22:03:30 +0000708 extern int sqlite3_io_error_hit;
drh1aa5af12008-03-07 19:51:14 +0000709 extern int sqlite3_io_error_hardhit;
drh047d4832004-10-01 14:38:02 +0000710 extern int sqlite3_diskfull_pending;
drhf307a4a2005-09-09 10:46:19 +0000711 extern int sqlite3_diskfull;
drhc2eef3b2002-08-31 18:53:06 +0000712 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 },
drh3aac2dd2004-04-26 14:10:20 +0000720 { "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 },
drhc2eef3b2002-08-31 18:53:06 +0000723 { "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 },
danielk1977aca790a2005-01-13 11:07:52 +0000731 { "pager_truncate", (Tcl_CmdProc*)pager_truncate },
danielk197744ee5bf2005-05-27 09:41:12 +0000732#ifndef SQLITE_OMIT_DISKIO
drhd0d006e2002-12-01 02:00:57 +0000733 { "fake_big_file", (Tcl_CmdProc*)fake_big_file },
danielk197744ee5bf2005-05-27 09:41:12 +0000734#endif
drhc7a3bb92009-02-05 16:31:45 +0000735 { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest },
drhc007f612014-05-16 14:17:01 +0000736 { "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte },
737 { "sqlite3_test_control_fault_install", (Tcl_CmdProc*)faultInstallCmd },
drhc2eef3b2002-08-31 18:53:06 +0000738 };
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 }
danielk1977369f27e2004-06-15 11:40:04 +0000743 Tcl_LinkVar(interp, "sqlite_io_error_pending",
danielk19776f8a5032004-05-10 10:34:51 +0000744 (char*)&sqlite3_io_error_pending, TCL_LINK_INT);
drhd5eb79e2007-03-15 12:17:42 +0000745 Tcl_LinkVar(interp, "sqlite_io_error_persist",
746 (char*)&sqlite3_io_error_persist, TCL_LINK_INT);
drhc9ac5ca2005-11-04 22:03:30 +0000747 Tcl_LinkVar(interp, "sqlite_io_error_hit",
748 (char*)&sqlite3_io_error_hit, TCL_LINK_INT);
drh1aa5af12008-03-07 19:51:14 +0000749 Tcl_LinkVar(interp, "sqlite_io_error_hardhit",
750 (char*)&sqlite3_io_error_hardhit, TCL_LINK_INT);
drh047d4832004-10-01 14:38:02 +0000751 Tcl_LinkVar(interp, "sqlite_diskfull_pending",
752 (char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
drhf307a4a2005-09-09 10:46:19 +0000753 Tcl_LinkVar(interp, "sqlite_diskfull",
754 (char*)&sqlite3_diskfull, TCL_LINK_INT);
drhf83dc1e2010-06-03 12:09:52 +0000755#ifndef SQLITE_OMIT_WSD
danielk1977fd5f5b62005-09-16 09:52:29 +0000756 Tcl_LinkVar(interp, "sqlite_pending_byte",
drhc7a3bb92009-02-05 16:31:45 +0000757 (char*)&sqlite3PendingByte, TCL_LINK_INT | TCL_LINK_READ_ONLY);
drhf83dc1e2010-06-03 12:09:52 +0000758#endif
drh5c4d9702001-08-20 00:33:58 +0000759 return TCL_OK;
760}