Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
test3.c690 linesDownload Raw Back to src
1/*2** 2001 September 153**4** The author disclaims copyright to this source code.  In place of5** 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 code13** is not included in the SQLite library.  It is used for automated14** testing of the SQLite library.15*/16#include "sqliteInt.h"17#include "btreeInt.h"18#include "tclsqlite.h"19#include <stdlib.h>20#include <string.h>21 22extern const char *sqlite3ErrName(int);23 24/*25** A bogus sqlite3 connection structure for use in the btree26** tests.27*/28static sqlite3 sDb;29static int nRefSqlite3 = 0;30 31/*32** Usage:   btree_open FILENAME NCACHE33**34** Open a new database35*/36static int SQLITE_TCLAPI btree_open(37  void *NotUsed,38  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */39  int argc,              /* Number of arguments */40  const char **argv      /* Text of each argument */41){42  Btree *pBt;43  int rc, nCache;44  char zBuf[100];45  int n;46  char *zFilename;47  if( argc!=3 ){48    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],49       " FILENAME NCACHE FLAGS\"", NULL);50    return TCL_ERROR;51  }52 53  if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;54  nRefSqlite3++;55  if( nRefSqlite3==1 ){56    sDb.pVfs = sqlite3_vfs_find(0);57    sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);58    sqlite3_mutex_enter(sDb.mutex);59  }60  n = (int)strlen(argv[1]);61  zFilename = sqlite3_malloc( n+2 );62  if( zFilename==0 ) return TCL_ERROR;63  memcpy(zFilename, argv[1], n+1);64  zFilename[n+1] = 0;65  rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0, 66     SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);67  sqlite3_free(zFilename);68  if( rc!=SQLITE_OK ){69    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);70    return TCL_ERROR;71  }72  sqlite3BtreeSetCacheSize(pBt, nCache);73  sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);74  Tcl_AppendResult(interp, zBuf, NULL);75  return TCL_OK;76}77 78/*79** Usage:   btree_close ID80**81** Close the given database.82*/83static int SQLITE_TCLAPI btree_close(84  void *NotUsed,85  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */86  int argc,              /* Number of arguments */87  const char **argv      /* Text of each argument */88){89  Btree *pBt;90  int rc;91  if( argc!=2 ){92    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],93       " ID\"", NULL);94    return TCL_ERROR;95  }96  pBt = sqlite3TestTextToPtr(argv[1]);97  rc = sqlite3BtreeClose(pBt);98  if( rc!=SQLITE_OK ){99    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);100    return TCL_ERROR;101  }102  nRefSqlite3--;103  if( nRefSqlite3==0 ){104    sqlite3_mutex_leave(sDb.mutex);105    sqlite3_mutex_free(sDb.mutex);106    sDb.mutex = 0;107    sDb.pVfs = 0;108  }109  return TCL_OK;110}111 112 113/*114** Usage:   btree_begin_transaction ID115**116** Start a new transaction117*/118static int SQLITE_TCLAPI btree_begin_transaction(119  void *NotUsed,120  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */121  int argc,              /* Number of arguments */122  const char **argv      /* Text of each argument */123){124  Btree *pBt;125  int rc;126  if( argc!=2 ){127    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],128       " ID\"", NULL);129    return TCL_ERROR;130  }131  pBt = sqlite3TestTextToPtr(argv[1]);132  sqlite3BtreeEnter(pBt);133  rc = sqlite3BtreeBeginTrans(pBt, 1, 0);134  sqlite3BtreeLeave(pBt);135  if( rc!=SQLITE_OK ){136    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);137    return TCL_ERROR;138  }139  return TCL_OK;140}141 142/*143** Usage:   btree_pager_stats ID144**145** Returns pager statistics146*/147static int SQLITE_TCLAPI btree_pager_stats(148  void *NotUsed,149  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */150  int argc,              /* Number of arguments */151  const char **argv      /* Text of each argument */152){153  Btree *pBt;154  int i;155  int *a;156 157  if( argc!=2 ){158    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],159       " ID\"", NULL);160    return TCL_ERROR;161  }162  pBt = sqlite3TestTextToPtr(argv[1]);163 164  /* Normally in this file, with a b-tree handle opened using the 165  ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.166  ** But this function is sometimes called with a btree handle obtained167  ** from an open SQLite connection (using [btree_from_db]). In this case168  ** we need to obtain the mutex for the controlling SQLite handle before169  ** it is safe to call sqlite3BtreeEnter().170  */171  sqlite3_mutex_enter(pBt->db->mutex);172 173  sqlite3BtreeEnter(pBt);174  a = sqlite3PagerStats(sqlite3BtreePager(pBt));175  for(i=0; i<11; i++){176    static char *zName[] = {177      "ref", "page", "max", "size", "state", "err",178      "hit", "miss", "ovfl", "read", "write"179    };180    char zBuf[100];181    Tcl_AppendElement(interp, zName[i]);182    sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);183    Tcl_AppendElement(interp, zBuf);184  }185  sqlite3BtreeLeave(pBt);186 187  /* Release the mutex on the SQLite handle that controls this b-tree */188  sqlite3_mutex_leave(pBt->db->mutex);189  return TCL_OK;190}191 192/*193** Usage:   btree_cursor ID TABLENUM WRITEABLE194**195** Create a new cursor.  Return the ID for the cursor.196*/197static int SQLITE_TCLAPI btree_cursor(198  void *NotUsed,199  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */200  int argc,              /* Number of arguments */201  const char **argv      /* Text of each argument */202){203  Btree *pBt;204  int iTable;205  BtCursor *pCur;206  int rc = SQLITE_OK;207  int wrFlag;208  char zBuf[30];209 210  if( argc!=4 ){211    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],212       " ID TABLENUM WRITEABLE\"", NULL);213    return TCL_ERROR;214  }215  pBt = sqlite3TestTextToPtr(argv[1]);216  if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;217  if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;218  if( wrFlag ) wrFlag = BTREE_WRCSR;219  pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());220  memset(pCur, 0, sqlite3BtreeCursorSize());221  sqlite3_mutex_enter(pBt->db->mutex);222  sqlite3BtreeEnter(pBt);223#ifndef SQLITE_OMIT_SHARED_CACHE224  rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag);225#endif226  if( rc==SQLITE_OK ){227    rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);228  }229  sqlite3BtreeLeave(pBt);230  sqlite3_mutex_leave(pBt->db->mutex);231  if( rc ){232    ckfree((char *)pCur);233    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);234    return TCL_ERROR;235  }236  sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);237  Tcl_AppendResult(interp, zBuf, NULL);238  return SQLITE_OK;239}240 241/*242** Usage:   btree_close_cursor ID243**244** Close a cursor opened using btree_cursor.245*/246static int SQLITE_TCLAPI btree_close_cursor(247  void *NotUsed,248  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */249  int argc,              /* Number of arguments */250  const char **argv      /* Text of each argument */251){252  BtCursor *pCur;253  int rc;254 255  if( argc!=2 ){256    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],257       " ID\"", NULL);258    return TCL_ERROR;259  }260  pCur = sqlite3TestTextToPtr(argv[1]);261#if SQLITE_THREADSAFE>0262  {263    Btree *pBt = pCur->pBtree;264    sqlite3_mutex_enter(pBt->db->mutex);265    sqlite3BtreeEnter(pBt);266    rc = sqlite3BtreeCloseCursor(pCur);267    sqlite3BtreeLeave(pBt);268    sqlite3_mutex_leave(pBt->db->mutex);269  }270#else271  rc = sqlite3BtreeCloseCursor(pCur);272#endif273  ckfree((char *)pCur);274  if( rc ){275    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);276    return TCL_ERROR;277  }278  return SQLITE_OK;279}280 281/*282** Usage:   btree_next ID283**284** Move the cursor to the next entry in the table.  Return 0 on success285** or 1 if the cursor was already on the last entry in the table or if286** the table is empty.287*/288static int SQLITE_TCLAPI btree_next(289  void *NotUsed,290  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */291  int argc,              /* Number of arguments */292  const char **argv      /* Text of each argument */293){294  BtCursor *pCur;295  int rc;296  int res = 0;297  char zBuf[100];298 299  if( argc!=2 ){300    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],301       " ID\"", NULL);302    return TCL_ERROR;303  }304  pCur = sqlite3TestTextToPtr(argv[1]);305  sqlite3BtreeEnter(pCur->pBtree);306  rc = sqlite3BtreeNext(pCur, 0);307  if( rc==SQLITE_DONE ){308    res = 1;309    rc = SQLITE_OK;310  }311  sqlite3BtreeLeave(pCur->pBtree);312  if( rc ){313    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);314    return TCL_ERROR;315  }316  sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);317  Tcl_AppendResult(interp, zBuf, NULL);318  return SQLITE_OK;319}320 321/*322** Usage:   btree_first ID323**324** Move the cursor to the first entry in the table.  Return 0 if the325** cursor was left point to something and 1 if the table is empty.326*/327static int SQLITE_TCLAPI btree_first(328  void *NotUsed,329  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */330  int argc,              /* Number of arguments */331  const char **argv      /* Text of each argument */332){333  BtCursor *pCur;334  int rc;335  int res = 0;336  char zBuf[100];337 338  if( argc!=2 ){339    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],340       " ID\"", NULL);341    return TCL_ERROR;342  }343  pCur = sqlite3TestTextToPtr(argv[1]);344  sqlite3BtreeEnter(pCur->pBtree);345  rc = sqlite3BtreeFirst(pCur, &res);346  sqlite3BtreeLeave(pCur->pBtree);347  if( rc ){348    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);349    return TCL_ERROR;350  }351  sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);352  Tcl_AppendResult(interp, zBuf, NULL);353  return SQLITE_OK;354}355 356/*357** Usage:   btree_eof ID358**359** Return TRUE if the given cursor is not pointing at a valid entry.360** Return FALSE if the cursor does point to a valid entry.361*/362static int SQLITE_TCLAPI btree_eof(363  void *NotUsed,364  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */365  int argc,              /* Number of arguments */366  const char **argv      /* Text of each argument */367){368  BtCursor *pCur;369  int rc;370  char zBuf[50];371 372  if( argc!=2 ){373    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],374       " ID\"", NULL);375    return TCL_ERROR;376  }377  pCur = sqlite3TestTextToPtr(argv[1]);378  sqlite3BtreeEnter(pCur->pBtree);379  rc = sqlite3BtreeEof(pCur);380  sqlite3BtreeLeave(pCur->pBtree);381  sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);382  Tcl_AppendResult(interp, zBuf, NULL);383  return SQLITE_OK;384}385 386/*387** Usage:   btree_payload_size ID388**389** Return the number of bytes of payload390*/391static int SQLITE_TCLAPI btree_payload_size(392  void *NotUsed,393  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */394  int argc,              /* Number of arguments */395  const char **argv      /* Text of each argument */396){397  BtCursor *pCur;398  u32 n;399  char zBuf[50];400 401  if( argc!=2 ){402    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],403       " ID\"", NULL);404    return TCL_ERROR;405  }406  pCur = sqlite3TestTextToPtr(argv[1]);407  sqlite3BtreeEnter(pCur->pBtree);408  n = sqlite3BtreePayloadSize(pCur);409  sqlite3BtreeLeave(pCur->pBtree);410  sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n);411  Tcl_AppendResult(interp, zBuf, NULL);412  return SQLITE_OK;413}414 415/*416** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT417**418** This command tests the putVarint() and getVarint()419** routines, both for accuracy and for speed.420**421** An integer is written using putVarint() and read back with422** getVarint() and verified to be unchanged.  This repeats COUNT423** times.  The first integer is START*MULTIPLIER.  Each iteration424** increases the integer by INCREMENT.425**426** This command returns nothing if it works.  It returns an error message427** if something goes wrong.428*/429static int SQLITE_TCLAPI btree_varint_test(430  void *NotUsed,431  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */432  int argc,              /* Number of arguments */433  const char **argv      /* Text of each argument */434){435  u32 start, mult, count, incr;436  u64 in, out;437  int n1, n2, i, j;438  unsigned char zBuf[100];439  if( argc!=5 ){440    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],441       " START MULTIPLIER COUNT INCREMENT\"", NULL);442    return TCL_ERROR;443  }444  if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;445  if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;446  if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;447  if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;448  in = start;449  in *= mult;450  for(i=0; i<(int)count; i++){451    char zErr[200];452    n1 = putVarint(zBuf, in);453    if( n1>9 || n1<1 ){454      sqlite3_snprintf(sizeof(zErr), zErr,455         "putVarint returned %d - should be between 1 and 9", n1);456      Tcl_AppendResult(interp, zErr, NULL);457      return TCL_ERROR;458    }459    n2 = getVarint(zBuf, &out);460    if( n1!=n2 ){461      sqlite3_snprintf(sizeof(zErr), zErr,462          "putVarint returned %d and getVarint returned %d", n1, n2);463      Tcl_AppendResult(interp, zErr, NULL);464      return TCL_ERROR;465    }466    if( in!=out ){467      sqlite3_snprintf(sizeof(zErr), zErr,468          "Wrote 0x%016llx and got back 0x%016llx", in, out);469      Tcl_AppendResult(interp, zErr, NULL);470      return TCL_ERROR;471    }472    if( (in & 0xffffffff)==in ){473      u32 out32;474      n2 = getVarint32(zBuf, out32);475      out = out32;476      if( n1!=n2 ){477        sqlite3_snprintf(sizeof(zErr), zErr,478          "putVarint returned %d and GetVarint32 returned %d", 479                  n1, n2);480        Tcl_AppendResult(interp, zErr, NULL);481        return TCL_ERROR;482      }483      if( in!=out ){484        sqlite3_snprintf(sizeof(zErr), zErr,485          "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",486            in, out);487        Tcl_AppendResult(interp, zErr, NULL);488        return TCL_ERROR;489      }490    }491 492    /* In order to get realistic timings, run getVarint 19 more times.493    ** This is because getVarint is called about 20 times more often494    ** than putVarint.495    */496    for(j=0; j<19; j++){497      getVarint(zBuf, &out);498    }499    in += incr;500  }501  return TCL_OK;502}503 504/*505** usage:   btree_from_db  DB-HANDLE506**507** This command returns the btree handle for the main database associated508** with the database-handle passed as the argument. Example usage:509**510** sqlite3 db test.db511** set bt [btree_from_db db]512*/513static int SQLITE_TCLAPI btree_from_db(514  void *NotUsed,515  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */516  int argc,              /* Number of arguments */517  const char **argv      /* Text of each argument */518){519  char zBuf[100];520  Tcl_CmdInfo info;521  sqlite3 *db;522  Btree *pBt;523  int iDb = 0;524 525  if( argc!=2 && argc!=3 ){526    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],527       " DB-HANDLE ?N?\"", NULL);528    return TCL_ERROR;529  }530 531  if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){532    Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", NULL);533    return TCL_ERROR;534  }535  if( argc==3 ){536    iDb = atoi(argv[2]);537  }538 539  db = *((sqlite3 **)info.objClientData);540  assert( db );541 542  pBt = db->aDb[iDb].pBt;543  sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);544  Tcl_SetResult(interp, zBuf, TCL_VOLATILE);545  return TCL_OK;546}547 548/*549** Usage:   btree_ismemdb ID550**551** Return true if the B-Tree is currently stored entirely in memory.552*/553static int SQLITE_TCLAPI btree_ismemdb(554  void *NotUsed,555  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */556  int argc,              /* Number of arguments */557  const char **argv      /* Text of each argument */558){559  Btree *pBt;560  int res;561  sqlite3_file *pFile;562 563  if( argc!=2 ){564    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],565       " ID\"", NULL);566    return TCL_ERROR;567  }568  pBt = sqlite3TestTextToPtr(argv[1]);569  sqlite3_mutex_enter(pBt->db->mutex);570  sqlite3BtreeEnter(pBt);571  pFile = sqlite3PagerFile(sqlite3BtreePager(pBt));572  res = (pFile->pMethods==0);573  sqlite3BtreeLeave(pBt);574  sqlite3_mutex_leave(pBt->db->mutex);575  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));576  return SQLITE_OK;577}578 579/*580** usage:   btree_set_cache_size ID NCACHE581**582** Set the size of the cache used by btree $ID.583*/584static int SQLITE_TCLAPI btree_set_cache_size(585  void *NotUsed,586  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */587  int argc,              /* Number of arguments */588  const char **argv      /* Text of each argument */589){590  int nCache;591  Btree *pBt;592  593  if( argc!=3 ){594    Tcl_AppendResult(595        interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", NULL);596    return TCL_ERROR;597  }598  pBt = sqlite3TestTextToPtr(argv[1]);599  if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;600 601  sqlite3_mutex_enter(pBt->db->mutex);602  sqlite3BtreeEnter(pBt);603  sqlite3BtreeSetCacheSize(pBt, nCache);604  sqlite3BtreeLeave(pBt);605  sqlite3_mutex_leave(pBt->db->mutex);606  return TCL_OK;607}      608 609/*610** usage:   btree_insert CSR ?KEY? VALUE611**612** Set the size of the cache used by btree $ID.613*/614static int SQLITE_TCLAPI btree_insert(615  ClientData clientData,616  Tcl_Interp *interp,617  int objc,618  Tcl_Obj *const objv[]619){620  BtCursor *pCur;621  int rc;622  BtreePayload x;623  Tcl_Size n;624 625  if( objc!=4 && objc!=3 ){626    Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE");627    return TCL_ERROR;628  }629 630  memset(&x, 0, sizeof(x));631  if( objc==4 ){632    if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR;633    x.nKey = rc;634    x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &n);635    x.nData = (int)n;636  }else{637    x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &n);638    x.nKey = (int)n;639  }640  pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));641 642  sqlite3_mutex_enter(pCur->pBtree->db->mutex);643  sqlite3BtreeEnter(pCur->pBtree);644  rc = sqlite3BtreeInsert(pCur, &x, 0, 0);645  sqlite3BtreeLeave(pCur->pBtree);646  sqlite3_mutex_leave(pCur->pBtree->db->mutex);647 648  Tcl_ResetResult(interp);649  if( rc ){650    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);651    return TCL_ERROR;652  }653  return TCL_OK;654}655 656 657/*658** Register commands with the TCL interpreter.659*/660int Sqlitetest3_Init(Tcl_Interp *interp){661  static struct {662     char *zName;663     Tcl_CmdProc *xProc;664  } aCmd[] = {665     { "btree_open",               (Tcl_CmdProc*)btree_open               },666     { "btree_close",              (Tcl_CmdProc*)btree_close              },667     { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  },668     { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        },669     { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             },670     { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       },671     { "btree_next",               (Tcl_CmdProc*)btree_next               },672     { "btree_eof",                (Tcl_CmdProc*)btree_eof                },673     { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       },674     { "btree_first",              (Tcl_CmdProc*)btree_first              },675     { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },676     { "btree_from_db",            (Tcl_CmdProc*)btree_from_db            },677     { "btree_ismemdb",            (Tcl_CmdProc*)btree_ismemdb            },678     { "btree_set_cache_size",     (Tcl_CmdProc*)btree_set_cache_size     }679  };680  int i;681 682  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){683    Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);684  }685 686  Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);687 688  return TCL_OK;689}690