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