OLD | NEW |
| (Empty) |
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 #include "tcl.h" | |
18 #include <stdlib.h> | |
19 #include <string.h> | |
20 #include <ctype.h> | |
21 | |
22 extern const char *sqlite3ErrName(int); | |
23 | |
24 /* | |
25 ** Page size and reserved size used for testing. | |
26 */ | |
27 static int test_pagesize = 1024; | |
28 | |
29 /* | |
30 ** Dummy page reinitializer | |
31 */ | |
32 static void pager_test_reiniter(DbPage *pNotUsed){ | |
33 return; | |
34 } | |
35 | |
36 /* | |
37 ** Usage: pager_open FILENAME N-PAGE | |
38 ** | |
39 ** Open a new pager | |
40 */ | |
41 static int pager_open( | |
42 void *NotUsed, | |
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 */ | |
46 ){ | |
47 u32 pageSize; | |
48 Pager *pPager; | |
49 int nPage; | |
50 int rc; | |
51 char zBuf[100]; | |
52 if( argc!=3 ){ | |
53 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
54 " FILENAME N-PAGE\"", 0); | |
55 return TCL_ERROR; | |
56 } | |
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, | |
60 pager_test_reiniter); | |
61 if( rc!=SQLITE_OK ){ | |
62 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
63 return TCL_ERROR; | |
64 } | |
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); | |
70 return TCL_OK; | |
71 } | |
72 | |
73 /* | |
74 ** Usage: pager_close ID | |
75 ** | |
76 ** Close the given pager. | |
77 */ | |
78 static int pager_close( | |
79 void *NotUsed, | |
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 */ | |
83 ){ | |
84 Pager *pPager; | |
85 int rc; | |
86 if( argc!=2 ){ | |
87 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
88 " ID\"", 0); | |
89 return TCL_ERROR; | |
90 } | |
91 pPager = sqlite3TestTextToPtr(argv[1]); | |
92 rc = sqlite3PagerClose(pPager); | |
93 if( rc!=SQLITE_OK ){ | |
94 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
95 return TCL_ERROR; | |
96 } | |
97 return TCL_OK; | |
98 } | |
99 | |
100 /* | |
101 ** Usage: pager_rollback ID | |
102 ** | |
103 ** Rollback changes | |
104 */ | |
105 static int pager_rollback( | |
106 void *NotUsed, | |
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 */ | |
110 ){ | |
111 Pager *pPager; | |
112 int rc; | |
113 if( argc!=2 ){ | |
114 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
115 " ID\"", 0); | |
116 return TCL_ERROR; | |
117 } | |
118 pPager = sqlite3TestTextToPtr(argv[1]); | |
119 rc = sqlite3PagerRollback(pPager); | |
120 if( rc!=SQLITE_OK ){ | |
121 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
122 return TCL_ERROR; | |
123 } | |
124 return TCL_OK; | |
125 } | |
126 | |
127 /* | |
128 ** Usage: pager_commit ID | |
129 ** | |
130 ** Commit all changes | |
131 */ | |
132 static int pager_commit( | |
133 void *NotUsed, | |
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 */ | |
137 ){ | |
138 Pager *pPager; | |
139 int rc; | |
140 if( argc!=2 ){ | |
141 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
142 " ID\"", 0); | |
143 return TCL_ERROR; | |
144 } | |
145 pPager = sqlite3TestTextToPtr(argv[1]); | |
146 rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0); | |
147 if( rc!=SQLITE_OK ){ | |
148 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
149 return TCL_ERROR; | |
150 } | |
151 rc = sqlite3PagerCommitPhaseTwo(pPager); | |
152 if( rc!=SQLITE_OK ){ | |
153 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
154 return TCL_ERROR; | |
155 } | |
156 return TCL_OK; | |
157 } | |
158 | |
159 /* | |
160 ** Usage: pager_stmt_begin ID | |
161 ** | |
162 ** Start a new checkpoint. | |
163 */ | |
164 static int pager_stmt_begin( | |
165 void *NotUsed, | |
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 */ | |
169 ){ | |
170 Pager *pPager; | |
171 int rc; | |
172 if( argc!=2 ){ | |
173 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
174 " ID\"", 0); | |
175 return TCL_ERROR; | |
176 } | |
177 pPager = sqlite3TestTextToPtr(argv[1]); | |
178 rc = sqlite3PagerOpenSavepoint(pPager, 1); | |
179 if( rc!=SQLITE_OK ){ | |
180 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
181 return TCL_ERROR; | |
182 } | |
183 return TCL_OK; | |
184 } | |
185 | |
186 /* | |
187 ** Usage: pager_stmt_rollback ID | |
188 ** | |
189 ** Rollback changes to a checkpoint | |
190 */ | |
191 static int pager_stmt_rollback( | |
192 void *NotUsed, | |
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 */ | |
196 ){ | |
197 Pager *pPager; | |
198 int rc; | |
199 if( argc!=2 ){ | |
200 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
201 " ID\"", 0); | |
202 return TCL_ERROR; | |
203 } | |
204 pPager = sqlite3TestTextToPtr(argv[1]); | |
205 rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0); | |
206 sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0); | |
207 if( rc!=SQLITE_OK ){ | |
208 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
209 return TCL_ERROR; | |
210 } | |
211 return TCL_OK; | |
212 } | |
213 | |
214 /* | |
215 ** Usage: pager_stmt_commit ID | |
216 ** | |
217 ** Commit changes to a checkpoint | |
218 */ | |
219 static int pager_stmt_commit( | |
220 void *NotUsed, | |
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 */ | |
224 ){ | |
225 Pager *pPager; | |
226 int rc; | |
227 if( argc!=2 ){ | |
228 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
229 " ID\"", 0); | |
230 return TCL_ERROR; | |
231 } | |
232 pPager = sqlite3TestTextToPtr(argv[1]); | |
233 rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0); | |
234 if( rc!=SQLITE_OK ){ | |
235 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
236 return TCL_ERROR; | |
237 } | |
238 return TCL_OK; | |
239 } | |
240 | |
241 /* | |
242 ** Usage: pager_stats ID | |
243 ** | |
244 ** Return pager statistics. | |
245 */ | |
246 static int pager_stats( | |
247 void *NotUsed, | |
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 */ | |
251 ){ | |
252 Pager *pPager; | |
253 int i, *a; | |
254 if( argc!=2 ){ | |
255 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
256 " ID\"", 0); | |
257 return TCL_ERROR; | |
258 } | |
259 pPager = sqlite3TestTextToPtr(argv[1]); | |
260 a = sqlite3PagerStats(pPager); | |
261 for(i=0; i<9; i++){ | |
262 static char *zName[] = { | |
263 "ref", "page", "max", "size", "state", "err", | |
264 "hit", "miss", "ovfl", | |
265 }; | |
266 char zBuf[100]; | |
267 Tcl_AppendElement(interp, zName[i]); | |
268 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",a[i]); | |
269 Tcl_AppendElement(interp, zBuf); | |
270 } | |
271 return TCL_OK; | |
272 } | |
273 | |
274 /* | |
275 ** Usage: pager_pagecount ID | |
276 ** | |
277 ** Return the size of the database file. | |
278 */ | |
279 static int pager_pagecount( | |
280 void *NotUsed, | |
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 */ | |
284 ){ | |
285 Pager *pPager; | |
286 char zBuf[100]; | |
287 int nPage; | |
288 if( argc!=2 ){ | |
289 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
290 " ID\"", 0); | |
291 return TCL_ERROR; | |
292 } | |
293 pPager = sqlite3TestTextToPtr(argv[1]); | |
294 sqlite3PagerPagecount(pPager, &nPage); | |
295 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nPage); | |
296 Tcl_AppendResult(interp, zBuf, 0); | |
297 return TCL_OK; | |
298 } | |
299 | |
300 /* | |
301 ** Usage: page_get ID PGNO | |
302 ** | |
303 ** Return a pointer to a page from the database. | |
304 */ | |
305 static int page_get( | |
306 void *NotUsed, | |
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 */ | |
310 ){ | |
311 Pager *pPager; | |
312 char zBuf[100]; | |
313 DbPage *pPage; | |
314 int pgno; | |
315 int rc; | |
316 if( argc!=3 ){ | |
317 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
318 " ID PGNO\"", 0); | |
319 return TCL_ERROR; | |
320 } | |
321 pPager = sqlite3TestTextToPtr(argv[1]); | |
322 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; | |
323 rc = sqlite3PagerSharedLock(pPager); | |
324 if( rc==SQLITE_OK ){ | |
325 rc = sqlite3PagerGet(pPager, pgno, &pPage); | |
326 } | |
327 if( rc!=SQLITE_OK ){ | |
328 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
329 return TCL_ERROR; | |
330 } | |
331 sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage); | |
332 Tcl_AppendResult(interp, zBuf, 0); | |
333 return TCL_OK; | |
334 } | |
335 | |
336 /* | |
337 ** Usage: page_lookup ID PGNO | |
338 ** | |
339 ** Return a pointer to a page if the page is already in cache. | |
340 ** If not in cache, return an empty string. | |
341 */ | |
342 static int page_lookup( | |
343 void *NotUsed, | |
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 */ | |
347 ){ | |
348 Pager *pPager; | |
349 char zBuf[100]; | |
350 DbPage *pPage; | |
351 int pgno; | |
352 if( argc!=3 ){ | |
353 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
354 " ID PGNO\"", 0); | |
355 return TCL_ERROR; | |
356 } | |
357 pPager = sqlite3TestTextToPtr(argv[1]); | |
358 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; | |
359 pPage = sqlite3PagerLookup(pPager, pgno); | |
360 if( pPage ){ | |
361 sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage); | |
362 Tcl_AppendResult(interp, zBuf, 0); | |
363 } | |
364 return TCL_OK; | |
365 } | |
366 | |
367 /* | |
368 ** Usage: pager_truncate ID PGNO | |
369 */ | |
370 static int pager_truncate( | |
371 void *NotUsed, | |
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 */ | |
375 ){ | |
376 Pager *pPager; | |
377 int pgno; | |
378 if( argc!=3 ){ | |
379 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
380 " ID PGNO\"", 0); | |
381 return TCL_ERROR; | |
382 } | |
383 pPager = sqlite3TestTextToPtr(argv[1]); | |
384 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; | |
385 sqlite3PagerTruncateImage(pPager, pgno); | |
386 return TCL_OK; | |
387 } | |
388 | |
389 | |
390 /* | |
391 ** Usage: page_unref PAGE | |
392 ** | |
393 ** Drop a pointer to a page. | |
394 */ | |
395 static int page_unref( | |
396 void *NotUsed, | |
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 */ | |
400 ){ | |
401 DbPage *pPage; | |
402 if( argc!=2 ){ | |
403 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
404 " PAGE\"", 0); | |
405 return TCL_ERROR; | |
406 } | |
407 pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]); | |
408 sqlite3PagerUnref(pPage); | |
409 return TCL_OK; | |
410 } | |
411 | |
412 /* | |
413 ** Usage: page_read PAGE | |
414 ** | |
415 ** Return the content of a page | |
416 */ | |
417 static int page_read( | |
418 void *NotUsed, | |
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 */ | |
422 ){ | |
423 char zBuf[100]; | |
424 DbPage *pPage; | |
425 if( argc!=2 ){ | |
426 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
427 " PAGE\"", 0); | |
428 return TCL_ERROR; | |
429 } | |
430 pPage = sqlite3TestTextToPtr(argv[1]); | |
431 memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf)); | |
432 Tcl_AppendResult(interp, zBuf, 0); | |
433 return TCL_OK; | |
434 } | |
435 | |
436 /* | |
437 ** Usage: page_number PAGE | |
438 ** | |
439 ** Return the page number for a page. | |
440 */ | |
441 static int page_number( | |
442 void *NotUsed, | |
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 */ | |
446 ){ | |
447 char zBuf[100]; | |
448 DbPage *pPage; | |
449 if( argc!=2 ){ | |
450 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
451 " PAGE\"", 0); | |
452 return TCL_ERROR; | |
453 } | |
454 pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]); | |
455 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage)); | |
456 Tcl_AppendResult(interp, zBuf, 0); | |
457 return TCL_OK; | |
458 } | |
459 | |
460 /* | |
461 ** Usage: page_write PAGE DATA | |
462 ** | |
463 ** Write something into a page. | |
464 */ | |
465 static int page_write( | |
466 void *NotUsed, | |
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 */ | |
470 ){ | |
471 DbPage *pPage; | |
472 char *pData; | |
473 int rc; | |
474 if( argc!=3 ){ | |
475 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
476 " PAGE DATA\"", 0); | |
477 return TCL_ERROR; | |
478 } | |
479 pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]); | |
480 rc = sqlite3PagerWrite(pPage); | |
481 if( rc!=SQLITE_OK ){ | |
482 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
483 return TCL_ERROR; | |
484 } | |
485 pData = sqlite3PagerGetData(pPage); | |
486 strncpy(pData, argv[2], test_pagesize-1); | |
487 pData[test_pagesize-1] = 0; | |
488 return TCL_OK; | |
489 } | |
490 | |
491 #ifndef SQLITE_OMIT_DISKIO | |
492 /* | |
493 ** Usage: fake_big_file N FILENAME | |
494 ** | |
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. | |
500 */ | |
501 static int fake_big_file( | |
502 void *NotUsed, | |
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 */ | |
506 ){ | |
507 sqlite3_vfs *pVfs; | |
508 sqlite3_file *fd = 0; | |
509 int rc; | |
510 int n; | |
511 i64 offset; | |
512 char *zFile; | |
513 int nFile; | |
514 if( argc!=3 ){ | |
515 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
516 " N-MEGABYTES FILE\"", 0); | |
517 return TCL_ERROR; | |
518 } | |
519 if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; | |
520 | |
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); | |
526 zFile[nFile+1] = 0; | |
527 rc = sqlite3OsOpenMalloc(pVfs, zFile, &fd, | |
528 (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0 | |
529 ); | |
530 if( rc ){ | |
531 Tcl_AppendResult(interp, "open failed: ", sqlite3ErrName(rc), 0); | |
532 sqlite3_free(zFile); | |
533 return TCL_ERROR; | |
534 } | |
535 offset = n; | |
536 offset *= 1024*1024; | |
537 rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset); | |
538 sqlite3OsCloseFree(fd); | |
539 sqlite3_free(zFile); | |
540 if( rc ){ | |
541 Tcl_AppendResult(interp, "write failed: ", sqlite3ErrName(rc), 0); | |
542 return TCL_ERROR; | |
543 } | |
544 return TCL_OK; | |
545 } | |
546 #endif | |
547 | |
548 | |
549 /* | |
550 ** test_control_pending_byte PENDING_BYTE | |
551 ** | |
552 ** Set the PENDING_BYTE using the sqlite3_test_control() interface. | |
553 */ | |
554 static int testPendingByte( | |
555 void *NotUsed, | |
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 */ | |
559 ){ | |
560 int pbyte; | |
561 int rc; | |
562 if( argc!=2 ){ | |
563 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
564 " PENDING-BYTE\"", (void*)0); | |
565 return TCL_ERROR; | |
566 } | |
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)); | |
570 return TCL_OK; | |
571 } | |
572 | |
573 /* | |
574 ** The sqlite3FaultSim() callback: | |
575 */ | |
576 static Tcl_Interp *faultSimInterp = 0; | |
577 static int faultSimScriptSize = 0; | |
578 static char *faultSimScript; | |
579 static int faultSimCallback(int x){ | |
580 char zInt[30]; | |
581 int i; | |
582 int isNeg; | |
583 int rc; | |
584 if( x==0 ){ | |
585 memcpy(faultSimScript+faultSimScriptSize, "0", 2); | |
586 }else{ | |
587 /* Convert x to text without using any sqlite3 routines */ | |
588 if( x<0 ){ | |
589 isNeg = 1; | |
590 x = -x; | |
591 }else{ | |
592 isNeg = 0; | |
593 } | |
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'; | |
597 } | |
598 if( isNeg ) zInt[i--] = '-'; | |
599 memcpy(faultSimScript+faultSimScriptSize, zInt+i+1, sizeof(zInt)-i); | |
600 } | |
601 rc = Tcl_Eval(faultSimInterp, faultSimScript); | |
602 if( rc ){ | |
603 fprintf(stderr, "fault simulator script failed: [%s]", faultSimScript); | |
604 rc = SQLITE_ERROR; | |
605 }else{ | |
606 rc = atoi(Tcl_GetStringResult(faultSimInterp)); | |
607 } | |
608 Tcl_ResetResult(faultSimInterp); | |
609 return rc; | |
610 } | |
611 | |
612 /* | |
613 ** sqlite3_test_control_fault_install SCRIPT | |
614 ** | |
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. | |
618 */ | |
619 static int faultInstallCmd( | |
620 void *NotUsed, | |
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 */ | |
624 ){ | |
625 const char *zScript; | |
626 int nScript; | |
627 int rc; | |
628 if( argc!=1 && argc!=2 ){ | |
629 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
630 " SCRIPT\"", (void*)0); | |
631 } | |
632 zScript = argc==2 ? argv[1] : ""; | |
633 nScript = (int)strlen(zScript); | |
634 if( faultSimScript ){ | |
635 free(faultSimScript); | |
636 faultSimScript = 0; | |
637 } | |
638 if( nScript==0 ){ | |
639 rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, 0); | |
640 }else{ | |
641 faultSimScript = malloc( nScript+100 ); | |
642 if( faultSimScript==0 ){ | |
643 Tcl_AppendResult(interp, "out of memory", (void*)0); | |
644 return SQLITE_ERROR; | |
645 } | |
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); | |
651 } | |
652 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); | |
653 return SQLITE_OK; | |
654 } | |
655 | |
656 /* | |
657 ** sqlite3BitvecBuiltinTest SIZE PROGRAM | |
658 ** | |
659 ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control. | |
660 ** See comments on sqlite3BitvecBuiltinTest() for additional information. | |
661 */ | |
662 static int testBitvecBuiltinTest( | |
663 void *NotUsed, | |
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 */ | |
667 ){ | |
668 int sz, rc; | |
669 int nProg = 0; | |
670 int aProg[100]; | |
671 const char *z; | |
672 if( argc!=3 ){ | |
673 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
674 " SIZE PROGRAM\"", (void*)0); | |
675 } | |
676 if( Tcl_GetInt(interp, argv[1], &sz) ) return TCL_ERROR; | |
677 z = argv[2]; | |
678 while( nProg<99 && *z ){ | |
679 while( *z && !sqlite3Isdigit(*z) ){ z++; } | |
680 if( *z==0 ) break; | |
681 aProg[nProg++] = atoi(z); | |
682 while( sqlite3Isdigit(*z) ){ z++; } | |
683 } | |
684 aProg[nProg] = 0; | |
685 rc = sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST, sz, aProg); | |
686 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); | |
687 return TCL_OK; | |
688 } | |
689 | |
690 /* | |
691 ** Register commands with the TCL interpreter. | |
692 */ | |
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; | |
700 static struct { | |
701 char *zName; | |
702 Tcl_CmdProc *xProc; | |
703 } aCmd[] = { | |
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 }, | |
722 #endif | |
723 { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest }, | |
724 { "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte }, | |
725 { "sqlite3_test_control_fault_install", (Tcl_CmdProc*)faultInstallCmd }, | |
726 }; | |
727 int i; | |
728 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | |
729 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | |
730 } | |
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); | |
746 #endif | |
747 return TCL_OK; | |
748 } | |
OLD | NEW |