os/persistentdata/persistentstorage/sqlite3api/TEST/SRC/test3.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 }