modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test2.c (about)

     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  #if defined(INCLUDE_SQLITE_TCL_H)
    18  #  include "sqlite_tcl.h"
    19  #else
    20  #  include "tcl.h"
    21  #endif
    22  #include <stdlib.h>
    23  #include <string.h>
    24  #include <ctype.h>
    25  
    26  extern const char *sqlite3ErrName(int);
    27  
    28  /*
    29  ** Page size and reserved size used for testing.
    30  */
    31  static int test_pagesize = 1024;
    32  
    33  /*
    34  ** Dummy page reinitializer
    35  */
    36  static void pager_test_reiniter(DbPage *pNotUsed){
    37    return;
    38  }
    39  
    40  /*
    41  ** Usage:   pager_open FILENAME N-PAGE
    42  **
    43  ** Open a new pager
    44  */
    45  static int SQLITE_TCLAPI pager_open(
    46    void *NotUsed,
    47    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
    48    int argc,              /* Number of arguments */
    49    const char **argv      /* Text of each argument */
    50  ){
    51    u32 pageSize;
    52    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;
    62    rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0,
    63        SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
    64        pager_test_reiniter);
    65    if( rc!=SQLITE_OK ){
    66      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    67      return TCL_ERROR;
    68    }
    69    sqlite3PagerSetCachesize(pPager, nPage);
    70    pageSize = test_pagesize;
    71    sqlite3PagerSetPagesize(pPager, &pageSize, -1);
    72    sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
    73    Tcl_AppendResult(interp, zBuf, 0);
    74    return TCL_OK;
    75  }
    76  
    77  /*
    78  ** Usage:   pager_close ID
    79  **
    80  ** Close the given pager.
    81  */
    82  static int SQLITE_TCLAPI pager_close(
    83    void *NotUsed,
    84    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
    85    int argc,              /* Number of arguments */
    86    const char **argv      /* Text of each argument */
    87  ){
    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    }
    95    pPager = sqlite3TestTextToPtr(argv[1]);
    96    rc = sqlite3PagerClose(pPager, 0);
    97    if( rc!=SQLITE_OK ){
    98      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    99      return TCL_ERROR;
   100    }
   101    return TCL_OK;
   102  }
   103  
   104  /*
   105  ** Usage:   pager_rollback ID
   106  **
   107  ** Rollback changes
   108  */
   109  static int SQLITE_TCLAPI pager_rollback(
   110    void *NotUsed,
   111    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   112    int argc,              /* Number of arguments */
   113    const char **argv      /* Text of each argument */
   114  ){
   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    }
   122    pPager = sqlite3TestTextToPtr(argv[1]);
   123    rc = sqlite3PagerRollback(pPager);
   124    if( rc!=SQLITE_OK ){
   125      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
   126      return TCL_ERROR;
   127    }
   128    return TCL_OK;
   129  }
   130  
   131  /*
   132  ** Usage:   pager_commit ID
   133  **
   134  ** Commit all changes
   135  */
   136  static int SQLITE_TCLAPI pager_commit(
   137    void *NotUsed,
   138    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   139    int argc,              /* Number of arguments */
   140    const char **argv      /* Text of each argument */
   141  ){
   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    }
   149    pPager = sqlite3TestTextToPtr(argv[1]);
   150    rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
   151    if( rc!=SQLITE_OK ){
   152      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
   153      return TCL_ERROR;
   154    }
   155    rc = sqlite3PagerCommitPhaseTwo(pPager);
   156    if( rc!=SQLITE_OK ){
   157      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
   158      return TCL_ERROR;
   159    }
   160    return TCL_OK;
   161  }
   162  
   163  /*
   164  ** Usage:   pager_stmt_begin ID
   165  **
   166  ** Start a new checkpoint.
   167  */
   168  static int SQLITE_TCLAPI pager_stmt_begin(
   169    void *NotUsed,
   170    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   171    int argc,              /* Number of arguments */
   172    const char **argv      /* Text of each argument */
   173  ){
   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    }
   181    pPager = sqlite3TestTextToPtr(argv[1]);
   182    rc = sqlite3PagerOpenSavepoint(pPager, 1);
   183    if( rc!=SQLITE_OK ){
   184      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
   185      return TCL_ERROR;
   186    }
   187    return TCL_OK;
   188  }
   189  
   190  /*
   191  ** Usage:   pager_stmt_rollback ID
   192  **
   193  ** Rollback changes to a checkpoint
   194  */
   195  static int SQLITE_TCLAPI pager_stmt_rollback(
   196    void *NotUsed,
   197    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   198    int argc,              /* Number of arguments */
   199    const char **argv      /* Text of each argument */
   200  ){
   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    }
   208    pPager = sqlite3TestTextToPtr(argv[1]);
   209    rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0);
   210    sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
   211    if( rc!=SQLITE_OK ){
   212      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
   213      return TCL_ERROR;
   214    }
   215    return TCL_OK;
   216  }
   217  
   218  /*
   219  ** Usage:   pager_stmt_commit ID
   220  **
   221  ** Commit changes to a checkpoint
   222  */
   223  static int SQLITE_TCLAPI pager_stmt_commit(
   224    void *NotUsed,
   225    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   226    int argc,              /* Number of arguments */
   227    const char **argv      /* Text of each argument */
   228  ){
   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    }
   236    pPager = sqlite3TestTextToPtr(argv[1]);
   237    rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
   238    if( rc!=SQLITE_OK ){
   239      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
   240      return TCL_ERROR;
   241    }
   242    return TCL_OK;
   243  }
   244  
   245  /*
   246  ** Usage:   pager_stats ID
   247  **
   248  ** Return pager statistics.
   249  */
   250  static int SQLITE_TCLAPI pager_stats(
   251    void *NotUsed,
   252    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   253    int argc,              /* Number of arguments */
   254    const char **argv      /* Text of each argument */
   255  ){
   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    }
   263    pPager = sqlite3TestTextToPtr(argv[1]);
   264    a = sqlite3PagerStats(pPager);
   265    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]);
   272      sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",a[i]);
   273      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  */
   283  static int SQLITE_TCLAPI pager_pagecount(
   284    void *NotUsed,
   285    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   286    int argc,              /* Number of arguments */
   287    const char **argv      /* Text of each argument */
   288  ){
   289    Pager *pPager;
   290    char zBuf[100];
   291    int nPage;
   292    if( argc!=2 ){
   293      Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   294         " ID\"", 0);
   295      return TCL_ERROR;
   296    }
   297    pPager = sqlite3TestTextToPtr(argv[1]);
   298    sqlite3PagerPagecount(pPager, &nPage);
   299    sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nPage);
   300    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  */
   309  static int SQLITE_TCLAPI page_get(
   310    void *NotUsed,
   311    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   312    int argc,              /* Number of arguments */
   313    const char **argv      /* Text of each argument */
   314  ){
   315    Pager *pPager;
   316    char zBuf[100];
   317    DbPage *pPage = 0;
   318    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    }
   325    pPager = sqlite3TestTextToPtr(argv[1]);
   326    if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
   327    rc = sqlite3PagerSharedLock(pPager);
   328    if( rc==SQLITE_OK ){
   329      rc = sqlite3PagerGet(pPager, pgno, &pPage, 0);
   330    }
   331    if( rc!=SQLITE_OK ){
   332      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
   333      return TCL_ERROR;
   334    }
   335    sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
   336    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  */
   346  static int SQLITE_TCLAPI page_lookup(
   347    void *NotUsed,
   348    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   349    int argc,              /* Number of arguments */
   350    const char **argv      /* Text of each argument */
   351  ){
   352    Pager *pPager;
   353    char zBuf[100];
   354    DbPage *pPage;
   355    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    }
   361    pPager = sqlite3TestTextToPtr(argv[1]);
   362    if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
   363    pPage = sqlite3PagerLookup(pPager, pgno);
   364    if( pPage ){
   365      sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
   366      Tcl_AppendResult(interp, zBuf, 0);
   367    }
   368    return TCL_OK;
   369  }
   370  
   371  /*
   372  ** Usage:   pager_truncate ID PGNO
   373  */
   374  static int SQLITE_TCLAPI pager_truncate(
   375    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;
   381    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    }
   387    pPager = sqlite3TestTextToPtr(argv[1]);
   388    if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
   389    sqlite3PagerTruncateImage(pPager, pgno);
   390    return TCL_OK;
   391  }
   392  
   393  
   394  /*
   395  ** Usage:   page_unref PAGE
   396  **
   397  ** Drop a pointer to a page.
   398  */
   399  static int SQLITE_TCLAPI page_unref(
   400    void *NotUsed,
   401    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   402    int argc,              /* Number of arguments */
   403    const char **argv      /* Text of each argument */
   404  ){
   405    DbPage *pPage;
   406    if( argc!=2 ){
   407      Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   408         " PAGE\"", 0);
   409      return TCL_ERROR;
   410    }
   411    pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
   412    sqlite3PagerUnref(pPage);
   413    return TCL_OK;
   414  }
   415  
   416  /*
   417  ** Usage:   page_read PAGE
   418  **
   419  ** Return the content of a page
   420  */
   421  static int SQLITE_TCLAPI page_read(
   422    void *NotUsed,
   423    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   424    int argc,              /* Number of arguments */
   425    const char **argv      /* Text of each argument */
   426  ){
   427    char zBuf[100];
   428    DbPage *pPage;
   429    if( argc!=2 ){
   430      Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   431         " PAGE\"", 0);
   432      return TCL_ERROR;
   433    }
   434    pPage = sqlite3TestTextToPtr(argv[1]);
   435    memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf));
   436    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  */
   445  static int SQLITE_TCLAPI page_number(
   446    void *NotUsed,
   447    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   448    int argc,              /* Number of arguments */
   449    const char **argv      /* Text of each argument */
   450  ){
   451    char zBuf[100];
   452    DbPage *pPage;
   453    if( argc!=2 ){
   454      Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   455         " PAGE\"", 0);
   456      return TCL_ERROR;
   457    }
   458    pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
   459    sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage));
   460    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  */
   469  static int SQLITE_TCLAPI page_write(
   470    void *NotUsed,
   471    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   472    int argc,              /* Number of arguments */
   473    const char **argv      /* Text of each argument */
   474  ){
   475    DbPage *pPage;
   476    char *pData;
   477    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    }
   483    pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
   484    rc = sqlite3PagerWrite(pPage);
   485    if( rc!=SQLITE_OK ){
   486      Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
   487      return TCL_ERROR;
   488    }
   489    pData = sqlite3PagerGetData(pPage);
   490    strncpy(pData, argv[2], test_pagesize-1);
   491    pData[test_pagesize-1] = 0;
   492    return TCL_OK;
   493  }
   494  
   495  #ifndef SQLITE_OMIT_DISKIO
   496  /*
   497  ** 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  */
   505  static int SQLITE_TCLAPI fake_big_file(
   506    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  ){
   511    sqlite3_vfs *pVfs;
   512    sqlite3_file *fd = 0;
   513    int rc;
   514    int n;
   515    i64 offset;
   516    char *zFile;
   517    int nFile;
   518    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;
   524  
   525    pVfs = sqlite3_vfs_find(0);
   526    nFile = (int)strlen(argv[2]);
   527    zFile = sqlite3_malloc( nFile+2 );
   528    if( zFile==0 ) return TCL_ERROR;
   529    memcpy(zFile, argv[2], nFile+1);
   530    zFile[nFile+1] = 0;
   531    rc = sqlite3OsOpenMalloc(pVfs, zFile, &fd, 
   532        (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0
   533    );
   534    if( rc ){
   535      Tcl_AppendResult(interp, "open failed: ", sqlite3ErrName(rc), 0);
   536      sqlite3_free(zFile);
   537      return TCL_ERROR;
   538    }
   539    offset = n;
   540    offset *= 1024*1024;
   541    rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
   542    sqlite3OsCloseFree(fd);
   543    sqlite3_free(zFile);
   544    if( rc ){
   545      Tcl_AppendResult(interp, "write failed: ", sqlite3ErrName(rc), 0);
   546      return TCL_ERROR;
   547    }
   548    return TCL_OK;
   549  }
   550  #endif
   551  
   552  
   553  /*
   554  ** test_control_pending_byte  PENDING_BYTE
   555  **
   556  ** Set the PENDING_BYTE using the sqlite3_test_control() interface.
   557  */
   558  static int SQLITE_TCLAPI testPendingByte(
   559    void *NotUsed,
   560    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   561    int argc,              /* Number of arguments */
   562    const char **argv      /* Text of each argument */
   563  ){
   564    int pbyte;
   565    int rc;
   566    if( argc!=2 ){
   567      Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   568                       " PENDING-BYTE\"", (void*)0);
   569      return TCL_ERROR;
   570    }
   571    if( Tcl_GetInt(interp, argv[1], &pbyte) ) return TCL_ERROR;
   572    rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
   573    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
   574    return TCL_OK;
   575  }
   576  
   577  /*
   578  ** The sqlite3FaultSim() callback:
   579  */
   580  static Tcl_Interp *faultSimInterp = 0;
   581  static int faultSimScriptSize = 0;
   582  static char *faultSimScript;
   583  static int faultSimCallback(int x){
   584    char zInt[30];
   585    int i;
   586    int isNeg;
   587    int rc;
   588    if( x==0 ){
   589      memcpy(faultSimScript+faultSimScriptSize, "0", 2);
   590    }else{
   591      /* Convert x to text without using any sqlite3 routines */
   592      if( x<0 ){
   593        isNeg = 1;
   594        x = -x;
   595      }else{
   596        isNeg = 0;
   597      }
   598      zInt[sizeof(zInt)-1] = 0;
   599      for(i=sizeof(zInt)-2; i>0 && x>0; i--, x /= 10){
   600        zInt[i] = (x%10) + '0';
   601      }
   602      if( isNeg ) zInt[i--] = '-';
   603      memcpy(faultSimScript+faultSimScriptSize, zInt+i+1, sizeof(zInt)-i);
   604    }
   605    rc = Tcl_Eval(faultSimInterp, faultSimScript);
   606    if( rc ){
   607      fprintf(stderr, "fault simulator script failed: [%s]", faultSimScript);
   608      rc = SQLITE_ERROR;
   609    }else{
   610      rc = atoi(Tcl_GetStringResult(faultSimInterp));
   611    }
   612    Tcl_ResetResult(faultSimInterp);
   613    return rc;
   614  }
   615  
   616  /*
   617  ** sqlite3_test_control_fault_install SCRIPT
   618  **
   619  ** Arrange to invoke SCRIPT with the integer argument to sqlite3FaultSim()
   620  ** appended, whenever sqlite3FaultSim() is called.  Or, if SCRIPT is the
   621  ** empty string, cancel the sqlite3FaultSim() callback.
   622  */
   623  static int SQLITE_TCLAPI faultInstallCmd(
   624    void *NotUsed,
   625    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   626    int argc,              /* Number of arguments */
   627    const char **argv      /* Text of each argument */
   628  ){
   629    const char *zScript;
   630    int nScript;
   631    int rc;
   632    if( argc!=1 && argc!=2 ){
   633      Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   634                       " SCRIPT\"", (void*)0);
   635    }
   636    zScript = argc==2 ? argv[1] : "";
   637    nScript = (int)strlen(zScript);
   638    if( faultSimScript ){
   639      free(faultSimScript);
   640      faultSimScript = 0;
   641    }
   642    if( nScript==0 ){
   643      rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, 0);
   644    }else{
   645      faultSimScript = malloc( nScript+100 );
   646      if( faultSimScript==0 ){
   647        Tcl_AppendResult(interp, "out of memory", (void*)0);
   648        return SQLITE_ERROR;
   649      }
   650      memcpy(faultSimScript, zScript, nScript);
   651      faultSimScript[nScript] = ' ';
   652      faultSimScriptSize = nScript+1;
   653      faultSimInterp = interp;
   654      rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, faultSimCallback);
   655    }
   656    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
   657    return SQLITE_OK;
   658  }
   659  
   660  /*
   661  ** sqlite3BitvecBuiltinTest SIZE PROGRAM
   662  **
   663  ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
   664  ** See comments on sqlite3BitvecBuiltinTest() for additional information.
   665  */
   666  static int SQLITE_TCLAPI testBitvecBuiltinTest(
   667    void *NotUsed,
   668    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   669    int argc,              /* Number of arguments */
   670    const char **argv      /* Text of each argument */
   671  ){
   672    int sz, rc;
   673    int nProg = 0;
   674    int aProg[100];
   675    const char *z;
   676    if( argc!=3 ){
   677      Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   678                       " SIZE PROGRAM\"", (void*)0);
   679    }
   680    if( Tcl_GetInt(interp, argv[1], &sz) ) return TCL_ERROR;
   681    z = argv[2];
   682    while( nProg<99 && *z ){
   683      while( *z && !sqlite3Isdigit(*z) ){ z++; }
   684      if( *z==0 ) break;
   685      aProg[nProg++] = atoi(z);
   686      while( sqlite3Isdigit(*z) ){ z++; }
   687    }
   688    aProg[nProg] = 0;
   689    rc = sqlite3_test_control(SQLITE_TESTCTRL_BITVEC_TEST, sz, aProg);
   690    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
   691    return TCL_OK;
   692  }  
   693  
   694  /*
   695  ** Register commands with the TCL interpreter.
   696  */
   697  int Sqlitetest2_Init(Tcl_Interp *interp){
   698    extern int sqlite3_io_error_persist;
   699    extern int sqlite3_io_error_pending;
   700    extern int sqlite3_io_error_hit;
   701    extern int sqlite3_io_error_hardhit;
   702    extern int sqlite3_diskfull_pending;
   703    extern int sqlite3_diskfull;
   704    static struct {
   705      char *zName;
   706      Tcl_CmdProc *xProc;
   707    } aCmd[] = {
   708      { "pager_open",              (Tcl_CmdProc*)pager_open          },
   709      { "pager_close",             (Tcl_CmdProc*)pager_close         },
   710      { "pager_commit",            (Tcl_CmdProc*)pager_commit        },
   711      { "pager_rollback",          (Tcl_CmdProc*)pager_rollback      },
   712      { "pager_stmt_begin",        (Tcl_CmdProc*)pager_stmt_begin    },
   713      { "pager_stmt_commit",       (Tcl_CmdProc*)pager_stmt_commit   },
   714      { "pager_stmt_rollback",     (Tcl_CmdProc*)pager_stmt_rollback },
   715      { "pager_stats",             (Tcl_CmdProc*)pager_stats         },
   716      { "pager_pagecount",         (Tcl_CmdProc*)pager_pagecount     },
   717      { "page_get",                (Tcl_CmdProc*)page_get            },
   718      { "page_lookup",             (Tcl_CmdProc*)page_lookup         },
   719      { "page_unref",              (Tcl_CmdProc*)page_unref          },
   720      { "page_read",               (Tcl_CmdProc*)page_read           },
   721      { "page_write",              (Tcl_CmdProc*)page_write          },
   722      { "page_number",             (Tcl_CmdProc*)page_number         },
   723      { "pager_truncate",          (Tcl_CmdProc*)pager_truncate      },
   724  #ifndef SQLITE_OMIT_DISKIO
   725      { "fake_big_file",           (Tcl_CmdProc*)fake_big_file       },
   726  #endif
   727      { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest     },
   728      { "sqlite3_test_control_pending_byte",  (Tcl_CmdProc*)testPendingByte },
   729      { "sqlite3_test_control_fault_install", (Tcl_CmdProc*)faultInstallCmd },
   730    };
   731    int i;
   732    for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
   733      Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
   734    }
   735    Tcl_LinkVar(interp, "sqlite_io_error_pending",
   736       (char*)&sqlite3_io_error_pending, TCL_LINK_INT);
   737    Tcl_LinkVar(interp, "sqlite_io_error_persist",
   738       (char*)&sqlite3_io_error_persist, TCL_LINK_INT);
   739    Tcl_LinkVar(interp, "sqlite_io_error_hit",
   740       (char*)&sqlite3_io_error_hit, TCL_LINK_INT);
   741    Tcl_LinkVar(interp, "sqlite_io_error_hardhit",
   742       (char*)&sqlite3_io_error_hardhit, TCL_LINK_INT);
   743    Tcl_LinkVar(interp, "sqlite_diskfull_pending",
   744       (char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
   745    Tcl_LinkVar(interp, "sqlite_diskfull",
   746       (char*)&sqlite3_diskfull, TCL_LINK_INT);
   747  #ifndef SQLITE_OMIT_WSD
   748    Tcl_LinkVar(interp, "sqlite_pending_byte",
   749       (char*)&sqlite3PendingByte, TCL_LINK_INT | TCL_LINK_READ_ONLY);
   750  #endif
   751    return TCL_OK;
   752  }