persistentstorage/sqlite3api/TEST/SRC/test3.c
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     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 btree.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: test3.c,v 1.101 2008/08/13 19:11:48 drh Exp $
       
    17 */
       
    18 #include "sqliteInt.h"
       
    19 #include "btreeInt.h"
       
    20 #include "tcl.h"
       
    21 #include <stdlib.h>
       
    22 #include <string.h>
       
    23 
       
    24 /*
       
    25 ** Interpret an SQLite error number
       
    26 */
       
    27 static char *errorName(int rc){
       
    28   char *zName;
       
    29   switch( rc ){
       
    30     case SQLITE_OK:         zName = "SQLITE_OK";          break;
       
    31     case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
       
    32     case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
       
    33     case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
       
    34     case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
       
    35     case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
       
    36     case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
       
    37     case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
       
    38     case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
       
    39     case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
       
    40     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
       
    41     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
       
    42     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
       
    43     case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
       
    44     case SQLITE_LOCKED:     zName = "SQLITE_LOCKED";      break;
       
    45     default:                zName = "SQLITE_Unknown";     break;
       
    46   }
       
    47   return zName;
       
    48 }
       
    49 
       
    50 /*
       
    51 ** A bogus sqlite3 connection structure for use in the btree
       
    52 ** tests.
       
    53 */
       
    54 static sqlite3 sDb;
       
    55 static int nRefSqlite3 = 0;
       
    56 
       
    57 /*
       
    58 ** Usage:   btree_open FILENAME NCACHE FLAGS
       
    59 **
       
    60 ** Open a new database
       
    61 */
       
    62 static int btree_open(
       
    63   void *NotUsed,
       
    64   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
    65   int argc,              /* Number of arguments */
       
    66   const char **argv      /* Text of each argument */
       
    67 ){
       
    68   Btree *pBt;
       
    69   int rc, nCache, flags;
       
    70   char zBuf[100];
       
    71   if( argc!=4 ){
       
    72     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
    73        " FILENAME NCACHE FLAGS\"", 0);
       
    74     return TCL_ERROR;
       
    75   }
       
    76   if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
       
    77   if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR;
       
    78   nRefSqlite3++;
       
    79   if( nRefSqlite3==1 ){
       
    80     sDb.pVfs = sqlite3_vfs_find(0);
       
    81     sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
       
    82     sqlite3_mutex_enter(sDb.mutex);
       
    83   }
       
    84   rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, flags,
       
    85      SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
       
    86   if( rc!=SQLITE_OK ){
       
    87     Tcl_AppendResult(interp, errorName(rc), 0);
       
    88     return TCL_ERROR;
       
    89   }
       
    90   sqlite3BtreeSetCacheSize(pBt, nCache);
       
    91   sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
       
    92   Tcl_AppendResult(interp, zBuf, 0);
       
    93   return TCL_OK;
       
    94 }
       
    95 
       
    96 /*
       
    97 ** Usage:   btree_close ID
       
    98 **
       
    99 ** Close the given database.
       
   100 */
       
   101 static int btree_close(
       
   102   void *NotUsed,
       
   103   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   104   int argc,              /* Number of arguments */
       
   105   const char **argv      /* Text of each argument */
       
   106 ){
       
   107   Btree *pBt;
       
   108   int rc;
       
   109   if( argc!=2 ){
       
   110     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   111        " ID\"", 0);
       
   112     return TCL_ERROR;
       
   113   }
       
   114   pBt = sqlite3TestTextToPtr(argv[1]);
       
   115   rc = sqlite3BtreeClose(pBt);
       
   116   if( rc!=SQLITE_OK ){
       
   117     Tcl_AppendResult(interp, errorName(rc), 0);
       
   118     return TCL_ERROR;
       
   119   }
       
   120   nRefSqlite3--;
       
   121   if( nRefSqlite3==0 ){
       
   122     sqlite3_mutex_leave(sDb.mutex);
       
   123     sqlite3_mutex_free(sDb.mutex);
       
   124     sDb.mutex = 0;
       
   125     sDb.pVfs = 0;
       
   126   }
       
   127   return TCL_OK;
       
   128 }
       
   129 
       
   130 
       
   131 /*
       
   132 ** Usage:   btree_begin_transaction ID
       
   133 **
       
   134 ** Start a new transaction
       
   135 */
       
   136 static int btree_begin_transaction(
       
   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   Btree *pBt;
       
   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   pBt = sqlite3TestTextToPtr(argv[1]);
       
   150   sqlite3BtreeEnter(pBt);
       
   151   rc = sqlite3BtreeBeginTrans(pBt, 1);
       
   152   sqlite3BtreeLeave(pBt);
       
   153   if( rc!=SQLITE_OK ){
       
   154     Tcl_AppendResult(interp, errorName(rc), 0);
       
   155     return TCL_ERROR;
       
   156   }
       
   157   return TCL_OK;
       
   158 }
       
   159 
       
   160 /*
       
   161 ** Usage:   btree_rollback ID
       
   162 **
       
   163 ** Rollback changes
       
   164 */
       
   165 static int btree_rollback(
       
   166   void *NotUsed,
       
   167   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   168   int argc,              /* Number of arguments */
       
   169   const char **argv      /* Text of each argument */
       
   170 ){
       
   171   Btree *pBt;
       
   172   int rc;
       
   173   if( argc!=2 ){
       
   174     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   175        " ID\"", 0);
       
   176     return TCL_ERROR;
       
   177   }
       
   178   pBt = sqlite3TestTextToPtr(argv[1]);
       
   179   sqlite3BtreeEnter(pBt);
       
   180   rc = sqlite3BtreeRollback(pBt);
       
   181   sqlite3BtreeLeave(pBt);
       
   182   if( rc!=SQLITE_OK ){
       
   183     Tcl_AppendResult(interp, errorName(rc), 0);
       
   184     return TCL_ERROR;
       
   185   }
       
   186   return TCL_OK;
       
   187 }
       
   188 
       
   189 /*
       
   190 ** Usage:   btree_commit ID
       
   191 **
       
   192 ** Commit all changes
       
   193 */
       
   194 static int btree_commit(
       
   195   void *NotUsed,
       
   196   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   197   int argc,              /* Number of arguments */
       
   198   const char **argv      /* Text of each argument */
       
   199 ){
       
   200   Btree *pBt;
       
   201   int rc;
       
   202   if( argc!=2 ){
       
   203     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   204        " ID\"", 0);
       
   205     return TCL_ERROR;
       
   206   }
       
   207   pBt = sqlite3TestTextToPtr(argv[1]);
       
   208   sqlite3BtreeEnter(pBt);
       
   209   rc = sqlite3BtreeCommit(pBt);
       
   210   sqlite3BtreeLeave(pBt);
       
   211   if( rc!=SQLITE_OK ){
       
   212     Tcl_AppendResult(interp, errorName(rc), 0);
       
   213     return TCL_ERROR;
       
   214   }
       
   215   return TCL_OK;
       
   216 }
       
   217 
       
   218 /*
       
   219 ** Usage:   btree_begin_statement ID
       
   220 **
       
   221 ** Start a new statement transaction
       
   222 */
       
   223 static int btree_begin_statement(
       
   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   Btree *pBt;
       
   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   pBt = sqlite3TestTextToPtr(argv[1]);
       
   237   sqlite3BtreeEnter(pBt);
       
   238   rc = sqlite3BtreeBeginStmt(pBt);
       
   239   sqlite3BtreeLeave(pBt);
       
   240   if( rc!=SQLITE_OK ){
       
   241     Tcl_AppendResult(interp, errorName(rc), 0);
       
   242     return TCL_ERROR;
       
   243   }
       
   244   return TCL_OK;
       
   245 }
       
   246 
       
   247 /*
       
   248 ** Usage:   btree_rollback_statement ID
       
   249 **
       
   250 ** Rollback changes
       
   251 */
       
   252 static int btree_rollback_statement(
       
   253   void *NotUsed,
       
   254   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   255   int argc,              /* Number of arguments */
       
   256   const char **argv      /* Text of each argument */
       
   257 ){
       
   258   Btree *pBt;
       
   259   int rc;
       
   260   if( argc!=2 ){
       
   261     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   262        " ID\"", 0);
       
   263     return TCL_ERROR;
       
   264   }
       
   265   pBt = sqlite3TestTextToPtr(argv[1]);
       
   266   sqlite3BtreeEnter(pBt);
       
   267   rc = sqlite3BtreeRollbackStmt(pBt);
       
   268   sqlite3BtreeLeave(pBt);
       
   269   if( rc!=SQLITE_OK ){
       
   270     Tcl_AppendResult(interp, errorName(rc), 0);
       
   271     return TCL_ERROR;
       
   272   }
       
   273   return TCL_OK;
       
   274 }
       
   275 
       
   276 /*
       
   277 ** Usage:   btree_commit_statement ID
       
   278 **
       
   279 ** Commit all changes
       
   280 */
       
   281 static int btree_commit_statement(
       
   282   void *NotUsed,
       
   283   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   284   int argc,              /* Number of arguments */
       
   285   const char **argv      /* Text of each argument */
       
   286 ){
       
   287   Btree *pBt;
       
   288   int rc;
       
   289   if( argc!=2 ){
       
   290     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   291        " ID\"", 0);
       
   292     return TCL_ERROR;
       
   293   }
       
   294   pBt = sqlite3TestTextToPtr(argv[1]);
       
   295   sqlite3BtreeEnter(pBt);
       
   296   rc = sqlite3BtreeCommitStmt(pBt);
       
   297   sqlite3BtreeLeave(pBt);
       
   298   if( rc!=SQLITE_OK ){
       
   299     Tcl_AppendResult(interp, errorName(rc), 0);
       
   300     return TCL_ERROR;
       
   301   }
       
   302   return TCL_OK;
       
   303 }
       
   304 
       
   305 /*
       
   306 ** Usage:   btree_create_table ID FLAGS
       
   307 **
       
   308 ** Create a new table in the database
       
   309 */
       
   310 static int btree_create_table(
       
   311   void *NotUsed,
       
   312   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   313   int argc,              /* Number of arguments */
       
   314   const char **argv      /* Text of each argument */
       
   315 ){
       
   316   Btree *pBt;
       
   317   int rc, iTable, flags;
       
   318   char zBuf[30];
       
   319   if( argc!=3 ){
       
   320     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   321        " ID FLAGS\"", 0);
       
   322     return TCL_ERROR;
       
   323   }
       
   324   pBt = sqlite3TestTextToPtr(argv[1]);
       
   325   if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR;
       
   326   sqlite3BtreeEnter(pBt);
       
   327   rc = sqlite3BtreeCreateTable(pBt, &iTable, flags);
       
   328   sqlite3BtreeLeave(pBt);
       
   329   if( rc!=SQLITE_OK ){
       
   330     Tcl_AppendResult(interp, errorName(rc), 0);
       
   331     return TCL_ERROR;
       
   332   }
       
   333   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iTable);
       
   334   Tcl_AppendResult(interp, zBuf, 0);
       
   335   return TCL_OK;
       
   336 }
       
   337 
       
   338 /*
       
   339 ** Usage:   btree_drop_table ID TABLENUM
       
   340 **
       
   341 ** Delete an entire table from the database
       
   342 */
       
   343 static int btree_drop_table(
       
   344   void *NotUsed,
       
   345   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   346   int argc,              /* Number of arguments */
       
   347   const char **argv      /* Text of each argument */
       
   348 ){
       
   349   Btree *pBt;
       
   350   int iTable;
       
   351   int rc;
       
   352   int notUsed1;
       
   353   if( argc!=3 ){
       
   354     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   355        " ID TABLENUM\"", 0);
       
   356     return TCL_ERROR;
       
   357   }
       
   358   pBt = sqlite3TestTextToPtr(argv[1]);
       
   359   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
       
   360   sqlite3BtreeEnter(pBt);
       
   361   rc = sqlite3BtreeDropTable(pBt, iTable, &notUsed1);
       
   362   sqlite3BtreeLeave(pBt);
       
   363   if( rc!=SQLITE_OK ){
       
   364     Tcl_AppendResult(interp, errorName(rc), 0);
       
   365     return TCL_ERROR;
       
   366   }
       
   367   return TCL_OK;
       
   368 }
       
   369 
       
   370 /*
       
   371 ** Usage:   btree_clear_table ID TABLENUM
       
   372 **
       
   373 ** Remove all entries from the given table but keep the table around.
       
   374 */
       
   375 static int btree_clear_table(
       
   376   void *NotUsed,
       
   377   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   378   int argc,              /* Number of arguments */
       
   379   const char **argv      /* Text of each argument */
       
   380 ){
       
   381   Btree *pBt;
       
   382   int iTable;
       
   383   int rc;
       
   384   if( argc!=3 ){
       
   385     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   386        " ID TABLENUM\"", 0);
       
   387     return TCL_ERROR;
       
   388   }
       
   389   pBt = sqlite3TestTextToPtr(argv[1]);
       
   390   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
       
   391   sqlite3BtreeEnter(pBt);
       
   392   rc = sqlite3BtreeClearTable(pBt, iTable);
       
   393   sqlite3BtreeLeave(pBt);
       
   394   if( rc!=SQLITE_OK ){
       
   395     Tcl_AppendResult(interp, errorName(rc), 0);
       
   396     return TCL_ERROR;
       
   397   }
       
   398   return TCL_OK;
       
   399 }
       
   400 
       
   401 /*
       
   402 ** Usage:   btree_get_meta ID
       
   403 **
       
   404 ** Return meta data
       
   405 */
       
   406 static int btree_get_meta(
       
   407   void *NotUsed,
       
   408   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   409   int argc,              /* Number of arguments */
       
   410   const char **argv      /* Text of each argument */
       
   411 ){
       
   412   Btree *pBt;
       
   413   int rc;
       
   414   int i;
       
   415   if( argc!=2 ){
       
   416     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   417        " ID\"", 0);
       
   418     return TCL_ERROR;
       
   419   }
       
   420   pBt = sqlite3TestTextToPtr(argv[1]);
       
   421   for(i=0; i<SQLITE_N_BTREE_META; i++){
       
   422     char zBuf[30];
       
   423     u32 v;
       
   424     sqlite3BtreeEnter(pBt);
       
   425     rc = sqlite3BtreeGetMeta(pBt, i, &v);
       
   426     sqlite3BtreeLeave(pBt);
       
   427     if( rc!=SQLITE_OK ){
       
   428       Tcl_AppendResult(interp, errorName(rc), 0);
       
   429       return TCL_ERROR;
       
   430     }
       
   431     sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",v);
       
   432     Tcl_AppendElement(interp, zBuf);
       
   433   }
       
   434   return TCL_OK;
       
   435 }
       
   436 
       
   437 /*
       
   438 ** Usage:   btree_update_meta ID METADATA...
       
   439 **
       
   440 ** Return meta data
       
   441 */
       
   442 static int btree_update_meta(
       
   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   Btree *pBt;
       
   449   int rc;
       
   450   int i;
       
   451   int aMeta[SQLITE_N_BTREE_META];
       
   452 
       
   453   if( argc!=2+SQLITE_N_BTREE_META ){
       
   454     char zBuf[30];
       
   455     sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",SQLITE_N_BTREE_META);
       
   456     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   457        " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0);
       
   458     return TCL_ERROR;
       
   459   }
       
   460   pBt = sqlite3TestTextToPtr(argv[1]);
       
   461   for(i=1; i<SQLITE_N_BTREE_META; i++){
       
   462     if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR;
       
   463   }
       
   464   for(i=1; i<SQLITE_N_BTREE_META; i++){
       
   465     sqlite3BtreeEnter(pBt);
       
   466     rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]);
       
   467     sqlite3BtreeLeave(pBt);
       
   468     if( rc!=SQLITE_OK ){
       
   469       Tcl_AppendResult(interp, errorName(rc), 0);
       
   470       return TCL_ERROR;
       
   471     }
       
   472   }
       
   473   return TCL_OK;
       
   474 }
       
   475 
       
   476 /*
       
   477 ** Usage:   btree_pager_stats ID
       
   478 **
       
   479 ** Returns pager statistics
       
   480 */
       
   481 static int btree_pager_stats(
       
   482   void *NotUsed,
       
   483   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   484   int argc,              /* Number of arguments */
       
   485   const char **argv      /* Text of each argument */
       
   486 ){
       
   487   Btree *pBt;
       
   488   int i;
       
   489   int *a;
       
   490 
       
   491   if( argc!=2 ){
       
   492     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   493        " ID\"", 0);
       
   494     return TCL_ERROR;
       
   495   }
       
   496   pBt = sqlite3TestTextToPtr(argv[1]);
       
   497  
       
   498   /* Normally in this file, with a b-tree handle opened using the 
       
   499   ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
       
   500   ** But this function is sometimes called with a btree handle obtained
       
   501   ** from an open SQLite connection (using [btree_from_db]). In this case
       
   502   ** we need to obtain the mutex for the controlling SQLite handle before
       
   503   ** it is safe to call sqlite3BtreeEnter().
       
   504   */
       
   505   sqlite3_mutex_enter(pBt->db->mutex);
       
   506 
       
   507   sqlite3BtreeEnter(pBt);
       
   508   a = sqlite3PagerStats(sqlite3BtreePager(pBt));
       
   509   for(i=0; i<11; i++){
       
   510     static char *zName[] = {
       
   511       "ref", "page", "max", "size", "state", "err",
       
   512       "hit", "miss", "ovfl", "read", "write"
       
   513     };
       
   514     char zBuf[100];
       
   515     Tcl_AppendElement(interp, zName[i]);
       
   516     sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
       
   517     Tcl_AppendElement(interp, zBuf);
       
   518   }
       
   519   sqlite3BtreeLeave(pBt);
       
   520 
       
   521   /* Release the mutex on the SQLite handle that controls this b-tree */
       
   522   sqlite3_mutex_leave(pBt->db->mutex);
       
   523   return TCL_OK;
       
   524 }
       
   525 
       
   526 /*
       
   527 ** Usage:   btree_integrity_check ID ROOT ...
       
   528 **
       
   529 ** Look through every page of the given BTree file to verify correct
       
   530 ** formatting and linkage.  Return a line of text for each problem found.
       
   531 ** Return an empty string if everything worked.
       
   532 */
       
   533 static int btree_integrity_check(
       
   534   void *NotUsed,
       
   535   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   536   int argc,              /* Number of arguments */
       
   537   const char **argv      /* Text of each argument */
       
   538 ){
       
   539   Btree *pBt;
       
   540   int nRoot;
       
   541   int *aRoot;
       
   542   int i;
       
   543   int nErr;
       
   544   char *zResult;
       
   545 
       
   546   if( argc<3 ){
       
   547     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   548        " ID ROOT ...\"", 0);
       
   549     return TCL_ERROR;
       
   550   }
       
   551   pBt = sqlite3TestTextToPtr(argv[1]);
       
   552   nRoot = argc-2;
       
   553   aRoot = (int*)sqlite3_malloc( sizeof(int)*(argc-2) );
       
   554   for(i=0; i<argc-2; i++){
       
   555     if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
       
   556   }
       
   557 #ifndef SQLITE_OMIT_INTEGRITY_CHECK
       
   558   sqlite3BtreeEnter(pBt);
       
   559   zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
       
   560   sqlite3BtreeLeave(pBt);
       
   561 #else
       
   562   zResult = 0;
       
   563 #endif
       
   564   sqlite3_free((void*)aRoot);
       
   565   if( zResult ){
       
   566     Tcl_AppendResult(interp, zResult, 0);
       
   567     sqlite3_free(zResult); 
       
   568   }
       
   569   return TCL_OK;
       
   570 }
       
   571 
       
   572 /*
       
   573 ** Usage:   btree_cursor_list ID
       
   574 **
       
   575 ** Print information about all cursors to standard output for debugging.
       
   576 */
       
   577 static int btree_cursor_list(
       
   578   void *NotUsed,
       
   579   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   580   int argc,              /* Number of arguments */
       
   581   const char **argv      /* Text of each argument */
       
   582 ){
       
   583   Btree *pBt;
       
   584 
       
   585   if( argc!=2 ){
       
   586     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   587        " ID\"", 0);
       
   588     return TCL_ERROR;
       
   589   }
       
   590   pBt = sqlite3TestTextToPtr(argv[1]);
       
   591   sqlite3BtreeEnter(pBt);
       
   592   sqlite3BtreeCursorList(pBt);
       
   593   sqlite3BtreeLeave(pBt);
       
   594   return SQLITE_OK;
       
   595 }
       
   596 
       
   597 /*
       
   598 ** Usage:   btree_cursor ID TABLENUM WRITEABLE
       
   599 **
       
   600 ** Create a new cursor.  Return the ID for the cursor.
       
   601 */
       
   602 static int btree_cursor(
       
   603   void *NotUsed,
       
   604   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   605   int argc,              /* Number of arguments */
       
   606   const char **argv      /* Text of each argument */
       
   607 ){
       
   608   Btree *pBt;
       
   609   int iTable;
       
   610   BtCursor *pCur;
       
   611   int rc;
       
   612   int wrFlag;
       
   613   char zBuf[30];
       
   614 
       
   615   if( argc!=4 ){
       
   616     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   617        " ID TABLENUM WRITEABLE\"", 0);
       
   618     return TCL_ERROR;
       
   619   }
       
   620   pBt = sqlite3TestTextToPtr(argv[1]);
       
   621   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
       
   622   if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
       
   623   pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
       
   624   memset(pCur, 0, sqlite3BtreeCursorSize());
       
   625   sqlite3BtreeEnter(pBt);
       
   626   rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
       
   627   sqlite3BtreeLeave(pBt);
       
   628   if( rc ){
       
   629     ckfree((char *)pCur);
       
   630     Tcl_AppendResult(interp, errorName(rc), 0);
       
   631     return TCL_ERROR;
       
   632   }
       
   633   sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
       
   634   Tcl_AppendResult(interp, zBuf, 0);
       
   635   return SQLITE_OK;
       
   636 }
       
   637 
       
   638 /*
       
   639 ** Usage:   btree_close_cursor ID
       
   640 **
       
   641 ** Close a cursor opened using btree_cursor.
       
   642 */
       
   643 static int btree_close_cursor(
       
   644   void *NotUsed,
       
   645   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   646   int argc,              /* Number of arguments */
       
   647   const char **argv      /* Text of each argument */
       
   648 ){
       
   649   BtCursor *pCur;
       
   650   Btree *pBt;
       
   651   int rc;
       
   652 
       
   653   if( argc!=2 ){
       
   654     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   655        " ID\"", 0);
       
   656     return TCL_ERROR;
       
   657   }
       
   658   pCur = sqlite3TestTextToPtr(argv[1]);
       
   659   pBt = pCur->pBtree;
       
   660   sqlite3BtreeEnter(pBt);
       
   661   rc = sqlite3BtreeCloseCursor(pCur);
       
   662   sqlite3BtreeLeave(pBt);
       
   663   ckfree((char *)pCur);
       
   664   if( rc ){
       
   665     Tcl_AppendResult(interp, errorName(rc), 0);
       
   666     return TCL_ERROR;
       
   667   }
       
   668   return SQLITE_OK;
       
   669 }
       
   670 
       
   671 /*
       
   672 ** Usage:   btree_move_to ID KEY
       
   673 **
       
   674 ** Move the cursor to the entry with the given key.
       
   675 */
       
   676 static int btree_move_to(
       
   677   void *NotUsed,
       
   678   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   679   int argc,              /* Number of arguments */
       
   680   const char **argv      /* Text of each argument */
       
   681 ){
       
   682   BtCursor *pCur;
       
   683   int rc;
       
   684   int res;
       
   685   char zBuf[20];
       
   686 
       
   687   if( argc!=3 ){
       
   688     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   689        " ID KEY\"", 0);
       
   690     return TCL_ERROR;
       
   691   }
       
   692   pCur = sqlite3TestTextToPtr(argv[1]);
       
   693   sqlite3BtreeEnter(pCur->pBtree);
       
   694   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
       
   695     int iKey;
       
   696     if( Tcl_GetInt(interp, argv[2], &iKey) ){
       
   697       sqlite3BtreeLeave(pCur->pBtree);
       
   698       return TCL_ERROR;
       
   699     }
       
   700     rc = sqlite3BtreeMovetoUnpacked(pCur, 0, iKey, 0, &res);
       
   701   }else{
       
   702     rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);  
       
   703   }
       
   704   sqlite3BtreeLeave(pCur->pBtree);
       
   705   if( rc ){
       
   706     Tcl_AppendResult(interp, errorName(rc), 0);
       
   707     return TCL_ERROR;
       
   708   }
       
   709   if( res<0 ) res = -1;
       
   710   if( res>0 ) res = 1;
       
   711   sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res);
       
   712   Tcl_AppendResult(interp, zBuf, 0);
       
   713   return SQLITE_OK;
       
   714 }
       
   715 
       
   716 /*
       
   717 ** Usage:   btree_delete ID
       
   718 **
       
   719 ** Delete the entry that the cursor is pointing to
       
   720 */
       
   721 static int btree_delete(
       
   722   void *NotUsed,
       
   723   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   724   int argc,              /* Number of arguments */
       
   725   const char **argv      /* Text of each argument */
       
   726 ){
       
   727   BtCursor *pCur;
       
   728   int rc;
       
   729 
       
   730   if( argc!=2 ){
       
   731     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   732        " ID\"", 0);
       
   733     return TCL_ERROR;
       
   734   }
       
   735   pCur = sqlite3TestTextToPtr(argv[1]);
       
   736   sqlite3BtreeEnter(pCur->pBtree);
       
   737   rc = sqlite3BtreeDelete(pCur);
       
   738   sqlite3BtreeLeave(pCur->pBtree);
       
   739   if( rc ){
       
   740     Tcl_AppendResult(interp, errorName(rc), 0);
       
   741     return TCL_ERROR;
       
   742   }
       
   743   return SQLITE_OK;
       
   744 }
       
   745 
       
   746 /*
       
   747 ** Usage:   btree_insert ID KEY DATA ?NZERO?
       
   748 **
       
   749 ** Create a new entry with the given key and data.  If an entry already
       
   750 ** exists with the same key the old entry is overwritten.
       
   751 */
       
   752 static int btree_insert(
       
   753   void * clientData,
       
   754   Tcl_Interp *interp,
       
   755   int objc,
       
   756   Tcl_Obj *CONST objv[]
       
   757 ){
       
   758   BtCursor *pCur;
       
   759   int rc;
       
   760   int nZero;
       
   761 
       
   762   if( objc!=4 && objc!=5 ){
       
   763     Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?");
       
   764     return TCL_ERROR;
       
   765   }
       
   766   pCur = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
       
   767   if( objc==5 ){
       
   768     if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR;
       
   769   }else{
       
   770     nZero = 0;
       
   771   }
       
   772   sqlite3BtreeEnter(pCur->pBtree);
       
   773   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
       
   774     i64 iKey;
       
   775     int len;
       
   776     unsigned char *pBuf;
       
   777     if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){
       
   778       sqlite3BtreeLeave(pCur->pBtree);
       
   779       return TCL_ERROR;
       
   780     }
       
   781     pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
       
   782     rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0);
       
   783   }else{
       
   784     int keylen;
       
   785     int dlen;
       
   786     unsigned char *pKBuf;
       
   787     unsigned char *pDBuf;
       
   788     pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
       
   789     pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
       
   790     rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0);
       
   791   }
       
   792   sqlite3BtreeLeave(pCur->pBtree);
       
   793   if( rc ){
       
   794     Tcl_AppendResult(interp, errorName(rc), 0);
       
   795     return TCL_ERROR;
       
   796   }
       
   797   return SQLITE_OK;
       
   798 }
       
   799 
       
   800 /*
       
   801 ** Usage:   btree_next ID
       
   802 **
       
   803 ** Move the cursor to the next entry in the table.  Return 0 on success
       
   804 ** or 1 if the cursor was already on the last entry in the table or if
       
   805 ** the table is empty.
       
   806 */
       
   807 static int btree_next(
       
   808   void *NotUsed,
       
   809   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   810   int argc,              /* Number of arguments */
       
   811   const char **argv      /* Text of each argument */
       
   812 ){
       
   813   BtCursor *pCur;
       
   814   int rc;
       
   815   int res = 0;
       
   816   char zBuf[100];
       
   817 
       
   818   if( argc!=2 ){
       
   819     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   820        " ID\"", 0);
       
   821     return TCL_ERROR;
       
   822   }
       
   823   pCur = sqlite3TestTextToPtr(argv[1]);
       
   824   sqlite3BtreeEnter(pCur->pBtree);
       
   825   rc = sqlite3BtreeNext(pCur, &res);
       
   826   sqlite3BtreeLeave(pCur->pBtree);
       
   827   if( rc ){
       
   828     Tcl_AppendResult(interp, errorName(rc), 0);
       
   829     return TCL_ERROR;
       
   830   }
       
   831   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
       
   832   Tcl_AppendResult(interp, zBuf, 0);
       
   833   return SQLITE_OK;
       
   834 }
       
   835 
       
   836 /*
       
   837 ** Usage:   btree_prev ID
       
   838 **
       
   839 ** Move the cursor to the previous entry in the table.  Return 0 on
       
   840 ** success and 1 if the cursor was already on the first entry in
       
   841 ** the table or if the table was empty.
       
   842 */
       
   843 static int btree_prev(
       
   844   void *NotUsed,
       
   845   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   846   int argc,              /* Number of arguments */
       
   847   const char **argv      /* Text of each argument */
       
   848 ){
       
   849   BtCursor *pCur;
       
   850   int rc;
       
   851   int res = 0;
       
   852   char zBuf[100];
       
   853 
       
   854   if( argc!=2 ){
       
   855     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   856        " ID\"", 0);
       
   857     return TCL_ERROR;
       
   858   }
       
   859   pCur = sqlite3TestTextToPtr(argv[1]);
       
   860   sqlite3BtreeEnter(pCur->pBtree);
       
   861   rc = sqlite3BtreePrevious(pCur, &res);
       
   862   sqlite3BtreeLeave(pCur->pBtree);
       
   863   if( rc ){
       
   864     Tcl_AppendResult(interp, errorName(rc), 0);
       
   865     return TCL_ERROR;
       
   866   }
       
   867   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
       
   868   Tcl_AppendResult(interp, zBuf, 0);
       
   869   return SQLITE_OK;
       
   870 }
       
   871 
       
   872 /*
       
   873 ** Usage:   btree_first ID
       
   874 **
       
   875 ** Move the cursor to the first entry in the table.  Return 0 if the
       
   876 ** cursor was left point to something and 1 if the table is empty.
       
   877 */
       
   878 static int btree_first(
       
   879   void *NotUsed,
       
   880   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   881   int argc,              /* Number of arguments */
       
   882   const char **argv      /* Text of each argument */
       
   883 ){
       
   884   BtCursor *pCur;
       
   885   int rc;
       
   886   int res = 0;
       
   887   char zBuf[100];
       
   888 
       
   889   if( argc!=2 ){
       
   890     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   891        " ID\"", 0);
       
   892     return TCL_ERROR;
       
   893   }
       
   894   pCur = sqlite3TestTextToPtr(argv[1]);
       
   895   sqlite3BtreeEnter(pCur->pBtree);
       
   896   rc = sqlite3BtreeFirst(pCur, &res);
       
   897   sqlite3BtreeLeave(pCur->pBtree);
       
   898   if( rc ){
       
   899     Tcl_AppendResult(interp, errorName(rc), 0);
       
   900     return TCL_ERROR;
       
   901   }
       
   902   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
       
   903   Tcl_AppendResult(interp, zBuf, 0);
       
   904   return SQLITE_OK;
       
   905 }
       
   906 
       
   907 /*
       
   908 ** Usage:   btree_last ID
       
   909 **
       
   910 ** Move the cursor to the last entry in the table.  Return 0 if the
       
   911 ** cursor was left point to something and 1 if the table is empty.
       
   912 */
       
   913 static int btree_last(
       
   914   void *NotUsed,
       
   915   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   916   int argc,              /* Number of arguments */
       
   917   const char **argv      /* Text of each argument */
       
   918 ){
       
   919   BtCursor *pCur;
       
   920   int rc;
       
   921   int res = 0;
       
   922   char zBuf[100];
       
   923 
       
   924   if( argc!=2 ){
       
   925     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   926        " ID\"", 0);
       
   927     return TCL_ERROR;
       
   928   }
       
   929   pCur = sqlite3TestTextToPtr(argv[1]);
       
   930   sqlite3BtreeEnter(pCur->pBtree);
       
   931   rc = sqlite3BtreeLast(pCur, &res);
       
   932   sqlite3BtreeLeave(pCur->pBtree);
       
   933   if( rc ){
       
   934     Tcl_AppendResult(interp, errorName(rc), 0);
       
   935     return TCL_ERROR;
       
   936   }
       
   937   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
       
   938   Tcl_AppendResult(interp, zBuf, 0);
       
   939   return SQLITE_OK;
       
   940 }
       
   941 
       
   942 /*
       
   943 ** Usage:   btree_eof ID
       
   944 **
       
   945 ** Return TRUE if the given cursor is not pointing at a valid entry.
       
   946 ** Return FALSE if the cursor does point to a valid entry.
       
   947 */
       
   948 static int btree_eof(
       
   949   void *NotUsed,
       
   950   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   951   int argc,              /* Number of arguments */
       
   952   const char **argv      /* Text of each argument */
       
   953 ){
       
   954   BtCursor *pCur;
       
   955   int rc;
       
   956   char zBuf[50];
       
   957 
       
   958   if( argc!=2 ){
       
   959     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   960        " ID\"", 0);
       
   961     return TCL_ERROR;
       
   962   }
       
   963   pCur = sqlite3TestTextToPtr(argv[1]);
       
   964   sqlite3BtreeEnter(pCur->pBtree);
       
   965   rc = sqlite3BtreeEof(pCur);
       
   966   sqlite3BtreeLeave(pCur->pBtree);
       
   967   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
       
   968   Tcl_AppendResult(interp, zBuf, 0);
       
   969   return SQLITE_OK;
       
   970 }
       
   971 
       
   972 /*
       
   973 ** Usage:   btree_keysize ID
       
   974 **
       
   975 ** Return the number of bytes of key.  For an INTKEY table, this
       
   976 ** returns the key itself.
       
   977 */
       
   978 static int btree_keysize(
       
   979   void *NotUsed,
       
   980   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
   981   int argc,              /* Number of arguments */
       
   982   const char **argv      /* Text of each argument */
       
   983 ){
       
   984   BtCursor *pCur;
       
   985   u64 n;
       
   986   char zBuf[50];
       
   987 
       
   988   if( argc!=2 ){
       
   989     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
   990        " ID\"", 0);
       
   991     return TCL_ERROR;
       
   992   }
       
   993   pCur = sqlite3TestTextToPtr(argv[1]);
       
   994   sqlite3BtreeEnter(pCur->pBtree);
       
   995   sqlite3BtreeKeySize(pCur, (i64*)&n);
       
   996   sqlite3BtreeLeave(pCur->pBtree);
       
   997   sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n);
       
   998   Tcl_AppendResult(interp, zBuf, 0);
       
   999   return SQLITE_OK;
       
  1000 }
       
  1001 
       
  1002 /*
       
  1003 ** Usage:   btree_key ID
       
  1004 **
       
  1005 ** Return the key for the entry at which the cursor is pointing.
       
  1006 */
       
  1007 static int btree_key(
       
  1008   void *NotUsed,
       
  1009   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1010   int argc,              /* Number of arguments */
       
  1011   const char **argv      /* Text of each argument */
       
  1012 ){
       
  1013   BtCursor *pCur;
       
  1014   int rc;
       
  1015   u64 n;
       
  1016   char *zBuf;
       
  1017 
       
  1018   if( argc!=2 ){
       
  1019     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1020        " ID\"", 0);
       
  1021     return TCL_ERROR;
       
  1022   }
       
  1023   pCur = sqlite3TestTextToPtr(argv[1]);
       
  1024   sqlite3BtreeEnter(pCur->pBtree);
       
  1025   sqlite3BtreeKeySize(pCur, (i64*)&n);
       
  1026   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
       
  1027     char zBuf2[60];
       
  1028     sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n);
       
  1029     Tcl_AppendResult(interp, zBuf2, 0);
       
  1030   }else{
       
  1031     zBuf = sqlite3_malloc( n+1 );
       
  1032     rc = sqlite3BtreeKey(pCur, 0, n, zBuf);
       
  1033     if( rc ){
       
  1034       sqlite3BtreeLeave(pCur->pBtree);
       
  1035       Tcl_AppendResult(interp, errorName(rc), 0);
       
  1036       return TCL_ERROR;
       
  1037     }
       
  1038     zBuf[n] = 0;
       
  1039     Tcl_AppendResult(interp, zBuf, 0);
       
  1040     sqlite3_free(zBuf);
       
  1041   }
       
  1042   sqlite3BtreeLeave(pCur->pBtree);
       
  1043   return SQLITE_OK;
       
  1044 }
       
  1045 
       
  1046 /*
       
  1047 ** Usage:   btree_data ID ?N?
       
  1048 **
       
  1049 ** Return the data for the entry at which the cursor is pointing.
       
  1050 */
       
  1051 static int btree_data(
       
  1052   void *NotUsed,
       
  1053   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1054   int argc,              /* Number of arguments */
       
  1055   const char **argv      /* Text of each argument */
       
  1056 ){
       
  1057   BtCursor *pCur;
       
  1058   int rc;
       
  1059   u32 n;
       
  1060   char *zBuf;
       
  1061 
       
  1062   if( argc!=2 && argc!=3 ){
       
  1063     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1064        " ID\"", 0);
       
  1065     return TCL_ERROR;
       
  1066   }
       
  1067   pCur = sqlite3TestTextToPtr(argv[1]);
       
  1068   sqlite3BtreeEnter(pCur->pBtree);
       
  1069   if( argc==2 ){
       
  1070     sqlite3BtreeDataSize(pCur, &n);
       
  1071   }else{
       
  1072     n = atoi(argv[2]);
       
  1073   }
       
  1074   zBuf = sqlite3_malloc( n+1 );
       
  1075   rc = sqlite3BtreeData(pCur, 0, n, zBuf);
       
  1076   sqlite3BtreeLeave(pCur->pBtree);
       
  1077   if( rc ){
       
  1078     Tcl_AppendResult(interp, errorName(rc), 0);
       
  1079     sqlite3_free(zBuf);
       
  1080     return TCL_ERROR;
       
  1081   }
       
  1082   zBuf[n] = 0;
       
  1083   Tcl_AppendResult(interp, zBuf, 0);
       
  1084   sqlite3_free(zBuf);
       
  1085   return SQLITE_OK;
       
  1086 }
       
  1087 
       
  1088 /*
       
  1089 ** Usage:   btree_fetch_key ID AMT
       
  1090 **
       
  1091 ** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key.
       
  1092 ** If sqlite3BtreeKeyFetch() fails, return an empty string.
       
  1093 */
       
  1094 static int btree_fetch_key(
       
  1095   void *NotUsed,
       
  1096   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1097   int argc,              /* Number of arguments */
       
  1098   const char **argv      /* Text of each argument */
       
  1099 ){
       
  1100   BtCursor *pCur;
       
  1101   int n;
       
  1102   int amt;
       
  1103   u64 nKey;
       
  1104   const char *zBuf;
       
  1105   char zStatic[1000];
       
  1106 
       
  1107   if( argc!=3 ){
       
  1108     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1109        " ID AMT\"", 0);
       
  1110     return TCL_ERROR;
       
  1111   }
       
  1112   pCur = sqlite3TestTextToPtr(argv[1]);
       
  1113   if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
       
  1114   sqlite3BtreeEnter(pCur->pBtree);
       
  1115   sqlite3BtreeKeySize(pCur, (i64*)&nKey);
       
  1116   zBuf = sqlite3BtreeKeyFetch(pCur, &amt);
       
  1117   if( zBuf && amt>=n ){
       
  1118     assert( nKey<sizeof(zStatic) );
       
  1119     if( n>0 ) nKey = n;
       
  1120     memcpy(zStatic, zBuf, (int)nKey); 
       
  1121     zStatic[nKey] = 0;
       
  1122     Tcl_AppendResult(interp, zStatic, 0);
       
  1123   }
       
  1124   sqlite3BtreeLeave(pCur->pBtree);
       
  1125   return TCL_OK;
       
  1126 }
       
  1127 
       
  1128 /*
       
  1129 ** Usage:   btree_fetch_data ID AMT
       
  1130 **
       
  1131 ** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key.
       
  1132 ** If sqlite3BtreeDataFetch() fails, return an empty string.
       
  1133 */
       
  1134 static int btree_fetch_data(
       
  1135   void *NotUsed,
       
  1136   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1137   int argc,              /* Number of arguments */
       
  1138   const char **argv      /* Text of each argument */
       
  1139 ){
       
  1140   BtCursor *pCur;
       
  1141   int n;
       
  1142   int amt;
       
  1143   u32 nData;
       
  1144   const char *zBuf;
       
  1145   char zStatic[1000];
       
  1146 
       
  1147   if( argc!=3 ){
       
  1148     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1149        " ID AMT\"", 0);
       
  1150     return TCL_ERROR;
       
  1151   }
       
  1152   pCur = sqlite3TestTextToPtr(argv[1]);
       
  1153   if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
       
  1154   sqlite3BtreeEnter(pCur->pBtree);
       
  1155   sqlite3BtreeDataSize(pCur, &nData);
       
  1156   zBuf = sqlite3BtreeDataFetch(pCur, &amt);
       
  1157   if( zBuf && amt>=n ){
       
  1158     assert( nData<sizeof(zStatic) );
       
  1159     if( n>0 ) nData = n;
       
  1160     memcpy(zStatic, zBuf, (int)nData); 
       
  1161     zStatic[nData] = 0;
       
  1162     Tcl_AppendResult(interp, zStatic, 0);
       
  1163   }
       
  1164   sqlite3BtreeLeave(pCur->pBtree);
       
  1165   return TCL_OK;
       
  1166 }
       
  1167 
       
  1168 /*
       
  1169 ** Usage:   btree_payload_size ID
       
  1170 **
       
  1171 ** Return the number of bytes of payload
       
  1172 */
       
  1173 static int btree_payload_size(
       
  1174   void *NotUsed,
       
  1175   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1176   int argc,              /* Number of arguments */
       
  1177   const char **argv      /* Text of each argument */
       
  1178 ){
       
  1179   BtCursor *pCur;
       
  1180   int n2;
       
  1181   u64 n1;
       
  1182   char zBuf[50];
       
  1183 
       
  1184   if( argc!=2 ){
       
  1185     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1186        " ID\"", 0);
       
  1187     return TCL_ERROR;
       
  1188   }
       
  1189   pCur = sqlite3TestTextToPtr(argv[1]);
       
  1190   sqlite3BtreeEnter(pCur->pBtree);
       
  1191   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
       
  1192     n1 = 0;
       
  1193   }else{
       
  1194     sqlite3BtreeKeySize(pCur, (i64*)&n1);
       
  1195   }
       
  1196   sqlite3BtreeDataSize(pCur, (u32*)&n2);
       
  1197   sqlite3BtreeLeave(pCur->pBtree);
       
  1198   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
       
  1199   Tcl_AppendResult(interp, zBuf, 0);
       
  1200   return SQLITE_OK;
       
  1201 }
       
  1202 
       
  1203 /*
       
  1204 ** Usage:   btree_cursor_info ID ?UP-CNT?
       
  1205 **
       
  1206 ** Return integers containing information about the entry the
       
  1207 ** cursor is pointing to:
       
  1208 **
       
  1209 **   aResult[0] =  The page number
       
  1210 **   aResult[1] =  The entry number
       
  1211 **   aResult[2] =  Total number of entries on this page
       
  1212 **   aResult[3] =  Cell size (local payload + header)
       
  1213 **   aResult[4] =  Number of free bytes on this page
       
  1214 **   aResult[5] =  Number of free blocks on the page
       
  1215 **   aResult[6] =  Total payload size (local + overflow)
       
  1216 **   aResult[7] =  Header size in bytes
       
  1217 **   aResult[8] =  Local payload size
       
  1218 **   aResult[9] =  Parent page number
       
  1219 **   aResult[10]=  Page number of the first overflow page
       
  1220 */
       
  1221 static int btree_cursor_info(
       
  1222   void *NotUsed,
       
  1223   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1224   int argc,              /* Number of arguments */
       
  1225   const char **argv      /* Text of each argument */
       
  1226 ){
       
  1227   BtCursor *pCur;
       
  1228   int rc;
       
  1229   int i, j;
       
  1230   int up;
       
  1231   int aResult[11];
       
  1232   char zBuf[400];
       
  1233 
       
  1234   if( argc!=2 && argc!=3 ){
       
  1235     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1236        " ID ?UP-CNT?\"", 0);
       
  1237     return TCL_ERROR;
       
  1238   }
       
  1239   pCur = sqlite3TestTextToPtr(argv[1]);
       
  1240   if( argc==3 ){
       
  1241     if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR;
       
  1242   }else{
       
  1243     up = 0;
       
  1244   }
       
  1245   sqlite3BtreeEnter(pCur->pBtree);
       
  1246   rc = sqlite3BtreeCursorInfo(pCur, aResult, up);
       
  1247   if( rc ){
       
  1248     Tcl_AppendResult(interp, errorName(rc), 0);
       
  1249     sqlite3BtreeLeave(pCur->pBtree);
       
  1250     return TCL_ERROR;
       
  1251   }
       
  1252   j = 0;
       
  1253   for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
       
  1254     sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]);
       
  1255     j += strlen(&zBuf[j]);
       
  1256   }
       
  1257   sqlite3BtreeLeave(pCur->pBtree);
       
  1258   Tcl_AppendResult(interp, &zBuf[1], 0);
       
  1259   return SQLITE_OK;
       
  1260 }
       
  1261 
       
  1262 /*
       
  1263 ** Copied from btree.c:
       
  1264 */
       
  1265 static u32 t4Get4byte(unsigned char *p){
       
  1266   return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
       
  1267 }
       
  1268 
       
  1269 /*
       
  1270 **   btree_ovfl_info  BTREE  CURSOR
       
  1271 **
       
  1272 ** Given a cursor, return the sequence of pages number that form the
       
  1273 ** overflow pages for the data of the entry that the cursor is point
       
  1274 ** to.
       
  1275 */ 
       
  1276 static int btree_ovfl_info(
       
  1277   void *NotUsed,
       
  1278   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1279   int argc,              /* Number of arguments */
       
  1280   const char **argv      /* Text of each argument */
       
  1281 ){
       
  1282   Btree *pBt;
       
  1283   BtCursor *pCur;
       
  1284   Pager *pPager;
       
  1285   int rc;
       
  1286   int n;
       
  1287   int dataSize;
       
  1288   u32 pgno;
       
  1289   void *pPage;
       
  1290   int aResult[11];
       
  1291   char zElem[100];
       
  1292   Tcl_DString str;
       
  1293 
       
  1294   if( argc!=3 ){
       
  1295     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
       
  1296                     " BTREE CURSOR", 0);
       
  1297     return TCL_ERROR;
       
  1298   }
       
  1299   pBt = sqlite3TestTextToPtr(argv[1]);
       
  1300   pCur = sqlite3TestTextToPtr(argv[2]);
       
  1301   if( (*(void**)pCur) != (void*)pBt ){
       
  1302     Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ",
       
  1303        argv[1], 0);
       
  1304     return TCL_ERROR;
       
  1305   }
       
  1306   sqlite3BtreeEnter(pBt);
       
  1307   pPager = sqlite3BtreePager(pBt);
       
  1308   rc = sqlite3BtreeCursorInfo(pCur, aResult, 0);
       
  1309   if( rc ){
       
  1310     Tcl_AppendResult(interp, errorName(rc), 0);
       
  1311     sqlite3BtreeLeave(pBt);
       
  1312     return TCL_ERROR;
       
  1313   }
       
  1314   dataSize = pBt->pBt->usableSize;
       
  1315   Tcl_DStringInit(&str);
       
  1316   n = aResult[6] - aResult[8];
       
  1317   n = (n + dataSize - 1)/dataSize;
       
  1318   pgno = (u32)aResult[10];
       
  1319   while( pgno && n-- ){
       
  1320     DbPage *pDbPage;
       
  1321     sprintf(zElem, "%d", pgno);
       
  1322     Tcl_DStringAppendElement(&str, zElem);
       
  1323     if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){
       
  1324       Tcl_DStringFree(&str);
       
  1325       Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
       
  1326       sqlite3BtreeLeave(pBt);
       
  1327       return TCL_ERROR;
       
  1328     }
       
  1329     pPage = sqlite3PagerGetData(pDbPage);
       
  1330     pgno = t4Get4byte((unsigned char*)pPage);
       
  1331     sqlite3PagerUnref(pDbPage);
       
  1332   }
       
  1333   sqlite3BtreeLeave(pBt);
       
  1334   Tcl_DStringResult(interp, &str);
       
  1335   return SQLITE_OK;
       
  1336 }
       
  1337 
       
  1338 /*
       
  1339 ** The command is provided for the purpose of setting breakpoints.
       
  1340 ** in regression test scripts.
       
  1341 **
       
  1342 ** By setting a GDB breakpoint on this procedure and executing the
       
  1343 ** btree_breakpoint command in a test script, we can stop GDB at
       
  1344 ** the point in the script where the btree_breakpoint command is
       
  1345 ** inserted.  This is useful for debugging.
       
  1346 */
       
  1347 static int btree_breakpoint(
       
  1348   void *NotUsed,
       
  1349   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1350   int argc,              /* Number of arguments */
       
  1351   const char **argv      /* Text of each argument */
       
  1352 ){
       
  1353   return TCL_OK;
       
  1354 }
       
  1355 
       
  1356 /*
       
  1357 ** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT
       
  1358 **
       
  1359 ** This command tests the putVarint() and getVarint()
       
  1360 ** routines, both for accuracy and for speed.
       
  1361 **
       
  1362 ** An integer is written using putVarint() and read back with
       
  1363 ** getVarint() and varified to be unchanged.  This repeats COUNT
       
  1364 ** times.  The first integer is START*MULTIPLIER.  Each iteration
       
  1365 ** increases the integer by INCREMENT.
       
  1366 **
       
  1367 ** This command returns nothing if it works.  It returns an error message
       
  1368 ** if something goes wrong.
       
  1369 */
       
  1370 static int btree_varint_test(
       
  1371   void *NotUsed,
       
  1372   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1373   int argc,              /* Number of arguments */
       
  1374   const char **argv      /* Text of each argument */
       
  1375 ){
       
  1376   u32 start, mult, count, incr;
       
  1377   u64 in, out;
       
  1378   int n1, n2, i, j;
       
  1379   unsigned char zBuf[100];
       
  1380   if( argc!=5 ){
       
  1381     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1382        " START MULTIPLIER COUNT INCREMENT\"", 0);
       
  1383     return TCL_ERROR;
       
  1384   }
       
  1385   if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
       
  1386   if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
       
  1387   if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
       
  1388   if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
       
  1389   in = start;
       
  1390   in *= mult;
       
  1391   for(i=0; i<count; i++){
       
  1392     char zErr[200];
       
  1393     n1 = putVarint(zBuf, in);
       
  1394     if( n1>9 || n1<1 ){
       
  1395       sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
       
  1396       Tcl_AppendResult(interp, zErr, 0);
       
  1397       return TCL_ERROR;
       
  1398     }
       
  1399     n2 = getVarint(zBuf, &out);
       
  1400     if( n1!=n2 ){
       
  1401       sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
       
  1402       Tcl_AppendResult(interp, zErr, 0);
       
  1403       return TCL_ERROR;
       
  1404     }
       
  1405     if( in!=out ){
       
  1406       sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
       
  1407       Tcl_AppendResult(interp, zErr, 0);
       
  1408       return TCL_ERROR;
       
  1409     }
       
  1410     if( (in & 0xffffffff)==in ){
       
  1411       u32 out32;
       
  1412       n2 = getVarint32(zBuf, out32);
       
  1413       out = out32;
       
  1414       if( n1!=n2 ){
       
  1415         sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d", 
       
  1416                   n1, n2);
       
  1417         Tcl_AppendResult(interp, zErr, 0);
       
  1418         return TCL_ERROR;
       
  1419       }
       
  1420       if( in!=out ){
       
  1421         sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
       
  1422             in, out);
       
  1423         Tcl_AppendResult(interp, zErr, 0);
       
  1424         return TCL_ERROR;
       
  1425       }
       
  1426     }
       
  1427 
       
  1428     /* In order to get realistic timings, run getVarint 19 more times.
       
  1429     ** This is because getVarint is called about 20 times more often
       
  1430     ** than putVarint.
       
  1431     */
       
  1432     for(j=0; j<19; j++){
       
  1433       getVarint(zBuf, &out);
       
  1434     }
       
  1435     in += incr;
       
  1436   }
       
  1437   return TCL_OK;
       
  1438 }
       
  1439 
       
  1440 /*
       
  1441 ** usage:   btree_from_db  DB-HANDLE
       
  1442 **
       
  1443 ** This command returns the btree handle for the main database associated
       
  1444 ** with the database-handle passed as the argument. Example usage:
       
  1445 **
       
  1446 ** sqlite3 db test.db
       
  1447 ** set bt [btree_from_db db]
       
  1448 */
       
  1449 static int btree_from_db(
       
  1450   void *NotUsed,
       
  1451   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1452   int argc,              /* Number of arguments */
       
  1453   const char **argv      /* Text of each argument */
       
  1454 ){
       
  1455   char zBuf[100];
       
  1456   Tcl_CmdInfo info;
       
  1457   sqlite3 *db;
       
  1458   Btree *pBt;
       
  1459   int iDb = 0;
       
  1460 
       
  1461   if( argc!=2 && argc!=3 ){
       
  1462     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1463        " DB-HANDLE ?N?\"", 0);
       
  1464     return TCL_ERROR;
       
  1465   }
       
  1466 
       
  1467   if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
       
  1468     Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
       
  1469     return TCL_ERROR;
       
  1470   }
       
  1471   if( argc==3 ){
       
  1472     iDb = atoi(argv[2]);
       
  1473   }
       
  1474 
       
  1475   db = *((sqlite3 **)info.objClientData);
       
  1476   assert( db );
       
  1477 
       
  1478   pBt = db->aDb[iDb].pBt;
       
  1479   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
       
  1480   Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
       
  1481   return TCL_OK;
       
  1482 }
       
  1483 
       
  1484 
       
  1485 /*
       
  1486 ** usage:   btree_set_cache_size ID NCACHE
       
  1487 **
       
  1488 ** Set the size of the cache used by btree $ID.
       
  1489 */
       
  1490 static int btree_set_cache_size(
       
  1491   void *NotUsed,
       
  1492   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1493   int argc,              /* Number of arguments */
       
  1494   const char **argv      /* Text of each argument */
       
  1495 ){
       
  1496   int nCache;
       
  1497   Btree *pBt;
       
  1498 
       
  1499   if( argc!=3 ){
       
  1500     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1501        " BT NCACHE\"", 0);
       
  1502     return TCL_ERROR;
       
  1503   }
       
  1504   pBt = sqlite3TestTextToPtr(argv[1]);
       
  1505   if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
       
  1506 
       
  1507   sqlite3_mutex_enter(pBt->db->mutex);
       
  1508   sqlite3BtreeEnter(pBt);
       
  1509   sqlite3BtreeSetCacheSize(pBt, nCache);
       
  1510   sqlite3BtreeLeave(pBt);
       
  1511   sqlite3_mutex_leave(pBt->db->mutex);
       
  1512 
       
  1513   return TCL_OK;
       
  1514 }
       
  1515 
       
  1516 /*
       
  1517 ** Usage:   btree_ismemdb ID
       
  1518 **
       
  1519 ** Return true if the B-Tree is in-memory.
       
  1520 */
       
  1521 static int btree_ismemdb(
       
  1522   void *NotUsed,
       
  1523   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
       
  1524   int argc,              /* Number of arguments */
       
  1525   const char **argv      /* Text of each argument */
       
  1526 ){
       
  1527   Btree *pBt;
       
  1528   int res;
       
  1529 
       
  1530   if( argc!=2 ){
       
  1531     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       
  1532        " ID\"", 0);
       
  1533     return TCL_ERROR;
       
  1534   }
       
  1535   pBt = sqlite3TestTextToPtr(argv[1]);
       
  1536   sqlite3_mutex_enter(pBt->db->mutex);
       
  1537   sqlite3BtreeEnter(pBt);
       
  1538   res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
       
  1539   sqlite3BtreeLeave(pBt);
       
  1540   sqlite3_mutex_leave(pBt->db->mutex);
       
  1541   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
       
  1542   return SQLITE_OK;
       
  1543 }
       
  1544 
       
  1545 
       
  1546 /*
       
  1547 ** Register commands with the TCL interpreter.
       
  1548 */
       
  1549 int Sqlitetest3_Init(Tcl_Interp *interp){
       
  1550   static struct {
       
  1551      char *zName;
       
  1552      Tcl_CmdProc *xProc;
       
  1553   } aCmd[] = {
       
  1554      { "btree_open",               (Tcl_CmdProc*)btree_open               },
       
  1555      { "btree_close",              (Tcl_CmdProc*)btree_close              },
       
  1556      { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  },
       
  1557      { "btree_commit",             (Tcl_CmdProc*)btree_commit             },
       
  1558      { "btree_rollback",           (Tcl_CmdProc*)btree_rollback           },
       
  1559      { "btree_create_table",       (Tcl_CmdProc*)btree_create_table       },
       
  1560      { "btree_drop_table",         (Tcl_CmdProc*)btree_drop_table         },
       
  1561      { "btree_clear_table",        (Tcl_CmdProc*)btree_clear_table        },
       
  1562      { "btree_get_meta",           (Tcl_CmdProc*)btree_get_meta           },
       
  1563      { "btree_update_meta",        (Tcl_CmdProc*)btree_update_meta        },
       
  1564      { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        },
       
  1565      { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             },
       
  1566      { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       },
       
  1567      { "btree_move_to",            (Tcl_CmdProc*)btree_move_to            },
       
  1568      { "btree_delete",             (Tcl_CmdProc*)btree_delete             },
       
  1569      { "btree_next",               (Tcl_CmdProc*)btree_next               },
       
  1570      { "btree_prev",               (Tcl_CmdProc*)btree_prev               },
       
  1571      { "btree_eof",                (Tcl_CmdProc*)btree_eof                },
       
  1572      { "btree_keysize",            (Tcl_CmdProc*)btree_keysize            },
       
  1573      { "btree_key",                (Tcl_CmdProc*)btree_key                },
       
  1574      { "btree_data",               (Tcl_CmdProc*)btree_data               },
       
  1575      { "btree_fetch_key",          (Tcl_CmdProc*)btree_fetch_key          },
       
  1576      { "btree_fetch_data",         (Tcl_CmdProc*)btree_fetch_data         },
       
  1577      { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       },
       
  1578      { "btree_first",              (Tcl_CmdProc*)btree_first              },
       
  1579      { "btree_last",               (Tcl_CmdProc*)btree_last               },
       
  1580      { "btree_integrity_check",    (Tcl_CmdProc*)btree_integrity_check    },
       
  1581      { "btree_breakpoint",         (Tcl_CmdProc*)btree_breakpoint         },
       
  1582      { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },
       
  1583      { "btree_begin_statement",    (Tcl_CmdProc*)btree_begin_statement    },
       
  1584      { "btree_commit_statement",   (Tcl_CmdProc*)btree_commit_statement   },
       
  1585      { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
       
  1586      { "btree_from_db",            (Tcl_CmdProc*)btree_from_db            },
       
  1587      { "btree_set_cache_size",     (Tcl_CmdProc*)btree_set_cache_size     },
       
  1588      { "btree_cursor_info",        (Tcl_CmdProc*)btree_cursor_info        },
       
  1589      { "btree_ovfl_info",          (Tcl_CmdProc*)btree_ovfl_info          },
       
  1590      { "btree_cursor_list",        (Tcl_CmdProc*)btree_cursor_list        },
       
  1591      { "btree_ismemdb",            (Tcl_CmdProc*)btree_ismemdb            },
       
  1592   };
       
  1593   int i;
       
  1594 
       
  1595   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
       
  1596     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
       
  1597   }
       
  1598 
       
  1599   /* The btree_insert command is implemented using the tcl 'object'
       
  1600   ** interface, not the string interface like the other commands in this
       
  1601   ** file. This is so binary data can be inserted into btree tables.
       
  1602   */
       
  1603   Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);
       
  1604   return TCL_OK;
       
  1605 }