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 ** $Id: test2.c,v 1.52 2007/09/03 15:19:35 drh Exp $ 17 */ 18 #include "sqliteInt.h" 19 #include "tcl.h" 20 #include <stdlib.h> 21 #include <string.h> 22 23 /* 24 ** Interpret an SQLite error number 25 */ 26 static char *errorName(int rc){ 27 char *zName; 28 switch( rc ){ 29 case SQLITE_OK: zName = "SQLITE_OK"; break; 30 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; 31 case SQLITE_PERM: zName = "SQLITE_PERM"; break; 32 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; 33 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; 34 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; 35 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; 36 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; 37 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; 38 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; 39 case SQLITE_FULL: zName = "SQLITE_FULL"; break; 40 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; 41 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; 42 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; 43 case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; 44 case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; 45 case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; 46 case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; 47 case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; 48 default: zName = "SQLITE_Unknown"; break; 49 } 50 return zName; 51 } 52 53 /* 54 ** Page size and reserved size used for testing. 55 */ 56 static int test_pagesize = 1024; 57 58 /* 59 ** Usage: pager_open FILENAME N-PAGE 60 ** 61 ** Open a new pager 62 */ 63 static int pager_open( 64 void *NotUsed, 65 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 66 int argc, /* Number of arguments */ 67 const char **argv /* Text of each argument */ 68 ){ 69 u16 pageSize; 70 Pager *pPager; 71 int nPage; 72 int rc; 73 char zBuf[100]; 74 if( argc!=3 ){ 75 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 76 " FILENAME N-PAGE\"", 0); 77 return TCL_ERROR; 78 } 79 if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR; 80 rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0, 81 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); 82 if( rc!=SQLITE_OK ){ 83 Tcl_AppendResult(interp, errorName(rc), 0); 84 return TCL_ERROR; 85 } 86 sqlite3PagerSetCachesize(pPager, nPage); 87 pageSize = test_pagesize; 88 sqlite3PagerSetPagesize(pPager, &pageSize); 89 sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager); 90 Tcl_AppendResult(interp, zBuf, 0); 91 return TCL_OK; 92 } 93 94 /* 95 ** Usage: pager_close ID 96 ** 97 ** Close the given pager. 98 */ 99 static int pager_close( 100 void *NotUsed, 101 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 102 int argc, /* Number of arguments */ 103 const char **argv /* Text of each argument */ 104 ){ 105 Pager *pPager; 106 int rc; 107 if( argc!=2 ){ 108 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 109 " ID\"", 0); 110 return TCL_ERROR; 111 } 112 pPager = sqlite3TextToPtr(argv[1]); 113 rc = sqlite3PagerClose(pPager); 114 if( rc!=SQLITE_OK ){ 115 Tcl_AppendResult(interp, errorName(rc), 0); 116 return TCL_ERROR; 117 } 118 return TCL_OK; 119 } 120 121 /* 122 ** Usage: pager_rollback ID 123 ** 124 ** Rollback changes 125 */ 126 static int pager_rollback( 127 void *NotUsed, 128 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 129 int argc, /* Number of arguments */ 130 const char **argv /* Text of each argument */ 131 ){ 132 Pager *pPager; 133 int rc; 134 if( argc!=2 ){ 135 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 136 " ID\"", 0); 137 return TCL_ERROR; 138 } 139 pPager = sqlite3TextToPtr(argv[1]); 140 rc = sqlite3PagerRollback(pPager); 141 if( rc!=SQLITE_OK ){ 142 Tcl_AppendResult(interp, errorName(rc), 0); 143 return TCL_ERROR; 144 } 145 return TCL_OK; 146 } 147 148 /* 149 ** Usage: pager_commit ID 150 ** 151 ** Commit all changes 152 */ 153 static int pager_commit( 154 void *NotUsed, 155 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 156 int argc, /* Number of arguments */ 157 const char **argv /* Text of each argument */ 158 ){ 159 Pager *pPager; 160 int rc; 161 if( argc!=2 ){ 162 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 163 " ID\"", 0); 164 return TCL_ERROR; 165 } 166 pPager = sqlite3TextToPtr(argv[1]); 167 rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0); 168 if( rc!=SQLITE_OK ){ 169 Tcl_AppendResult(interp, errorName(rc), 0); 170 return TCL_ERROR; 171 } 172 rc = sqlite3PagerCommitPhaseTwo(pPager); 173 if( rc!=SQLITE_OK ){ 174 Tcl_AppendResult(interp, errorName(rc), 0); 175 return TCL_ERROR; 176 } 177 return TCL_OK; 178 } 179 180 /* 181 ** Usage: pager_stmt_begin ID 182 ** 183 ** Start a new checkpoint. 184 */ 185 static int pager_stmt_begin( 186 void *NotUsed, 187 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 188 int argc, /* Number of arguments */ 189 const char **argv /* Text of each argument */ 190 ){ 191 Pager *pPager; 192 int rc; 193 if( argc!=2 ){ 194 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 195 " ID\"", 0); 196 return TCL_ERROR; 197 } 198 pPager = sqlite3TextToPtr(argv[1]); 199 rc = sqlite3PagerStmtBegin(pPager); 200 if( rc!=SQLITE_OK ){ 201 Tcl_AppendResult(interp, errorName(rc), 0); 202 return TCL_ERROR; 203 } 204 return TCL_OK; 205 } 206 207 /* 208 ** Usage: pager_stmt_rollback ID 209 ** 210 ** Rollback changes to a checkpoint 211 */ 212 static int pager_stmt_rollback( 213 void *NotUsed, 214 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 215 int argc, /* Number of arguments */ 216 const char **argv /* Text of each argument */ 217 ){ 218 Pager *pPager; 219 int rc; 220 if( argc!=2 ){ 221 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 222 " ID\"", 0); 223 return TCL_ERROR; 224 } 225 pPager = sqlite3TextToPtr(argv[1]); 226 rc = sqlite3PagerStmtRollback(pPager); 227 if( rc!=SQLITE_OK ){ 228 Tcl_AppendResult(interp, errorName(rc), 0); 229 return TCL_ERROR; 230 } 231 return TCL_OK; 232 } 233 234 /* 235 ** Usage: pager_stmt_commit ID 236 ** 237 ** Commit changes to a checkpoint 238 */ 239 static int pager_stmt_commit( 240 void *NotUsed, 241 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 242 int argc, /* Number of arguments */ 243 const char **argv /* Text of each argument */ 244 ){ 245 Pager *pPager; 246 int rc; 247 if( argc!=2 ){ 248 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 249 " ID\"", 0); 250 return TCL_ERROR; 251 } 252 pPager = sqlite3TextToPtr(argv[1]); 253 rc = sqlite3PagerStmtCommit(pPager); 254 if( rc!=SQLITE_OK ){ 255 Tcl_AppendResult(interp, errorName(rc), 0); 256 return TCL_ERROR; 257 } 258 return TCL_OK; 259 } 260 261 /* 262 ** Usage: pager_stats ID 263 ** 264 ** Return pager statistics. 265 */ 266 static int pager_stats( 267 void *NotUsed, 268 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 269 int argc, /* Number of arguments */ 270 const char **argv /* Text of each argument */ 271 ){ 272 Pager *pPager; 273 int i, *a; 274 if( argc!=2 ){ 275 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 276 " ID\"", 0); 277 return TCL_ERROR; 278 } 279 pPager = sqlite3TextToPtr(argv[1]); 280 a = sqlite3PagerStats(pPager); 281 for(i=0; i<9; i++){ 282 static char *zName[] = { 283 "ref", "page", "max", "size", "state", "err", 284 "hit", "miss", "ovfl", 285 }; 286 char zBuf[100]; 287 Tcl_AppendElement(interp, zName[i]); 288 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",a[i]); 289 Tcl_AppendElement(interp, zBuf); 290 } 291 return TCL_OK; 292 } 293 294 /* 295 ** Usage: pager_pagecount ID 296 ** 297 ** Return the size of the database file. 298 */ 299 static int pager_pagecount( 300 void *NotUsed, 301 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 302 int argc, /* Number of arguments */ 303 const char **argv /* Text of each argument */ 304 ){ 305 Pager *pPager; 306 char zBuf[100]; 307 if( argc!=2 ){ 308 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 309 " ID\"", 0); 310 return TCL_ERROR; 311 } 312 pPager = sqlite3TextToPtr(argv[1]); 313 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3PagerPagecount(pPager)); 314 Tcl_AppendResult(interp, zBuf, 0); 315 return TCL_OK; 316 } 317 318 /* 319 ** Usage: page_get ID PGNO 320 ** 321 ** Return a pointer to a page from the database. 322 */ 323 static int page_get( 324 void *NotUsed, 325 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 326 int argc, /* Number of arguments */ 327 const char **argv /* Text of each argument */ 328 ){ 329 Pager *pPager; 330 char zBuf[100]; 331 DbPage *pPage; 332 int pgno; 333 int rc; 334 if( argc!=3 ){ 335 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 336 " ID PGNO\"", 0); 337 return TCL_ERROR; 338 } 339 pPager = sqlite3TextToPtr(argv[1]); 340 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; 341 rc = sqlite3PagerGet(pPager, pgno, &pPage); 342 if( rc!=SQLITE_OK ){ 343 Tcl_AppendResult(interp, errorName(rc), 0); 344 return TCL_ERROR; 345 } 346 sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage); 347 Tcl_AppendResult(interp, zBuf, 0); 348 return TCL_OK; 349 } 350 351 /* 352 ** Usage: page_lookup ID PGNO 353 ** 354 ** Return a pointer to a page if the page is already in cache. 355 ** If not in cache, return an empty string. 356 */ 357 static int page_lookup( 358 void *NotUsed, 359 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 360 int argc, /* Number of arguments */ 361 const char **argv /* Text of each argument */ 362 ){ 363 Pager *pPager; 364 char zBuf[100]; 365 DbPage *pPage; 366 int pgno; 367 if( argc!=3 ){ 368 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 369 " ID PGNO\"", 0); 370 return TCL_ERROR; 371 } 372 pPager = sqlite3TextToPtr(argv[1]); 373 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; 374 pPage = sqlite3PagerLookup(pPager, pgno); 375 if( pPage ){ 376 sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage); 377 Tcl_AppendResult(interp, zBuf, 0); 378 } 379 return TCL_OK; 380 } 381 382 /* 383 ** Usage: pager_truncate ID PGNO 384 */ 385 static int pager_truncate( 386 void *NotUsed, 387 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 388 int argc, /* Number of arguments */ 389 const char **argv /* Text of each argument */ 390 ){ 391 Pager *pPager; 392 int rc; 393 int pgno; 394 if( argc!=3 ){ 395 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 396 " ID PGNO\"", 0); 397 return TCL_ERROR; 398 } 399 pPager = sqlite3TextToPtr(argv[1]); 400 if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; 401 rc = sqlite3PagerTruncate(pPager, pgno); 402 if( rc!=SQLITE_OK ){ 403 Tcl_AppendResult(interp, errorName(rc), 0); 404 return TCL_ERROR; 405 } 406 return TCL_OK; 407 } 408 409 410 /* 411 ** Usage: page_unref PAGE 412 ** 413 ** Drop a pointer to a page. 414 */ 415 static int page_unref( 416 void *NotUsed, 417 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 418 int argc, /* Number of arguments */ 419 const char **argv /* Text of each argument */ 420 ){ 421 DbPage *pPage; 422 int rc; 423 if( argc!=2 ){ 424 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 425 " PAGE\"", 0); 426 return TCL_ERROR; 427 } 428 pPage = (DbPage *)sqlite3TextToPtr(argv[1]); 429 rc = sqlite3PagerUnref(pPage); 430 if( rc!=SQLITE_OK ){ 431 Tcl_AppendResult(interp, errorName(rc), 0); 432 return TCL_ERROR; 433 } 434 return TCL_OK; 435 } 436 437 /* 438 ** Usage: page_read PAGE 439 ** 440 ** Return the content of a page 441 */ 442 static int page_read( 443 void *NotUsed, 444 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 445 int argc, /* Number of arguments */ 446 const char **argv /* Text of each argument */ 447 ){ 448 char zBuf[100]; 449 DbPage *pPage; 450 if( argc!=2 ){ 451 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 452 " PAGE\"", 0); 453 return TCL_ERROR; 454 } 455 pPage = sqlite3TextToPtr(argv[1]); 456 memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf)); 457 Tcl_AppendResult(interp, zBuf, 0); 458 return TCL_OK; 459 } 460 461 /* 462 ** Usage: page_number PAGE 463 ** 464 ** Return the page number for a page. 465 */ 466 static int page_number( 467 void *NotUsed, 468 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 469 int argc, /* Number of arguments */ 470 const char **argv /* Text of each argument */ 471 ){ 472 char zBuf[100]; 473 DbPage *pPage; 474 if( argc!=2 ){ 475 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 476 " PAGE\"", 0); 477 return TCL_ERROR; 478 } 479 pPage = (DbPage *)sqlite3TextToPtr(argv[1]); 480 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage)); 481 Tcl_AppendResult(interp, zBuf, 0); 482 return TCL_OK; 483 } 484 485 /* 486 ** Usage: page_write PAGE DATA 487 ** 488 ** Write something into a page. 489 */ 490 static int page_write( 491 void *NotUsed, 492 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 493 int argc, /* Number of arguments */ 494 const char **argv /* Text of each argument */ 495 ){ 496 DbPage *pPage; 497 char *pData; 498 int rc; 499 if( argc!=3 ){ 500 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 501 " PAGE DATA\"", 0); 502 return TCL_ERROR; 503 } 504 pPage = (DbPage *)sqlite3TextToPtr(argv[1]); 505 rc = sqlite3PagerWrite(pPage); 506 if( rc!=SQLITE_OK ){ 507 Tcl_AppendResult(interp, errorName(rc), 0); 508 return TCL_ERROR; 509 } 510 pData = sqlite3PagerGetData(pPage); 511 strncpy(pData, argv[2], test_pagesize-1); 512 pData[test_pagesize-1] = 0; 513 return TCL_OK; 514 } 515 516 #ifndef SQLITE_OMIT_DISKIO 517 /* 518 ** Usage: fake_big_file N FILENAME 519 ** 520 ** Write a few bytes at the N megabyte point of FILENAME. This will 521 ** create a large file. If the file was a valid SQLite database, then 522 ** the next time the database is opened, SQLite will begin allocating 523 ** new pages after N. If N is 2096 or bigger, this will test the 524 ** ability of SQLite to write to large files. 525 */ 526 static int fake_big_file( 527 void *NotUsed, 528 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 529 int argc, /* Number of arguments */ 530 const char **argv /* Text of each argument */ 531 ){ 532 sqlite3_vfs *pVfs; 533 sqlite3_file *fd = 0; 534 int rc; 535 int n; 536 i64 offset; 537 if( argc!=3 ){ 538 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 539 " N-MEGABYTES FILE\"", 0); 540 return TCL_ERROR; 541 } 542 if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 543 544 pVfs = sqlite3_vfs_find(0); 545 rc = sqlite3OsOpenMalloc(pVfs, argv[2], &fd, 546 (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0 547 ); 548 if( rc ){ 549 Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0); 550 return TCL_ERROR; 551 } 552 offset = n; 553 offset *= 1024*1024; 554 rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset); 555 sqlite3OsCloseFree(fd); 556 if( rc ){ 557 Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0); 558 return TCL_ERROR; 559 } 560 return TCL_OK; 561 } 562 #endif 563 564 /* 565 ** Register commands with the TCL interpreter. 566 */ 567 int Sqlitetest2_Init(Tcl_Interp *interp){ 568 extern int sqlite3_io_error_persist; 569 extern int sqlite3_io_error_pending; 570 extern int sqlite3_io_error_hit; 571 extern int sqlite3_diskfull_pending; 572 extern int sqlite3_diskfull; 573 extern int sqlite3_pager_n_sort_bucket; 574 static struct { 575 char *zName; 576 Tcl_CmdProc *xProc; 577 } aCmd[] = { 578 { "pager_open", (Tcl_CmdProc*)pager_open }, 579 { "pager_close", (Tcl_CmdProc*)pager_close }, 580 { "pager_commit", (Tcl_CmdProc*)pager_commit }, 581 { "pager_rollback", (Tcl_CmdProc*)pager_rollback }, 582 { "pager_stmt_begin", (Tcl_CmdProc*)pager_stmt_begin }, 583 { "pager_stmt_commit", (Tcl_CmdProc*)pager_stmt_commit }, 584 { "pager_stmt_rollback", (Tcl_CmdProc*)pager_stmt_rollback }, 585 { "pager_stats", (Tcl_CmdProc*)pager_stats }, 586 { "pager_pagecount", (Tcl_CmdProc*)pager_pagecount }, 587 { "page_get", (Tcl_CmdProc*)page_get }, 588 { "page_lookup", (Tcl_CmdProc*)page_lookup }, 589 { "page_unref", (Tcl_CmdProc*)page_unref }, 590 { "page_read", (Tcl_CmdProc*)page_read }, 591 { "page_write", (Tcl_CmdProc*)page_write }, 592 { "page_number", (Tcl_CmdProc*)page_number }, 593 { "pager_truncate", (Tcl_CmdProc*)pager_truncate }, 594 #ifndef SQLITE_OMIT_DISKIO 595 { "fake_big_file", (Tcl_CmdProc*)fake_big_file }, 596 #endif 597 }; 598 int i; 599 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 600 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 601 } 602 Tcl_LinkVar(interp, "sqlite_io_error_pending", 603 (char*)&sqlite3_io_error_pending, TCL_LINK_INT); 604 Tcl_LinkVar(interp, "sqlite_io_error_persist", 605 (char*)&sqlite3_io_error_persist, TCL_LINK_INT); 606 Tcl_LinkVar(interp, "sqlite_io_error_hit", 607 (char*)&sqlite3_io_error_hit, TCL_LINK_INT); 608 Tcl_LinkVar(interp, "sqlite_diskfull_pending", 609 (char*)&sqlite3_diskfull_pending, TCL_LINK_INT); 610 Tcl_LinkVar(interp, "sqlite_diskfull", 611 (char*)&sqlite3_diskfull, TCL_LINK_INT); 612 Tcl_LinkVar(interp, "sqlite_pending_byte", 613 (char*)&sqlite3_pending_byte, TCL_LINK_INT); 614 Tcl_LinkVar(interp, "pager_pagesize", 615 (char*)&test_pagesize, TCL_LINK_INT); 616 Tcl_LinkVar(interp, "sqlite_pager_n_sort_bucket", 617 (char*)&sqlite3_pager_n_sort_bucket, TCL_LINK_INT); 618 return TCL_OK; 619 } 620